blob: fe2ed64592adcbffa0064e4b4b7fa3b8c36b6fa2 [file] [log] [blame]
// Copyright 2020 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/paint_preview/browser/paint_preview_file_mixin.h"
#include <string_view>
#include <utility>
#include "base/files/file_util.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "ui/accessibility/mojom/ax_tree_update.mojom.h"
namespace paint_preview {
namespace {
const char kPaintPreviewDir[] = "paint_preview";
const char kAxTreeFilename[] = "ax_tree.message";
// Threadpool task to read the proto from disk.
std::pair<PaintPreviewFileMixin::ProtoReadStatus,
std::unique_ptr<PaintPreviewProto>>
GetProto(scoped_refptr<FileManager> file_manager,
const DirectoryKey& key,
std::optional<base::TimeDelta> expiry_horizon) {
TRACE_EVENT0("paint_preview", "PaintPreviewFileMixin::GetProto");
if (expiry_horizon.has_value()) {
auto file_info = file_manager->GetInfo(key);
if (!file_info.has_value())
return std::make_pair(PaintPreviewFileMixin::ProtoReadStatus::kNoProto,
nullptr);
if (file_info->last_modified + expiry_horizon.value() <
base::Time::NowFromSystemTime()) {
return std::make_pair(PaintPreviewFileMixin::ProtoReadStatus::kExpired,
nullptr);
}
}
auto result = file_manager->DeserializePaintPreviewProto(key);
PaintPreviewFileMixin::ProtoReadStatus status =
PaintPreviewFileMixin::ProtoReadStatus::kNoProto;
switch (result.first) {
case FileManager::ProtoReadStatus::kOk:
status = PaintPreviewFileMixin::ProtoReadStatus::kOk;
break;
case FileManager::ProtoReadStatus::kNoProto:
status = PaintPreviewFileMixin::ProtoReadStatus::kNoProto;
break;
case FileManager::ProtoReadStatus::kDeserializationError:
status = PaintPreviewFileMixin::ProtoReadStatus::kDeserializationError;
break;
default:
NOTREACHED();
}
return std::make_pair(status, std::move(result.second));
}
// Callback executed on threadpool read complete.
void OnReadProto(PaintPreviewFileMixin::OnReadProtoCallback callback,
std::pair<PaintPreviewFileMixin::ProtoReadStatus,
std::unique_ptr<PaintPreviewProto>> result) {
TRACE_EVENT0("paint_preview", "PaintPreviewFileMixin::OnReadProto");
std::move(callback).Run(result.first, std::move(result.second));
}
} // namespace
PaintPreviewFileMixin::PaintPreviewFileMixin(
const base::FilePath& path,
std::string_view ascii_feature_name)
: task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN,
base::ThreadPolicy::MUST_USE_FOREGROUND})),
file_manager_(base::MakeRefCounted<FileManager>(
path.AppendASCII(kPaintPreviewDir).AppendASCII(ascii_feature_name),
task_runner_)) {}
PaintPreviewFileMixin::~PaintPreviewFileMixin() = default;
void PaintPreviewFileMixin::GetCapturedPaintPreviewProto(
const DirectoryKey& key,
std::optional<base::TimeDelta> expiry_horizon,
OnReadProtoCallback on_read_proto_callback) {
task_runner_->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(&GetProto, file_manager_, key, expiry_horizon),
base::BindOnce(OnReadProto, std::move(on_read_proto_callback)));
}
void PaintPreviewFileMixin::WriteAXTreeUpdate(
const DirectoryKey& key,
base::OnceCallback<void(bool)> finished_callback,
ui::AXTreeUpdate& ax_tree_update) {
std::vector<uint8_t> ax_data =
ax::mojom::AXTreeUpdate::Serialize(&ax_tree_update);
task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
[](scoped_refptr<FileManager> file_manager, const DirectoryKey& key,
const std::vector<uint8_t>& ax_data) {
TRACE_EVENT0("paint_preview",
"PaintPreviewFileMixin::WriteAXTreeUpdate Task");
auto directory = file_manager->CreateOrGetDirectory(key, false);
if (!directory.has_value()) {
return false;
}
return base::WriteFile(directory->AppendASCII(kAxTreeFilename),
ax_data);
},
file_manager_, key, ax_data),
std::move(finished_callback));
}
void PaintPreviewFileMixin::GetAXTreeUpdate(const DirectoryKey& key,
OnReadAXTree callback) {
task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
[](scoped_refptr<FileManager> file_manager,
const DirectoryKey& key) -> std::unique_ptr<ui::AXTreeUpdate> {
TRACE_EVENT0("paint_preview",
"PaintPreviewFileMixin::GetAXTreeUpdate Task");
auto dir = file_manager->CreateOrGetDirectory(key, false);
if (!dir.has_value()) {
return nullptr;
}
auto path = dir->AppendASCII(kAxTreeFilename);
std::string content;
if (!base::ReadFileToString(path, &content)) {
return nullptr;
}
auto update = std::make_unique<ui::AXTreeUpdate>();
if (!ax::mojom::AXTreeUpdate::Deserialize(
content.data(), content.size(), update.get())) {
return nullptr;
}
return update;
},
file_manager_, key),
std::move(callback));
}
} // namespace paint_preview