blob: ac4fda971fb674dcd9ff8be7e375b3502e4597a4 [file] [log] [blame]
// Copyright 2013 The Flutter 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 "fake_resources.h"
#include "flutter/fml/logging.h"
namespace flutter_runner::testing {
namespace {
using FakeResourceCache =
std::unordered_map<FakeResourceState*, std::shared_ptr<FakeResource>>;
std::shared_ptr<FakeResource> ResourceFromState(
const std::shared_ptr<FakeResourceState>& resource,
FakeResourceCache& cache);
std::vector<std::shared_ptr<FakeResource>> ResourcesFromStates(
const std::vector<std::shared_ptr<FakeResourceState>>& resources,
FakeResourceCache& cache);
FakeNode NodeFromState(FakeNodeState* node, FakeResourceCache& cache) {
FML_CHECK(node);
return FakeNode{
.children = ResourcesFromStates(node->children, cache),
.rotation_quaternion = node->rotation_quaternion,
.scale_vector = node->scale_vector,
.translation_vector = node->translation_vector,
.anchor_vector = node->anchor_vector,
.hit_testable = node->hit_testable,
.semantically_visible = node->semantically_visible,
};
}
FakeEntityNode EntityNodeFromState(FakeEntityNodeState* entity_node,
FakeResourceCache& cache) {
FML_CHECK(entity_node);
// Convert clip planes.
std::vector<FakeEntityNode::ClipPlane> clip_planes;
for (auto& clip_plane : entity_node->clip_planes) {
clip_planes.emplace_back(FakeEntityNode::ClipPlane{
.dir = clip_plane.dir,
.dist = clip_plane.dist,
});
}
return FakeEntityNode{
.node_state = NodeFromState(&entity_node->node_state, cache),
.clip_planes = std::move(clip_planes),
};
}
FakeOpacityNode OpacityNodeFromState(FakeOpacityNodeState* opacity_node,
FakeResourceCache& cache) {
FML_CHECK(opacity_node);
return FakeOpacityNode{
.node_state = NodeFromState(&opacity_node->node_state, cache),
.opacity = opacity_node->opacity,
};
}
FakeShapeNode ShapeNodeFromState(FakeShapeNodeState* shape_node,
FakeResourceCache& cache) {
FML_CHECK(shape_node);
return FakeShapeNode{
.node_state = NodeFromState(&shape_node->node_state, cache),
.shape = ResourceFromState(shape_node->shape, cache),
.material = ResourceFromState(shape_node->material, cache),
};
}
FakeView ViewFromState(FakeViewState* view, FakeResourceCache& cache) {
FML_CHECK(view);
return FakeView{
.token = view->token.koid,
.control_ref = view->control_ref.koid,
.view_ref = view->view_ref.koid,
.debug_name = view->debug_name,
.children = ResourcesFromStates(view->children, cache),
.enable_debug_bounds = view->enable_debug_bounds,
};
}
FakeViewHolder ViewHolderFromState(FakeViewHolderState* view_holder,
FakeResourceCache& cache) {
FML_CHECK(view_holder);
return FakeViewHolder{
.token = view_holder->token.koid,
.debug_name = view_holder->debug_name,
.properties = view_holder->properties,
.bounds_color = view_holder->bounds_color,
};
}
FakeShape ShapeFromState(FakeShapeState* shape, FakeResourceCache& cache) {
FML_CHECK(shape);
auto snapshot = FakeShape{};
std::visit(
[&snapshot](auto&& shape_def) {
using T = std::decay_t<decltype(shape_def)>;
if constexpr (std::is_same_v<T, FakeShapeState::CircleDef>) {
snapshot.shape_def = FakeShape::CircleDef{
.radius = shape_def.radius,
};
} else if constexpr (std::is_same_v<T, FakeShapeState::RectangleDef>) {
snapshot.shape_def = FakeShape::RectangleDef{
.width = shape_def.width,
.height = shape_def.height,
};
} else if constexpr (std::is_same_v<
T, FakeShapeState::RoundedRectangleDef>) {
snapshot.shape_def = FakeShape::RoundedRectangleDef{
.width = shape_def.width,
.height = shape_def.height,
.top_left_radius = shape_def.top_left_radius,
.top_right_radius = shape_def.top_right_radius,
.bottom_right_radius = shape_def.bottom_right_radius,
.bottom_left_radius = shape_def.bottom_left_radius,
};
} else {
FML_CHECK(false);
}
},
shape->shape_def);
return snapshot;
}
FakeMaterial MaterialFromState(FakeMaterialState* material,
FakeResourceCache& cache) {
FML_CHECK(material);
return FakeMaterial{
.image = ResourceFromState(material->image, cache),
.color = material->color,
};
}
FakeImage ImageFromState(FakeImageState* image, FakeResourceCache& cache) {
FML_CHECK(image);
auto snapshot = FakeImage{
.memory = ResourceFromState(image->memory, cache),
};
std::visit(
[&snapshot](auto&& image_def) {
using T = std::decay_t<decltype(image_def)>;
if constexpr (std::is_same_v<T, FakeImageState::ImageDef>) {
snapshot.image_def = FakeImage::ImageDef{
.info = image_def.info,
.memory_offset = image_def.memory_offset,
};
} else if constexpr (std::is_same_v<T, FakeImageState::Image2Def>) {
snapshot.image_def = FakeImage::Image2Def{
.buffer_collection_id = image_def.buffer_collection_id,
.buffer_collection_index = image_def.buffer_collection_index,
.width = image_def.width,
.height = image_def.height,
};
} else if constexpr (std::is_same_v<T, FakeImageState::Image3Def>) {
snapshot.image_def = FakeImage::Image3Def{
.import_token = image_def.import_token.koid,
.buffer_collection_index = image_def.buffer_collection_index,
.width = image_def.width,
.height = image_def.height,
};
} else if constexpr (std::is_same_v<T, FakeImageState::ImagePipe2Def>) {
snapshot.image_def = FakeImage::ImagePipe2Def{
.image_pipe_request = image_def.image_pipe_request.koid,
};
} else {
FML_CHECK(false);
}
},
image->image_def);
return snapshot;
}
FakeMemory MemoryFromState(FakeMemoryState* memory, FakeResourceCache& cache) {
FML_CHECK(memory);
return FakeMemory{
.vmo = memory->vmo.koid,
.allocation_size = memory->allocation_size,
.is_device_memory = memory->is_device_memory,
};
}
std::shared_ptr<FakeResource> ResourceFromState(
const std::shared_ptr<FakeResourceState>& resource,
FakeResourceCache& cache) {
if (!resource) {
return std::shared_ptr<FakeResource>();
}
// Try to hit the cache first...
auto cache_it = cache.find(resource.get());
if (cache_it != cache.end()) {
return cache_it->second;
}
// Otherwise create a brand-new snapshot.
std::shared_ptr<FakeResource> snapshot =
std::make_shared<FakeResource>(FakeResource{
.id = resource->id,
.label = resource->label,
.event_mask = resource->event_mask,
});
std::visit(
[&snapshot, &resource, &cache](auto&& state) {
using T = std::decay_t<decltype(state)>;
if constexpr (std::is_same_v<T, FakeEntityNodeState>) {
snapshot->state = EntityNodeFromState(
std::get_if<FakeEntityNodeState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeOpacityNodeState>) {
snapshot->state = OpacityNodeFromState(
std::get_if<FakeOpacityNodeState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeShapeNodeState>) {
snapshot->state = ShapeNodeFromState(
std::get_if<FakeShapeNodeState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeViewState>) {
snapshot->state = ViewFromState(
std::get_if<FakeViewState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeViewHolderState>) {
snapshot->state = ViewHolderFromState(
std::get_if<FakeViewHolderState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeShapeState>) {
snapshot->state = ShapeFromState(
std::get_if<FakeShapeState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeMaterialState>) {
snapshot->state = MaterialFromState(
std::get_if<FakeMaterialState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeImageState>) {
snapshot->state = ImageFromState(
std::get_if<FakeImageState>(&resource->state), cache);
} else if constexpr (std::is_same_v<T, FakeMemoryState>) {
snapshot->state = MemoryFromState(
std::get_if<FakeMemoryState>(&resource->state), cache);
} else {
FML_CHECK(false);
}
},
resource->state);
auto [_, cache_success] =
cache.emplace(std::make_pair(resource.get(), snapshot));
FML_CHECK(cache_success);
return snapshot;
}
std::vector<std::shared_ptr<FakeResource>> ResourcesFromStates(
const std::vector<std::shared_ptr<FakeResourceState>>& resources,
FakeResourceCache& cache) {
std::vector<std::shared_ptr<FakeResource>> snapshots;
for (auto& resource : resources) {
snapshots.emplace_back(ResourceFromState(resource, cache));
}
return snapshots;
}
} // namespace
FakeSceneGraph SceneGraphFromState(const FakeSceneGraphState& state) {
FakeResourceCache resource_cache;
FakeSceneGraph scene_graph;
// Snapshot all buffer collections.
for (auto& buffer_collection : state.buffer_collection_map) {
scene_graph.buffer_collection_map.emplace(
std::make_pair(buffer_collection.first, buffer_collection.second.koid));
}
// Snapshot resources in the map recursively.
for (auto& resource : state.resource_map) {
scene_graph.resource_map.emplace(std::make_pair(
resource.first, ResourceFromState(resource.second, resource_cache)));
}
// Snapshot labels in the map.
for (auto& label_resources : state.label_map) {
auto [label_iter, label_success] =
scene_graph.label_map.emplace(std::make_pair(
label_resources.first, std::vector<std::weak_ptr<FakeResource>>()));
FML_CHECK(label_success);
auto& snapshot_label_resources = label_iter->second;
for (auto& resource : label_resources.second) {
auto resource_ptr = resource.lock();
FML_CHECK(resource_ptr);
snapshot_label_resources.emplace_back(
ResourceFromState(resource_ptr, resource_cache));
}
}
// Snapshot the view id.
scene_graph.root_view_id = state.root_view_id;
return scene_graph;
}
} // namespace flutter_runner::testing