blob: d7cd3c67bc95c0eb8661d42f6a67dc1bb0833157 [file] [log] [blame]
// Copyright 2021 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 "third_party/blink/renderer/modules/handwriting/handwriting_recognition_service.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_feature_query_result.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_handwriting_model_constraint.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/handwriting/handwriting_recognizer.h"
#include "third_party/blink/renderer/modules/handwriting/handwriting_type_converters.h"
namespace blink {
namespace {
void OnCreateHandwritingRecognizer(
ScriptState* script_state,
ScriptPromiseResolver* resolver,
handwriting::mojom::blink::CreateHandwritingRecognizerResult result,
mojo::PendingRemote<handwriting::mojom::blink::HandwritingRecognizer>
pending_remote) {
if (result !=
handwriting::mojom::blink::CreateHandwritingRecognizerResult::kOk) {
resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError, "Internal error."));
return;
}
auto* handwriting_recognizer = MakeGarbageCollected<HandwritingRecognizer>(
ExecutionContext::From(script_state), std::move(pending_remote));
resolver->Resolve(handwriting_recognizer);
}
void OnQueryHandwritingFeature(
ScriptState* script_state,
ScriptPromiseResolver* resolver,
handwriting::mojom::blink::HandwritingFeatureQueryResultPtr query_result) {
resolver->Resolve(
mojo::ConvertTo<HandwritingFeatureQueryResult*>(std::move(query_result)));
}
} // namespace
const char HandwritingRecognitionService::kSupplementName[] =
"NavigatorHandwritingRecognitionService";
HandwritingRecognitionService::HandwritingRecognitionService(
Navigator& navigator)
: Supplement<Navigator>(navigator),
remote_service_(navigator.GetExecutionContext()) {}
// static
HandwritingRecognitionService& HandwritingRecognitionService::From(
Navigator& navigator) {
HandwritingRecognitionService* supplement =
Supplement<Navigator>::From<HandwritingRecognitionService>(navigator);
if (!supplement) {
supplement = MakeGarbageCollected<HandwritingRecognitionService>(navigator);
ProvideTo(navigator, supplement);
}
return *supplement;
}
// static
ScriptPromise HandwritingRecognitionService::createHandwritingRecognizer(
ScriptState* script_state,
Navigator& navigator,
const HandwritingModelConstraint* constraint,
ExceptionState& exception_state) {
return HandwritingRecognitionService::From(navigator)
.CreateHandwritingRecognizer(script_state, constraint, exception_state);
}
bool HandwritingRecognitionService::BootstrapMojoConnectionIfNeeded(
ScriptState* script_state,
ExceptionState& exception_state) {
// We need to do the following check because the execution context of this
// navigator may be invalid (e.g. the frame is detached).
if (!script_state->ContextIsValid()) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"The execution context is invalid");
return false;
}
// Note that we do not use `ExecutionContext::From(script_state)` because
// the ScriptState passed in may not be guaranteed to match the execution
// context associated with this navigator, especially with
// cross-browsing-context calls.
auto* execution_context = GetSupplementable()->GetExecutionContext();
if (!remote_service_.is_bound()) {
execution_context->GetBrowserInterfaceBroker().GetInterface(
remote_service_.BindNewPipeAndPassReceiver(
execution_context->GetTaskRunner(TaskType::kInternalDefault)));
}
return true;
}
ScriptPromise HandwritingRecognitionService::CreateHandwritingRecognizer(
ScriptState* script_state,
const HandwritingModelConstraint* blink_model_constraint,
ExceptionState& exception_state) {
if (!BootstrapMojoConnectionIfNeeded(script_state, exception_state)) {
return ScriptPromise();
}
ScriptPromiseResolver* resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
auto promise = resolver->Promise();
auto mojo_model_constraint =
handwriting::mojom::blink::HandwritingModelConstraint::New();
for (auto const& lang : blink_model_constraint->languages()) {
mojo_model_constraint->languages.push_back(lang);
}
remote_service_->CreateHandwritingRecognizer(
std::move(mojo_model_constraint),
WTF::Bind(OnCreateHandwritingRecognizer, WrapPersistent(script_state),
WrapPersistent(resolver)));
return promise;
}
// static
ScriptPromise HandwritingRecognitionService::queryHandwritingRecognizerSupport(
ScriptState* script_state,
Navigator& navigator,
const HandwritingFeatureQuery* query,
ExceptionState& exception_state) {
return HandwritingRecognitionService::From(navigator)
.QueryHandwritingRecognizerSupport(script_state, query, exception_state);
}
ScriptPromise HandwritingRecognitionService::QueryHandwritingRecognizerSupport(
ScriptState* script_state,
const HandwritingFeatureQuery* query,
ExceptionState& exception_state) {
if (!BootstrapMojoConnectionIfNeeded(script_state, exception_state)) {
return ScriptPromise();
}
ScriptPromiseResolver* resolver =
MakeGarbageCollected<ScriptPromiseResolver>(script_state);
auto promise = resolver->Promise();
remote_service_->QueryHandwritingRecognizerSupport(
mojo::ConvertTo<handwriting::mojom::blink::HandwritingFeatureQueryPtr>(
query),
WTF::Bind(&OnQueryHandwritingFeature, WrapPersistent(script_state),
WrapPersistent(resolver)));
return promise;
}
void HandwritingRecognitionService::Trace(Visitor* visitor) const {
visitor->Trace(remote_service_);
Supplement<Navigator>::Trace(visitor);
}
} // namespace blink