blob: 96fe3cc847708b9e68f86223cf0ae909d833be65 [file] [log] [blame]
// Copyright 2020 The Chromium OS 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 "ml/handwriting.h"
#include <string>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/native_library.h>
namespace ml {
namespace {
constexpr char kHandwritingLibraryPath[] = "/usr/lib64/libhandwriting.so";
// Returns whether HandwritingLibrary is supported.
constexpr bool IsHandwritingLibrarySupported() {
#ifdef ML_SUPPORT_HANDWRITING
// Currently HandwritingLibrary is supported only when the "sanitizer" is not
// enabled (see https://crbug.com/1082632).
#if __has_feature(address_sanitizer)
return false;
#else
return true;
#endif
#else
return false;
#endif
}
} // namespace
HandwritingLibrary::HandwritingLibrary()
: status_(Status::kUninitialized),
create_handwriting_recognizer_(nullptr),
load_handwriting_recognizer_(nullptr),
recognize_handwriting_(nullptr),
delete_handwriting_result_data_(nullptr),
destroy_handwriting_recognizer_(nullptr) {
if (!IsHandwritingLibrarySupported()) {
status_ = Status::kNotSupported;
return;
}
// Load the library with an option preferring own symbols. Otherwise the
// library will try to call, e.g., external tflite, which leads to crash.
base::NativeLibraryOptions native_library_options;
native_library_options.prefer_own_symbols = true;
library_.emplace(base::LoadNativeLibraryWithOptions(
base::FilePath(kHandwritingLibraryPath), native_library_options,
nullptr));
if (!library_->is_valid()) {
status_ = Status::kLoadLibraryFailed;
return;
}
// Helper macro to look up functions from the library, assuming the function
// pointer type is named as (name+"Fn"), which is the case in
// "libhandwriting/interface.h".
#define ML_HANDWRITING_LOOKUP_FUNCTION(function_ptr, name) \
function_ptr = \
reinterpret_cast<name##Fn>(library_->GetFunctionPointer(#name)); \
if (function_ptr == NULL) { \
status_ = Status::kFunctionLookupFailed; \
return; \
}
// Look up the function pointers.
ML_HANDWRITING_LOOKUP_FUNCTION(create_handwriting_recognizer_,
CreateHandwritingRecognizer);
ML_HANDWRITING_LOOKUP_FUNCTION(load_handwriting_recognizer_,
LoadHandwritingRecognizer);
ML_HANDWRITING_LOOKUP_FUNCTION(recognize_handwriting_, RecognizeHandwriting);
ML_HANDWRITING_LOOKUP_FUNCTION(delete_handwriting_result_data_,
DeleteHandwritingResultData);
ML_HANDWRITING_LOOKUP_FUNCTION(destroy_handwriting_recognizer_,
DestroyHandwritingRecognizer);
#undef ML_HANDWRITING_LOOKUP_FUNCTION
status_ = Status::kOk;
}
HandwritingLibrary::Status HandwritingLibrary::GetStatus() const {
return status_;
}
HandwritingLibrary* HandwritingLibrary::GetInstance() {
static base::NoDestructor<HandwritingLibrary> instance;
return instance.get();
}
// Proxy functions to the library function pointers.
HandwritingRecognizer HandwritingLibrary::CreateHandwritingRecognizer() const {
DCHECK(status_ == Status::kOk);
return (*create_handwriting_recognizer_)();
}
bool HandwritingLibrary::LoadHandwritingRecognizer(
HandwritingRecognizer const recognizer,
const chrome_knowledge::HandwritingRecognizerOptions& options,
const chrome_knowledge::HandwritingRecognizerModelPaths& model_path) const {
DCHECK(status_ == Status::kOk);
const std::string options_pb = options.SerializeAsString();
const std::string paths_pb = model_path.SerializeAsString();
return (*load_handwriting_recognizer_)(recognizer, options_pb.data(),
options_pb.size(), paths_pb.data(),
paths_pb.size());
}
bool HandwritingLibrary::RecognizeHandwriting(
HandwritingRecognizer const recognizer,
const chrome_knowledge::HandwritingRecognizerRequest& request,
chrome_knowledge::HandwritingRecognizerResult* const result) const {
DCHECK(status_ == Status::kOk);
const std::string request_pb = request.SerializeAsString();
char* result_data = nullptr;
int result_size = 0;
const bool recognize_result =
(*recognize_handwriting_)(recognizer, request_pb.data(),
request_pb.size(), &result_data, &result_size);
if (recognize_result) {
const bool parse_result_status =
result->ParseFromArray(result_data, result_size);
DCHECK(parse_result_status);
// only need to delete result_data if succeeds.
(*delete_handwriting_result_data_)(result_data);
}
return recognize_result;
}
void HandwritingLibrary::DestroyHandwritingRecognizer(
HandwritingRecognizer const recognizer) const {
DCHECK(status_ == Status::kOk);
(*destroy_handwriting_recognizer_)(recognizer);
}
} // namespace ml