blob: 43584ac274296f5c1a570294093d9147d0739b01 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/tab/tab_storage_packager.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "base/token.h"
#include "chrome/browser/tab/collection_storage_package.h"
#include "chrome/browser/tab/payload.h"
#include "chrome/browser/tab/protocol/children.pb.h"
#include "chrome/browser/tab/protocol/split_collection_state.pb.h"
#include "chrome/browser/tab/protocol/tab_group_collection_state.pb.h"
#include "chrome/browser/tab/protocol/token.pb.h"
#include "chrome/browser/tab/storage_id.h"
#include "chrome/browser/tab/storage_id_mapping.h"
#include "chrome/browser/tab/storage_package.h"
#include "chrome/browser/tab/tab_group_collection_data.h"
#include "chrome/browser/tab/tab_storage_package.h"
#include "chrome/browser/tab/tab_storage_type.h"
#include "chrome/browser/tab/tab_storage_util.h"
#include "components/tabs/public/direct_child_walker.h"
#include "components/tabs/public/split_tab_collection.h"
#include "components/tabs/public/split_tab_data.h"
namespace tabs {
// Crawls the direct children of a TabCollection and adds them to the list of
// children.
class ChildProcessor : public DirectChildWalker::Processor {
public:
ChildProcessor(tabs_pb::Children& children_proto, StorageIdMapping& mapping)
: children_proto_(children_proto), mapping_(mapping) {}
void ProcessTab(const TabInterface* tab) override {
tabs_pb::Token* token = children_proto_->add_storage_id();
StorageIdToTokenProto(mapping_->GetStorageId(tab), token);
}
void ProcessCollection(const TabCollection* collection) override {
tabs_pb::Token* token = children_proto_->add_storage_id();
StorageIdToTokenProto(mapping_->GetStorageId(collection), token);
}
private:
raw_ref<tabs_pb::Children> children_proto_;
raw_ref<StorageIdMapping> mapping_;
};
// An empty payload of data.
class EmptyPayload : public Payload {
public:
EmptyPayload() = default;
std::vector<uint8_t> SerializePayload() const override { return {}; }
};
// A payload representing the collection children.
class ChildrenPayload : public Payload {
public:
explicit ChildrenPayload(tabs_pb::Children children)
: children_(std::move(children)) {}
std::vector<uint8_t> SerializePayload() const override {
std::vector<uint8_t> payload_vec(children_.ByteSizeLong());
children_.SerializeToArray(payload_vec.data(), payload_vec.size());
return payload_vec;
}
private:
tabs_pb::Children children_;
};
// A payload of data representing SplitTabCollections.
class SplitCollectionStorageData : public Payload {
public:
explicit SplitCollectionStorageData(
tabs_pb::SplitCollectionState split_collection_state)
: split_collection_state_(std::move(split_collection_state)) {}
~SplitCollectionStorageData() override = default;
std::vector<uint8_t> SerializePayload() const override {
std::vector<uint8_t> payload_vec(split_collection_state_.ByteSizeLong());
split_collection_state_.SerializeToArray(payload_vec.data(),
payload_vec.size());
return payload_vec;
}
private:
tabs_pb::SplitCollectionState split_collection_state_;
};
// A payload of data representing TabGroupTabCollection.
class TabGroupCollectionStorageData : public Payload {
public:
explicit TabGroupCollectionStorageData(tabs_pb::TabGroupCollectionState state)
: state_(std::move(state)) {}
~TabGroupCollectionStorageData() override = default;
std::vector<uint8_t> SerializePayload() const override {
std::vector<uint8_t> payload_vec(state_.ByteSizeLong());
state_.SerializeToArray(payload_vec.data(), payload_vec.size());
return payload_vec;
}
private:
tabs_pb::TabGroupCollectionState state_;
};
TabStoragePackager::TabStoragePackager() = default;
TabStoragePackager::~TabStoragePackager() = default;
void PopulateChildren(tabs_pb::Children& children_proto,
const TabCollection* collection,
StorageIdMapping& mapping) {
ChildProcessor processor(children_proto, mapping);
DirectChildWalker walker(collection, &processor);
walker.Walk();
}
std::unique_ptr<StoragePackage> TabStoragePackager::Package(
const TabCollection* collection,
StorageIdMapping& mapping) {
tabs_pb::Children children_proto;
PopulateChildren(children_proto, collection, mapping);
return std::make_unique<CollectionStoragePackage>(
TabStoragePackager::PackagePayload(collection, mapping),
std::move(children_proto));
}
std::unique_ptr<Payload> TabStoragePackager::PackagePayload(
const TabCollection* collection,
StorageIdMapping& mapping) {
TabStorageType type = TabCollectionTypeToTabStorageType(collection->type());
if (type == TabStorageType::kSplit) {
return PackageSplitTabCollectionData(
static_cast<const SplitTabCollection*>(collection));
} else if (type == TabStorageType::kGroup) {
return PackageTabGroupTabCollectionData(
static_cast<const TabGroupTabCollection*>(collection));
} else if (type == TabStorageType::kTabStrip) {
return PackageTabStripCollectionData(
static_cast<const TabStripCollection*>(collection), mapping);
} else {
return std::make_unique<EmptyPayload>();
}
}
std::unique_ptr<Payload> TabStoragePackager::PackageChildren(
const TabCollection* collection,
StorageIdMapping& mapping) {
tabs_pb::Children children_proto;
PopulateChildren(children_proto, collection, mapping);
return std::make_unique<ChildrenPayload>(std::move(children_proto));
}
const TabCollection* TabStoragePackager::GetRootCollection(
const TabCollection* collection) const {
CHECK(collection);
const TabCollection* parent = collection->GetParentCollection();
while (parent) {
collection = parent;
parent = collection->GetParentCollection();
}
return collection;
}
std::unique_ptr<Payload> TabStoragePackager::PackageTabGroupTabCollectionData(
const TabGroupTabCollection* collection) {
tabs_pb::TabGroupCollectionState state;
const base::Token group_id = collection->GetTabGroupId().token();
state.set_group_id_high(group_id.high());
state.set_group_id_low(group_id.low());
const tab_groups::TabGroupVisualData* visual_data =
collection->GetTabGroup()->visual_data();
state.set_color(static_cast<int32_t>(visual_data->color()));
state.set_is_collapsed(visual_data->is_collapsed());
state.set_title(base::UTF16ToUTF8(visual_data->title()));
return std::make_unique<TabGroupCollectionStorageData>(std::move(state));
}
std::unique_ptr<Payload> TabStoragePackager::PackageSplitTabCollectionData(
const SplitTabCollection* collection) {
tabs_pb::SplitCollectionState state;
const base::Token split_tab_id = collection->GetSplitTabId().token();
state.set_split_tab_id_high(split_tab_id.high());
state.set_split_tab_id_low(split_tab_id.low());
split_tabs::SplitTabData* data = collection->data();
split_tabs::SplitTabVisualData* visual_data = data->visual_data();
state.set_split_layout(static_cast<int32_t>(visual_data->split_layout()));
state.set_split_ratio(visual_data->split_ratio());
return std::make_unique<SplitCollectionStorageData>(std::move(state));
}
} // namespace tabs