blob: e3e13be2fa280aeb7ef33e81421ab0aa89ff992e [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/services/screen_ai/screen_ai_library_wrapper.h"
#include "base/metrics/histogram_functions.h"
#include "ui/accessibility/accessibility_features.h"
namespace screen_ai {
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
void HandleLibraryLogging(int severity, const char* message) {
switch (severity) {
case logging::LOG_VERBOSE:
case logging::LOG_INFO:
VLOG(2) << message;
break;
case logging::LOG_WARNING:
VLOG(1) << message;
break;
case logging::LOG_ERROR:
case logging::LOG_FATAL:
VLOG(0) << message;
break;
}
}
#endif
std::vector<char> LoadModelFile(base::File& model_file) {
std::vector<char> buffer;
int64_t length = model_file.GetLength();
if (length < 0) {
VLOG(0) << "Could not query Screen AI model file's length.";
return buffer;
}
buffer.resize(length);
if (model_file.Read(0, buffer.data(), length) != length) {
buffer.clear();
VLOG(0) << "Could not read Screen AI model file's content.";
}
return buffer;
}
} // namespace
ScreenAILibraryWrapper::ScreenAILibraryWrapper() = default;
template <typename T>
bool ScreenAILibraryWrapper::LoadFunction(T& function_variable,
const char* function_name) {
function_variable =
reinterpret_cast<T>(library_.GetFunctionPointer(function_name));
if (function_variable == nullptr) {
VLOG(0) << "Could not load function: " << function_name;
return false;
}
return true;
}
bool ScreenAILibraryWrapper::Init(const base::FilePath& library_path) {
library_ = base::ScopedNativeLibrary(library_path);
#if BUILDFLAG(IS_WIN)
DWORD error = library_.GetError()->code;
base::UmaHistogramSparse(
"Accessibility.ScreenAI.LibraryLoadDetailedResultOnWindows",
static_cast<int>(error));
if (error != ERROR_SUCCESS) {
VLOG(0) << "Library load error: " << library_.GetError()->code;
return false;
}
#else
if (!library_.GetError()->message.empty()) {
VLOG(0) << "Library load error: " << library_.GetError()->message;
return false;
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!LoadFunction(set_logger_, "SetLogger")) {
return false;
}
#endif
// General functions.
if (!LoadFunction(get_library_version_, "GetLibraryVersion") ||
!LoadFunction(get_library_version_, "GetLibraryVersion") ||
!LoadFunction(enable_debug_mode_, "EnableDebugMode") ||
!LoadFunction(free_library_allocated_int32_array_,
"FreeLibraryAllocatedInt32Array") ||
!LoadFunction(free_library_allocated_char_array_,
"FreeLibraryAllocatedCharArray")) {
return false;
}
// Layout Extraction functions.
if (features::IsLayoutExtractionEnabled()) {
if (!LoadFunction(init_layout_extraction_, "InitLayoutExtraction") ||
!LoadFunction(extract_layout_, "ExtractLayout")) {
return false;
}
}
// OCR functions.
if (features::IsPdfOcrEnabled()) {
if (!LoadFunction(init_ocr_, "InitOCR") ||
!LoadFunction(perform_ocr_, "PerformOCR")) {
return false;
}
}
// Main Content Extraction functions.
if (features::IsReadAnythingWithScreen2xEnabled()) {
if (!LoadFunction(init_main_content_extraction_,
"InitMainContentExtraction") ||
!LoadFunction(extract_main_content_, "ExtractMainContent")) {
return false;
}
}
return true;
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapper::ScreenAILibraryWrapper::SetLogger() {
CHECK(set_logger_);
set_logger_(&HandleLibraryLogging);
}
#endif
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapper::GetLibraryVersion(uint32_t& major,
uint32_t& minor) {
CHECK(get_library_version_);
get_library_version_(major, minor);
}
NO_SANITIZE("cfi-icall")
void ScreenAILibraryWrapper::EnableDebugMode() {
CHECK(enable_debug_mode_);
enable_debug_mode_();
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::InitLayoutExtraction() {
CHECK(init_layout_extraction_);
return init_layout_extraction_();
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::InitOCR(const base::FilePath& models_folder) {
CHECK(init_ocr_);
return init_ocr_(models_folder.MaybeAsASCII().c_str());
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::InitMainContentExtraction(
base::File& model_config_file,
base::File& model_tflite_file) {
CHECK(init_main_content_extraction_);
std::vector<char> model_config = LoadModelFile(model_config_file);
std::vector<char> model_tflite = LoadModelFile(model_tflite_file);
if (model_config.empty() || model_tflite.empty()) {
return false;
}
return init_main_content_extraction_(model_config.data(), model_config.size(),
model_tflite.data(),
model_tflite.size());
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::PerformOcr(
const SkBitmap& image,
chrome_screen_ai::VisualAnnotation& annotation_proto) {
CHECK(perform_ocr_);
CHECK(free_library_allocated_char_array_);
uint32_t annotation_proto_length = 0;
std::unique_ptr<char, decltype(free_library_allocated_char_array_)>
library_buffer(perform_ocr_(image, annotation_proto_length),
free_library_allocated_char_array_);
bool result = library_buffer
? annotation_proto.ParseFromArray(library_buffer.get(),
annotation_proto_length)
: false;
// TODO(crbug.com/1278245): Remove this after fixing the crash issue on Linux
// official.
#if BUILDFLAG(IS_LINUX)
free_library_allocated_char_array_(library_buffer.release());
#endif
return result;
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::ExtractLayout(
const SkBitmap& image,
chrome_screen_ai::VisualAnnotation& annotation_proto) {
CHECK(extract_layout_);
CHECK(free_library_allocated_char_array_);
uint32_t annotation_proto_length = 0;
std::unique_ptr<char, decltype(free_library_allocated_char_array_)>
library_buffer(extract_layout_(image, annotation_proto_length),
free_library_allocated_char_array_);
bool result = library_buffer
? annotation_proto.ParseFromArray(library_buffer.get(),
annotation_proto_length)
: false;
// TODO(crbug.com/1278245): Remove this after fixing the crash issue on Linux
// official.
#if BUILDFLAG(IS_LINUX)
free_library_allocated_char_array_(library_buffer.release());
#endif
return result;
}
NO_SANITIZE("cfi-icall")
bool ScreenAILibraryWrapper::ExtractMainContent(
const std::string& serialized_view_hierarchy,
std::vector<int32_t>& node_ids) {
CHECK(extract_main_content_);
CHECK(free_library_allocated_int32_array_);
uint32_t nodes_count = 0;
std::unique_ptr<int32_t, decltype(free_library_allocated_int32_array_)>
library_buffer(extract_main_content_(serialized_view_hierarchy.data(),
serialized_view_hierarchy.length(),
nodes_count),
free_library_allocated_int32_array_);
if (!library_buffer) {
return false;
}
node_ids.resize(nodes_count);
if (nodes_count != 0) {
memcpy(node_ids.data(), library_buffer.get(),
nodes_count * sizeof(int32_t));
}
// TODO(crbug.com/1278245): Remove this after fixing the crash issue on Linux
// official.
#if BUILDFLAG(IS_LINUX)
free_library_allocated_int32_array_(library_buffer.release());
#endif
return true;
}
} // namespace screen_ai