|  | // 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 "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/layer_tree.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/floating_point.h" | 
|  | #include "flutter/lib/ui/painting/matrix.h" | 
|  | #include "flutter/lib/ui/painting/shader.h" | 
|  | #include "third_party/tonic/converter/dart_converter.h" | 
|  | #include "third_party/tonic/dart_args.h" | 
|  | #include "third_party/tonic/dart_binding_macros.h" | 
|  | #include "third_party/tonic/dart_library_natives.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>& oldLayer) { | 
|  | SkM44 sk_matrix = ToSkM44(matrix4); | 
|  | auto layer = std::make_shared<flutter::TransformLayer>(sk_matrix); | 
|  | PushLayer(layer); | 
|  | // matrix4 has to be released before we can return another Dart object | 
|  | matrix4.Release(); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushOffset(Dart_Handle layer_handle, | 
|  | double dx, | 
|  | double dy, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | SkMatrix sk_matrix = SkMatrix::Translate(SafeNarrow(dx), SafeNarrow(dy)); | 
|  | auto layer = std::make_shared<flutter::TransformLayer>(sk_matrix); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushClipRect(Dart_Handle layer_handle, | 
|  | double left, | 
|  | double right, | 
|  | double top, | 
|  | double bottom, | 
|  | int clipBehavior, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | SkRect clipRect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), | 
|  | SafeNarrow(right), SafeNarrow(bottom)); | 
|  | flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior); | 
|  | auto layer = | 
|  | std::make_shared<flutter::ClipRectLayer>(clipRect, clip_behavior); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushClipRRect(Dart_Handle layer_handle, | 
|  | const RRect& rrect, | 
|  | int clipBehavior, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior); | 
|  | auto layer = | 
|  | std::make_shared<flutter::ClipRRectLayer>(rrect.sk_rrect, clip_behavior); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushClipPath(Dart_Handle layer_handle, | 
|  | const CanvasPath* path, | 
|  | int clipBehavior, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior); | 
|  | FML_DCHECK(clip_behavior != flutter::Clip::kNone); | 
|  | auto layer = | 
|  | std::make_shared<flutter::ClipPathLayer>(path->path(), clip_behavior); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushOpacity(Dart_Handle layer_handle, | 
|  | int alpha, | 
|  | double dx, | 
|  | double dy, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | auto layer = std::make_shared<flutter::OpacityLayer>( | 
|  | alpha, SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy))); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushColorFilter(Dart_Handle layer_handle, | 
|  | const ColorFilter* color_filter, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | auto layer = | 
|  | std::make_shared<flutter::ColorFilterLayer>(color_filter->filter()); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushImageFilter(Dart_Handle layer_handle, | 
|  | const ImageFilter* image_filter, | 
|  | double dx, | 
|  | double dy, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | auto layer = std::make_shared<flutter::ImageFilterLayer>( | 
|  | image_filter->filter(), SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy))); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushBackdropFilter( | 
|  | Dart_Handle layer_handle, | 
|  | ImageFilter* filter, | 
|  | int blendMode, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | auto layer = std::make_shared<flutter::BackdropFilterLayer>( | 
|  | filter->filter(), static_cast<DlBlendMode>(blendMode)); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::pushShaderMask(Dart_Handle layer_handle, | 
|  | Shader* shader, | 
|  | double maskRectLeft, | 
|  | double maskRectRight, | 
|  | double maskRectTop, | 
|  | double maskRectBottom, | 
|  | int blendMode, | 
|  | int filterQualityIndex, | 
|  | const fml::RefPtr<EngineLayer>& oldLayer) { | 
|  | SkRect rect = | 
|  | SkRect::MakeLTRB(SafeNarrow(maskRectLeft), SafeNarrow(maskRectTop), | 
|  | SafeNarrow(maskRectRight), SafeNarrow(maskRectBottom)); | 
|  | auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); | 
|  | auto layer = std::make_shared<flutter::ShaderMaskLayer>( | 
|  | shader->shader(sampling), rect, static_cast<DlBlendMode>(blendMode)); | 
|  | PushLayer(layer); | 
|  | EngineLayer::MakeRetained(layer_handle, layer); | 
|  |  | 
|  | if (oldLayer && oldLayer->Layer()) { | 
|  | layer->AssignOldLayer(oldLayer->Layer().get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SceneBuilder::addRetained(const fml::RefPtr<EngineLayer>& retainedLayer) { | 
|  | AddLayer(retainedLayer->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>( | 
|  | SkPoint::Make(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 textureId, | 
|  | bool freeze, | 
|  | int filterQualityIndex) { | 
|  | auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); | 
|  | auto layer = std::make_unique<flutter::TextureLayer>( | 
|  | SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)), | 
|  | SkSize::Make(SafeNarrow(width), SafeNarrow(height)), textureId, freeze, | 
|  | sampling); | 
|  | AddLayer(std::move(layer)); | 
|  | } | 
|  |  | 
|  | void SceneBuilder::addPlatformView(double dx, | 
|  | double dy, | 
|  | double width, | 
|  | double height, | 
|  | int64_t viewId) { | 
|  | auto layer = std::make_unique<flutter::PlatformViewLayer>( | 
|  | SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)), | 
|  | SkSize::Make(SafeNarrow(width), SafeNarrow(height)), viewId); | 
|  | AddLayer(std::move(layer)); | 
|  | } | 
|  |  | 
|  | void SceneBuilder::addPerformanceOverlay(uint64_t enabledOptions, | 
|  | double left, | 
|  | double right, | 
|  | double top, | 
|  | double bottom) { | 
|  | SkRect rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), | 
|  | SafeNarrow(right), SafeNarrow(bottom)); | 
|  | auto layer = | 
|  | std::make_unique<flutter::PerformanceOverlayLayer>(enabledOptions); | 
|  | 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 |