blob: 656c94f507b63743b482133a264905790e7108e3 [file] [log] [blame] [edit]
// 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 "flutter/lib/ui/compositing/scene_builder.h"
#include <cstdint>
#include "dart_api.h"
#include "flutter/flow/layers/backdrop_filter_layer.h"
#include "flutter/flow/layers/clip_path_layer.h"
#include "flutter/flow/layers/clip_rect_layer.h"
#include "flutter/flow/layers/clip_rrect_layer.h"
#include "flutter/flow/layers/color_filter_layer.h"
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/display_list_layer.h"
#include "flutter/flow/layers/image_filter_layer.h"
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/layers/opacity_layer.h"
#include "flutter/flow/layers/performance_overlay_layer.h"
#include "flutter/flow/layers/platform_view_layer.h"
#include "flutter/flow/layers/shader_mask_layer.h"
#include "flutter/flow/layers/texture_layer.h"
#include "flutter/flow/layers/transform_layer.h"
#include "flutter/fml/build_config.h"
#include "flutter/lib/ui/compositing/scene.h"
#include "flutter/lib/ui/floating_point.h"
#include "flutter/lib/ui/painting/matrix.h"
#include "flutter/lib/ui/painting/shader.h"
namespace flutter {
IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder);
SceneBuilder::SceneBuilder() {
// Add a ContainerLayer as the root layer, so that AddLayer operations are
// always valid.
PushLayer(std::make_shared<flutter::ContainerLayer>());
}
SceneBuilder::~SceneBuilder() = default;
void SceneBuilder::pushTransform(Dart_Handle layer_handle,
tonic::Float64List& matrix4,
const fml::RefPtr<EngineLayer>& old_layer) {
DlMatrix matrix = ToDlMatrix(matrix4);
auto layer = std::make_shared<flutter::TransformLayer>(matrix);
PushLayer(layer);
// matrix4 has to be released before we can return another Dart object
matrix4.Release();
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushOffset(Dart_Handle layer_handle,
double dx,
double dy,
const fml::RefPtr<EngineLayer>& old_layer) {
DlMatrix matrix = DlMatrix::MakeTranslation({SafeNarrow(dx), SafeNarrow(dy)});
auto layer = std::make_shared<flutter::TransformLayer>(matrix);
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushClipRect(Dart_Handle layer_handle,
double left,
double right,
double top,
double bottom,
int clip_behavior,
const fml::RefPtr<EngineLayer>& old_layer) {
DlRect clip_rect = DlRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top),
SafeNarrow(right), SafeNarrow(bottom));
auto layer = std::make_shared<flutter::ClipRectLayer>(
clip_rect, static_cast<flutter::Clip>(clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushClipRRect(Dart_Handle layer_handle,
const RRect& rrect,
int clip_behavior,
const fml::RefPtr<EngineLayer>& old_layer) {
auto layer = std::make_shared<flutter::ClipRRectLayer>(
rrect.rrect, static_cast<flutter::Clip>(clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushClipPath(Dart_Handle layer_handle,
const CanvasPath* path,
int clip_behavior,
const fml::RefPtr<EngineLayer>& old_layer) {
flutter::Clip flutter_clip_behavior =
static_cast<flutter::Clip>(clip_behavior);
FML_DCHECK(flutter_clip_behavior != flutter::Clip::kNone);
auto layer = std::make_shared<flutter::ClipPathLayer>(
path->path(), static_cast<flutter::Clip>(flutter_clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushOpacity(Dart_Handle layer_handle,
int alpha,
double dx,
double dy,
const fml::RefPtr<EngineLayer>& old_layer) {
auto layer = std::make_shared<flutter::OpacityLayer>(
alpha, DlPoint(SafeNarrow(dx), SafeNarrow(dy)));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushColorFilter(Dart_Handle layer_handle,
const ColorFilter* color_filter,
const fml::RefPtr<EngineLayer>& old_layer) {
auto layer =
std::make_shared<flutter::ColorFilterLayer>(color_filter->filter());
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushImageFilter(Dart_Handle layer_handle,
const ImageFilter* image_filter,
double dx,
double dy,
const fml::RefPtr<EngineLayer>& old_layer) {
auto layer = std::make_shared<flutter::ImageFilterLayer>(
image_filter->filter(DlTileMode::kDecal),
DlPoint(SafeNarrow(dx), SafeNarrow(dy)));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushBackdropFilter(
Dart_Handle layer_handle,
ImageFilter* filter,
int blend_mode,
Dart_Handle backdrop_id,
const fml::RefPtr<EngineLayer>& old_layer) {
std::optional<int64_t> converted_backdrop_id;
if (Dart_IsInteger(backdrop_id)) {
int64_t out;
Dart_IntegerToInt64(backdrop_id, &out);
converted_backdrop_id = out;
}
auto layer = std::make_shared<flutter::BackdropFilterLayer>(
filter->filter(DlTileMode::kMirror), static_cast<DlBlendMode>(blend_mode),
converted_backdrop_id);
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushShaderMask(Dart_Handle layer_handle,
Shader* shader,
double mask_rect_left,
double mask_rect_right,
double mask_rect_top,
double mask_rect_bottom,
int blend_mode,
int filter_quality_index,
const fml::RefPtr<EngineLayer>& old_layer) {
DlRect rect = DlRect::MakeLTRB(
SafeNarrow(mask_rect_left), SafeNarrow(mask_rect_top),
SafeNarrow(mask_rect_right), SafeNarrow(mask_rect_bottom));
auto sampling = ImageFilter::SamplingFromIndex(filter_quality_index);
auto layer = std::make_shared<flutter::ShaderMaskLayer>(
shader->shader(sampling), rect, static_cast<DlBlendMode>(blend_mode));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
if (old_layer && old_layer->Layer()) {
layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::addRetained(const fml::RefPtr<EngineLayer>& retained_layer) {
AddLayer(retained_layer->Layer());
}
void SceneBuilder::pop() {
PopLayer();
}
void SceneBuilder::addPicture(double dx,
double dy,
Picture* picture,
int hints) {
if (!picture) {
// Picture::dispose was called and it has been collected.
return;
}
// Explicitly check for display_list, since the picture object might have
// been disposed but not collected yet, but the display list is null.
if (picture->display_list()) {
auto layer = std::make_unique<flutter::DisplayListLayer>(
DlPoint(SafeNarrow(dx), SafeNarrow(dy)), picture->display_list(),
!!(hints & 1), !!(hints & 2));
AddLayer(std::move(layer));
}
}
void SceneBuilder::addTexture(double dx,
double dy,
double width,
double height,
int64_t texture_id,
bool freeze,
int filter_quality_index) {
auto sampling = ImageFilter::SamplingFromIndex(filter_quality_index);
auto layer = std::make_unique<flutter::TextureLayer>(
DlPoint(SafeNarrow(dx), SafeNarrow(dy)),
DlSize(SafeNarrow(width), SafeNarrow(height)), texture_id, freeze,
sampling);
AddLayer(std::move(layer));
}
void SceneBuilder::addPlatformView(double dx,
double dy,
double width,
double height,
int64_t view_id) {
auto layer = std::make_unique<flutter::PlatformViewLayer>(
DlPoint(SafeNarrow(dx), SafeNarrow(dy)),
DlSize(SafeNarrow(width), SafeNarrow(height)), view_id);
AddLayer(std::move(layer));
}
void SceneBuilder::addPerformanceOverlay(uint64_t enabled_options,
double left,
double right,
double top,
double bottom) {
DlRect rect = DlRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top),
SafeNarrow(right), SafeNarrow(bottom));
auto layer =
std::make_unique<flutter::PerformanceOverlayLayer>(enabled_options);
layer->set_paint_bounds(rect);
AddLayer(std::move(layer));
}
void SceneBuilder::build(Dart_Handle scene_handle) {
FML_DCHECK(layer_stack_.size() >= 1);
Scene::create(scene_handle, std::move(layer_stack_[0]));
layer_stack_.clear();
ClearDartWrapper(); // may delete this object.
}
void SceneBuilder::AddLayer(std::shared_ptr<Layer> layer) {
FML_DCHECK(layer);
if (!layer_stack_.empty()) {
layer_stack_.back()->Add(std::move(layer));
}
}
void SceneBuilder::PushLayer(std::shared_ptr<ContainerLayer> layer) {
AddLayer(layer);
layer_stack_.push_back(std::move(layer));
}
void SceneBuilder::PopLayer() {
// We never pop the root layer, so that AddLayer operations are always valid.
if (layer_stack_.size() > 1) {
layer_stack_.pop_back();
}
}
} // namespace flutter