Revert "[fuchsia] Wire up OpacityLayer to Scenic (#11322)" (#12610)

This reverts commit fcc4ab3230.

Fixes https://github.com/flutter/flutter/issues/41394 and other
related correctness issues.

TBR: @arbreng @jason-simmons @mehmetf
This commit is contained in:
liyuqian
2019-09-27 16:50:43 -07:00
committed by GitHub
parent 3c271bb942
commit 7c3dcee2e9
39 changed files with 557 additions and 638 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ void BackdropFilterLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0});
ContainerLayer::Paint(context);
PaintChildren(context);
}
} // namespace flutter
+1 -16
View File
@@ -19,25 +19,10 @@ ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
set_needs_system_composite(true);
// An alpha "hole punch" is required if the frame behind us is not opaque.
if (!context->is_opaque) {
set_paint_bounds(
SkRect::MakeXYWH(offset_.fX, offset_.fY, size_.fWidth, size_.fHeight));
}
}
void ChildSceneLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ChildSceneLayer::Paint");
FML_DCHECK(needs_painting());
// If we are being rendered into our own frame using the system compositor,
// then it is neccesary to "punch a hole" in the canvas/frame behind us so
// that group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
FML_NOTREACHED() << "This layer never needs painting.";
}
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
+23 -17
View File
@@ -4,6 +4,12 @@
#include "flutter/flow/layers/clip_path_layer.h"
#if defined(OS_FUCHSIA)
#include "lib/ui/scenic/cpp/commands.h"
#endif // defined(OS_FUCHSIA)
namespace flutter {
ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior)
@@ -18,18 +24,29 @@ void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect clip_path_bounds = clip_path_.getBounds();
if (context->cull_rect.intersect(clip_path_bounds)) {
context->mutators_stack.PushClipPath(clip_path_);
ContainerLayer::Preroll(context, matrix);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (clip_path_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_path_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
if (child_paint_bounds.intersect(clip_path_bounds)) {
set_paint_bounds(child_paint_bounds);
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_path_.getBounds());
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipPathLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipPathLayer::Paint");
FML_DCHECK(needs_painting());
@@ -41,21 +58,10 @@ void ClipPathLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
}
ContainerLayer::Paint(context);
PaintChildren(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_path_.getBounds());
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
+4
View File
@@ -15,8 +15,12 @@ class ClipPathLayer : public ContainerLayer {
~ClipPathLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkPath clip_path_;
+19 -20
View File
@@ -15,21 +15,31 @@ ClipRectLayer::~ClipRectLayer() = default;
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_rect_bounds = clip_rect_;
if (context->cull_rect.intersect(clip_rect_bounds)) {
context->mutators_stack.PushClipRect(clip_rect_bounds);
ContainerLayer::Preroll(context, matrix);
if (context->cull_rect.intersect(clip_rect_)) {
context->mutators_stack.PushClipRect(clip_rect_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (clip_rect_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_rect_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipRectLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rect_);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRectLayer::Paint");
FML_DCHECK(needs_painting());
@@ -41,21 +51,10 @@ void ClipRectLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(clip_rect_, nullptr);
}
ContainerLayer::Paint(context);
PaintChildren(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipRectLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rect_);
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
+3
View File
@@ -16,7 +16,10 @@ class ClipRectLayer : public ContainerLayer {
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkRect clip_rect_;
+17 -17
View File
@@ -18,18 +18,29 @@ void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect clip_rrect_bounds = clip_rrect_.getBounds();
if (context->cull_rect.intersect(clip_rrect_bounds)) {
context->mutators_stack.PushClipRRect(clip_rrect_);
ContainerLayer::Preroll(context, matrix);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (clip_rrect_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_rrect_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
if (child_paint_bounds.intersect(clip_rrect_bounds)) {
set_paint_bounds(child_paint_bounds);
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rrect_.getBounds());
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRRectLayer::Paint");
FML_DCHECK(needs_painting());
@@ -41,21 +52,10 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
}
ContainerLayer::Paint(context);
PaintChildren(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rrect_.getBounds());
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
+4
View File
@@ -15,8 +15,12 @@ class ClipRRectLayer : public ContainerLayer {
~ClipRRectLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkRRect clip_rrect_;
+1 -1
View File
@@ -20,7 +20,7 @@ void ColorFilterLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save =
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
ContainerLayer::Paint(context);
PaintChildren(context);
}
} // namespace flutter
+28 -84
View File
@@ -4,44 +4,13 @@
#include "flutter/flow/layers/container_layer.h"
#include <memory>
#include "flutter/flow/layers/transform_layer.h"
namespace flutter {
static float ClampElevation(float elevation,
float parent_elevation,
float max_elevation) {
// TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be
// able to have developers specify the behavior here to alternatives besides
// clamping, like normalization on some arbitrary curve.
float clamped_elevation = elevation;
if (max_elevation > -1 && (parent_elevation + elevation) > max_elevation) {
// Clamp the local z coordinate at our max bound. Take into account the
// parent z position here to fix clamping in cases where the child is
// overflowing because of its parents.
clamped_elevation = max_elevation - parent_elevation;
}
ContainerLayer::ContainerLayer() {}
return clamped_elevation;
}
ContainerLayer::~ContainerLayer() = default;
ContainerLayer::ContainerLayer(bool force_single_child) {
// Place all "child" layers under a single child if requested.
if (force_single_child) {
single_child_ = std::make_shared<TransformLayer>(SkMatrix::I());
single_child_->set_parent(this);
layers_.push_back(single_child_);
}
}
void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
// Place all "child" layers under a single child if requested.
if (single_child_) {
single_child_->Add(std::move(layer));
return;
}
layer->set_parent(this);
layers_.push_back(std::move(layer));
}
@@ -49,29 +18,25 @@ void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ContainerLayer::Preroll");
// Track total elevation as we walk the tree, in order to deal with bounds
// overflow in z.
parent_elevation_ = context->total_elevation;
clamped_elevation_ = ClampElevation(elevation_, parent_elevation_,
context->frame_physical_depth);
context->total_elevation += clamped_elevation_;
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
set_paint_bounds(child_paint_bounds);
}
void ContainerLayer::PrerollChildren(PrerollContext* context,
const SkMatrix& child_matrix,
SkRect* child_paint_bounds) {
for (auto& layer : layers_) {
layer->Preroll(context, matrix);
layer->Preroll(context, child_matrix);
if (layer->needs_system_composite()) {
set_needs_system_composite(true);
}
child_paint_bounds.join(layer->paint_bounds());
child_paint_bounds->join(layer->paint_bounds());
}
set_paint_bounds(child_paint_bounds);
// Restore the elevation for our parent.
context->total_elevation = parent_elevation_;
}
void ContainerLayer::Paint(PaintContext& context) const {
void ContainerLayer::PaintChildren(PaintContext& context) const {
FML_DCHECK(needs_painting());
// Intentionally not tracing here as there should be no self-time
@@ -83,45 +48,24 @@ void ContainerLayer::Paint(PaintContext& context) const {
}
}
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
if (should_render_as_frame()) {
FML_DCHECK(needs_system_composite());
// Retained rendering: speedup by reusing a retained entity node if
// possible. When an entity node is reused, no paint layer is added to the
// frame so we won't call Paint.
LayerRasterCacheKey key(unique_id(), context.Matrix());
if (context.HasRetainedNode(key)) {
const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
FML_DCHECK(context.top_entity());
FML_DCHECK(retained_node.session() == context.session());
context.top_entity()->embedder_node().AddChild(retained_node);
return;
}
SceneUpdateContext::Frame frame(context, frame_rrect_, frame_color_,
frame_opacity_, elevation(), this);
// Paint the child layers into the Frame as well as allowing them to create
// their own scene entities.
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
}
if (layer->needs_system_composite()) {
layer->UpdateScene(context);
}
}
} else {
// Update all of the Layers which are part of the container. This may cause
// additional scene entities to be created.
for (auto& layer : layers()) {
if (layer->needs_system_composite()) {
layer->UpdateScene(context);
}
}
}
#endif // defined(OS_FUCHSIA)
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
UpdateSceneChildren(context);
}
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// Paint all of the layers which need to be drawn into the container.
// These may be flattened down to a containing
for (auto& layer : layers_) {
if (layer->needs_system_composite()) {
layer->UpdateScene(context);
}
}
}
#endif // defined(OS_FUCHSIA)
} // namespace flutter
+18 -33
View File
@@ -5,56 +5,41 @@
#ifndef FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
#include <memory>
#include <vector>
#include "flutter/flow/layers/layer.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRRect.h"
namespace flutter {
class ContainerLayer : public Layer {
public:
ContainerLayer(bool force_single_child = false);
~ContainerLayer() override = default;
ContainerLayer();
~ContainerLayer() override;
void Add(std::shared_ptr<Layer> layer);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
bool should_render_as_frame() const { return !frame_rrect_.isEmpty(); }
void set_frame_properties(SkRRect frame_rrect,
SkColor frame_color,
float frame_opacity) {
frame_rrect_ = frame_rrect;
frame_color_ = frame_color;
frame_opacity_ = frame_opacity;
}
float elevation() const { return clamped_elevation_; }
float total_elevation() const {
return parent_elevation_ + clamped_elevation_;
}
void set_elevation(float elevation) {
parent_elevation_ = 0.0f;
elevation_ = elevation;
clamped_elevation_ = elevation;
}
#endif // defined(OS_FUCHSIA)
const std::vector<std::shared_ptr<Layer>>& layers() const { return layers_; }
protected:
void PrerollChildren(PrerollContext* context,
const SkMatrix& child_matrix,
SkRect* child_paint_bounds);
void PaintChildren(PaintContext& context) const;
#if defined(OS_FUCHSIA)
void UpdateSceneChildren(SceneUpdateContext& context);
#endif // defined(OS_FUCHSIA)
// For OpacityLayer to restructure to have a single child.
void ClearChildren() { layers_.clear(); }
private:
std::vector<std::shared_ptr<Layer>> layers_;
std::shared_ptr<ContainerLayer> single_child_;
SkRRect frame_rrect_;
SkColor frame_color_;
float parent_elevation_ = 0.0f;
float elevation_ = 0.0f;
float clamped_elevation_ = 0.0f;
float frame_opacity_ = 1.0f;
FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
};
+14 -10
View File
@@ -7,9 +7,17 @@
#include "flutter/flow/paint_utils.h"
#include "third_party/skia/include/core/SkColorFilter.h"
namespace {
namespace flutter {
uint64_t NextUniqueID() {
Layer::Layer()
: parent_(nullptr),
needs_system_composite_(false),
paint_bounds_(SkRect::MakeEmpty()),
unique_id_(NextUniqueID()) {}
Layer::~Layer() = default;
uint64_t Layer::NextUniqueID() {
static std::atomic<uint64_t> nextID(1);
uint64_t id;
do {
@@ -18,15 +26,11 @@ uint64_t NextUniqueID() {
return id;
}
} // anonymous namespace
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
namespace flutter {
Layer::Layer()
: parent_(nullptr),
paint_bounds_(SkRect::MakeEmpty()),
unique_id_(NextUniqueID()),
needs_system_composite_(false) {}
#if defined(OS_FUCHSIA)
void Layer::UpdateScene(SceneUpdateContext& context) {}
#endif // defined(OS_FUCHSIA)
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkRect& bounds,
+21 -23
View File
@@ -11,7 +11,6 @@
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/flow/texture.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/compiler_specific.h"
@@ -28,6 +27,14 @@
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
#if defined(OS_FUCHSIA)
#include "flutter/flow/scene_update_context.h" //nogncheck
#include "lib/ui/scenic/cpp/resources.h" //nogncheck
#include "lib/ui/scenic/cpp/session.h" //nogncheck
#endif // defined(OS_FUCHSIA)
namespace flutter {
static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
@@ -36,7 +43,6 @@ static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer };
class ContainerLayer;
class SceneUpdateContext;
struct PrerollContext {
RasterCache* raster_cache;
@@ -51,15 +57,7 @@ struct PrerollContext {
const Stopwatch& ui_time;
TextureRegistry& texture_registry;
const bool checkerboard_offscreen_layers;
// The folllowing allow us to make use of the scene metrics during Preroll.
float frame_physical_depth;
float frame_device_pixel_ratio;
// The following allow us to track properties like elevation and opacity
// which stack with each other during Preroll.
float total_elevation = 0.0f;
bool is_opaque = true;
};
// Represents a single composited layer. Created on the UI thread but then
@@ -67,7 +65,9 @@ struct PrerollContext {
class Layer {
public:
Layer();
virtual ~Layer() = default;
virtual ~Layer();
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
struct PaintContext {
// When splitting the scene into multiple canvases (e.g when embedding
@@ -89,10 +89,6 @@ class Layer {
TextureRegistry& texture_registry;
const RasterCache* raster_cache;
const bool checkerboard_offscreen_layers;
// The folllowing allow us to make use of the scene metrics during Paint.
float frame_physical_depth;
float frame_device_pixel_ratio;
};
// Calls SkCanvas::saveLayer and restores the layer upon destruction. Also
@@ -122,18 +118,15 @@ class Layer {
const SkRect bounds_;
};
// Performs pre-paint optimizations, including bounds calculation. Called
// before |Paint|. If the |paint_bounds| calculated in this method is empty,
// then |Paint| will not be called.
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix) {}
// Paints this layer onto a canvas. Not called if |paint_bounds| is empty.
virtual void Paint(PaintContext& context) const = 0;
#if defined(OS_FUCHSIA)
// Updates the system composited scene.
virtual void UpdateScene(SceneUpdateContext& context) {}
virtual void UpdateScene(SceneUpdateContext& context);
#endif
ContainerLayer* parent() const { return parent_; }
void set_parent(ContainerLayer* parent) { parent_ = parent; }
bool needs_system_composite() const { return needs_system_composite_; }
@@ -142,6 +135,9 @@ class Layer {
}
const SkRect& paint_bounds() const { return paint_bounds_; }
// This must be set by the time Preroll() returns otherwise the layer will
// be assumed to have empty paint bounds (paints no content).
void set_paint_bounds(const SkRect& paint_bounds) {
paint_bounds_ = paint_bounds;
}
@@ -152,9 +148,11 @@ class Layer {
private:
ContainerLayer* parent_;
bool needs_system_composite_;
SkRect paint_bounds_;
uint64_t unique_id_;
bool needs_system_composite_;
static uint64_t NextUniqueID();
FML_DISALLOW_COPY_AND_ASSIGN(Layer);
};
+44 -69
View File
@@ -9,18 +9,10 @@
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
#if defined(OS_FUCHSIA)
#include <lib/ui/scenic/cpp/resources.h>
#endif
namespace flutter {
LayerTree::LayerTree(const SkISize& frame_size,
float frame_physical_depth,
float frame_device_pixel_ratio)
: frame_size_(frame_size),
frame_physical_depth_(frame_physical_depth),
frame_device_pixel_ratio_(frame_device_pixel_ratio),
LayerTree::LayerTree()
: frame_size_{},
rasterizer_tracing_threshold_(0),
checkerboard_raster_cache_images_(false),
checkerboard_offscreen_layers_(false) {}
@@ -50,13 +42,36 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
frame.context().raster_time(),
frame.context().ui_time(),
frame.context().texture_registry(),
checkerboard_offscreen_layers_,
frame_physical_depth_,
frame_device_pixel_ratio_};
checkerboard_offscreen_layers_};
root_layer_->Preroll(&context, frame.root_surface_transformation());
}
#if defined(OS_FUCHSIA)
void LayerTree::UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container) {
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
const auto& metrics = context.metrics();
SceneUpdateContext::Transform transform(context, // context
1.0f / metrics->scale_x, // X
1.0f / metrics->scale_y, // Y
1.0f / metrics->scale_z // Z
);
SceneUpdateContext::Frame frame(
context,
SkRRect::MakeRect(
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
SK_ColorTRANSPARENT);
if (root_layer_->needs_system_composite()) {
root_layer_->UpdateScene(context);
}
if (root_layer_->needs_painting()) {
frame.AddPaintLayer(root_layer_.get());
}
container.AddChild(transform.entity_node());
}
#endif
void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache) const {
TRACE_EVENT0("flutter", "LayerTree::Paint");
@@ -79,9 +94,7 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
frame.context().ui_time(),
frame.context().texture_registry(),
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
checkerboard_offscreen_layers_,
frame_physical_depth_,
frame_device_pixel_ratio_};
checkerboard_offscreen_layers_};
if (root_layer_->needs_painting())
root_layer_->Paint(context);
@@ -105,18 +118,16 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
root_surface_transformation.reset();
PrerollContext preroll_context{
nullptr, // raster_cache (don't consult the cache)
nullptr, // gr_context (used for the raster cache)
nullptr, // external view embedder
unused_stack, // mutator stack
nullptr, // SkColorSpace* dst_color_space
kGiantRect, // SkRect cull_rect
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
false, // checkerboard_offscreen_layers
frame_physical_depth_, // maximum depth allowed for rendering
frame_device_pixel_ratio_ // ratio between logical and physical
nullptr, // raster_cache (don't consult the cache)
nullptr, // gr_context (used for the raster cache)
nullptr, // external view embedder
unused_stack, // mutator stack
nullptr, // SkColorSpace* dst_color_space
kGiantRect, // SkRect cull_rect
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
false, // checkerboard_offscreen_layers
};
SkISize canvas_size = canvas->getBaseLayerSize();
@@ -128,13 +139,11 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
canvas, // canvas
nullptr,
nullptr,
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
nullptr, // raster cache
false, // checkerboard offscreen layers
frame_physical_depth_, // maximum depth allowed for rendering
frame_device_pixel_ratio_ // ratio between logical and physical
unused_stopwatch, // frame time (dont care)
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
nullptr, // raster cache
false // checkerboard offscreen layers
};
// Even if we don't have a root layer, we still need to create an empty
@@ -150,38 +159,4 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
return recorder.finishRecordingAsPicture();
}
void LayerTree::UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container) {
#if defined(OS_FUCHSIA)
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
// Ensure the context is aware of the view metrics.
context.set_frame_dimensions(frame_size_, frame_physical_depth_,
frame_device_pixel_ratio_);
const auto& metrics = context.metrics();
FML_DCHECK(metrics->scale_x > 0.0f);
FML_DCHECK(metrics->scale_y > 0.0f);
FML_DCHECK(metrics->scale_z > 0.0f);
SceneUpdateContext::Transform transform(context, // context
1.0f / metrics->scale_x, // X
1.0f / metrics->scale_y, // Y
1.0f / metrics->scale_z // Z
);
SceneUpdateContext::Frame frame(
context,
SkRRect::MakeRect(
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
SK_ColorTRANSPARENT, /* opacity */ 1.0f, /* elevation */ 0.0f);
if (root_layer_->needs_system_composite()) {
root_layer_->UpdateScene(context);
}
if (root_layer_->needs_painting()) {
frame.AddPaintLayer(root_layer_.get());
}
container.AddChild(transform.entity_node());
#endif
}
} // namespace flutter
+14 -18
View File
@@ -16,37 +16,36 @@
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkSize.h"
namespace scenic {
class ContainerNode;
} // namespace scenic
namespace flutter {
class SceneUpdateContext;
class LayerTree {
public:
LayerTree(const SkISize& frame_size,
float frame_physical_depth,
float frame_device_pixel_ratio);
LayerTree();
~LayerTree();
void Preroll(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false);
void Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false) const;
sk_sp<SkPicture> Flatten(const SkRect& bounds);
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container);
#endif
void Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false) const;
sk_sp<SkPicture> Flatten(const SkRect& bounds);
Layer* root_layer() const { return root_layer_.get(); }
void set_root_layer(std::shared_ptr<Layer> root_layer) {
root_layer_ = std::move(root_layer);
}
const SkISize& frame_size() const { return frame_size_; }
float frame_physical_depth() const { return frame_physical_depth_; }
float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; }
void RecordBuildTime(fml::TimePoint begin_start);
fml::TimePoint build_start() const { return build_start_; }
@@ -73,13 +72,10 @@ class LayerTree {
}
private:
SkISize frame_size_; // Physical pixels.
std::shared_ptr<Layer> root_layer_;
fml::TimePoint build_start_;
fml::TimePoint build_finish_;
SkISize frame_size_; // Physical pixels.
float frame_physical_depth_;
float
frame_device_pixel_ratio_; // Ratio between logical and physical pixels.
uint32_t rasterizer_tracing_threshold_;
bool checkerboard_raster_cache_images_;
bool checkerboard_offscreen_layers_;
+36 -71
View File
@@ -4,64 +4,56 @@
#include "flutter/flow/layers/opacity_layer.h"
#include "flutter/flow/layers/transform_layer.h"
namespace flutter {
#if defined(OS_FUCHSIA)
constexpr bool kRenderOpacityUsingSystemCompositor = true;
#else
constexpr bool kRenderOpacityUsingSystemCompositor = false;
#endif
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f;
OpacityLayer::OpacityLayer(int alpha, const SkPoint& offset)
: ContainerLayer(true), alpha_(alpha), offset_(offset) {
#if !defined(OS_FUCHSIA)
static_assert(!kRenderOpacityUsingSystemCompositor,
"Delegation of OpacityLayer to the system compositor is only "
"allowed on Fuchsia");
#endif
: alpha_(alpha), offset_(offset) {}
if (kRenderOpacityUsingSystemCompositor) {
set_elevation(kOpacityElevationWhenUsingSystemCompositor);
OpacityLayer::~OpacityLayer() = default;
void OpacityLayer::EnsureSingleChild() {
FML_DCHECK(layers().size() > 0); // OpacityLayer should never be a leaf
if (layers().size() == 1) {
return;
}
// Be careful: SkMatrix's default constructor doesn't initialize the matrix to
// identity. Hence we have to explicitly call SkMatrix::setIdentity.
SkMatrix identity;
identity.setIdentity();
auto new_child = std::make_shared<flutter::TransformLayer>(identity);
for (auto& child : layers()) {
new_child->Add(child);
}
ClearChildren();
Add(new_child);
}
void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
EnsureSingleChild();
SkMatrix child_matrix = matrix;
float parent_is_opaque = context->is_opaque;
child_matrix.postTranslate(offset_.fX, offset_.fY);
context->mutators_stack.PushTransform(
SkMatrix::MakeTrans(offset_.fX, offset_.fY));
context->mutators_stack.PushOpacity(alpha_);
context->is_opaque = parent_is_opaque && (alpha_ == 255);
ContainerLayer::Preroll(context, child_matrix);
context->is_opaque = parent_is_opaque;
context->mutators_stack.Pop();
context->mutators_stack.Pop();
// When using the system compositor, do not include the offset or use the
// raster cache, since we are rendering as a separate piece of geometry.
if (kRenderOpacityUsingSystemCompositor) {
set_needs_system_composite(true);
set_frame_properties(SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
alpha_ / 255.0f);
// If the frame behind us is opaque, don't punch a hole in it for group
// opacity.
if (context->is_opaque) {
set_paint_bounds(SkRect());
}
} else {
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
if (context->raster_cache &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
Layer* child = layers()[0].get();
SkMatrix ctm = child_matrix;
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
// See |EnsureSingleChild|.
FML_DCHECK(layers().size() == 1);
if (context->view_embedder == nullptr && context->raster_cache &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
Layer* child = layers()[0].get();
SkMatrix ctm = child_matrix;
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
ctm = RasterCache::GetIntegralTransCTM(ctm);
ctm = RasterCache::GetIntegralTransCTM(ctm);
#endif
context->raster_cache->Prepare(context, child, ctm);
}
context->raster_cache->Prepare(context, child, ctm);
}
}
@@ -69,27 +61,6 @@ void OpacityLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
FML_DCHECK(needs_painting());
// The compositor will paint this layer (which is |Sk_ColorWHITE| scaled by
// opacity) via the model color on |SceneUpdateContext::Frame|.
//
// The child layers will be painted into the texture used by the Frame, so
// painting them here would actually cause them to be painted on the display
// twice -- once into the current canvas (which may be inside of another
// Frame) and once into the Frame's texture (which is then drawn on top of the
// current canvas).
if (kRenderOpacityUsingSystemCompositor) {
#if defined(OS_FUCHSIA)
// On Fuchsia, If we are being rendered into our own frame using the system
// compositor, then it is neccesary to "punch a hole" in the canvas/frame
// behind us so that single-pass group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
#endif
return;
}
SkPaint paint;
paint.setAlpha(alpha_);
@@ -101,6 +72,9 @@ void OpacityLayer::Paint(PaintContext& context) const {
context.leaf_nodes_canvas->getTotalMatrix()));
#endif
// See |EnsureSingleChild|.
FML_DCHECK(layers().size() == 1);
// Embedded platform views are changing the canvas in the middle of the paint
// traversal. To make sure we paint on the right canvas, when the embedded
// platform views preview is enabled (context.view_embedded is not null) we
@@ -131,16 +105,7 @@ void OpacityLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save_layer =
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
ContainerLayer::Paint(context);
}
void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
SceneUpdateContext::Transform transform(
context, SkMatrix::MakeTrans(offset_.fX, offset_.fY));
ContainerLayer::UpdateScene(context);
#endif
PaintChildren(context);
}
} // namespace flutter
+15 -2
View File
@@ -26,16 +26,29 @@ class OpacityLayer : public ContainerLayer {
// to many leaf layers. Therefore we try to capture that offset here to stop
// the propagation as repainting the OpacityLayer is expensive.
OpacityLayer(int alpha, const SkPoint& offset);
~OpacityLayer() override = default;
~OpacityLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
void UpdateScene(SceneUpdateContext& context) override;
// TODO(chinmaygarde): Once SCN-139 is addressed, introduce a new node in the
// session scene hierarchy.
private:
int alpha_;
SkPoint offset_;
// Restructure (if necessary) OpacityLayer to have only one child.
//
// This is needed to ensure that retained rendering can always be applied to
// save the costly saveLayer.
//
// If there are multiple children, this creates a new identity TransformLayer,
// sets all children to be the TransformLayer's children, and sets that
// TransformLayer as the single child of this OpacityLayer.
void EnsureSingleChild();
FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
};
+78 -84
View File
@@ -5,81 +5,66 @@
#include "flutter/flow/layers/physical_shape_layer.h"
#include "flutter/flow/paint_utils.h"
#include "include/core/SkColor.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"
namespace flutter {
constexpr SkScalar kLightHeight = 600;
constexpr SkScalar kLightRadius = 800;
constexpr bool kRenderPhysicalShapeUsingSystemCompositor = false;
const SkScalar kLightHeight = 600;
const SkScalar kLightRadius = 800;
PhysicalShapeLayer::PhysicalShapeLayer(SkColor color,
SkColor shadow_color,
SkScalar device_pixel_ratio,
float viewport_depth,
float elevation,
const SkPath& path,
Clip clip_behavior)
: color_(color),
shadow_color_(shadow_color),
device_pixel_ratio_(device_pixel_ratio),
viewport_depth_(viewport_depth),
elevation_(elevation),
path_(path),
isRect_(false),
clip_behavior_(clip_behavior) {
#if !defined(OS_FUCHSIA)
static_assert(!kRenderPhysicalShapeUsingSystemCompositor,
"Delegation of PhysicalShapeLayer to the system compositor is "
"only allowed on Fuchsia");
#endif // !defined(OS_FUCHSIA)
// If rendering as a separate frame using the system compositor, then make
// sure to set up the properties needed to do so.
if (kRenderPhysicalShapeUsingSystemCompositor) {
SkRect rect;
SkRRect frame_rrect;
if (path.isRect(&rect)) {
frame_rrect = SkRRect::MakeRect(rect);
} else if (path.isRRect(&frame_rrect)) {
// Nothing needed here, as isRRect will fill in frameRRect_ already.
} else if (path.isOval(&rect)) {
// isRRect returns false for ovals, so we need to explicitly check isOval
// as well.
frame_rrect = SkRRect::MakeOval(rect);
} else {
// Scenic currently doesn't provide an easy way to create shapes from
// arbitrary paths.
// For shapes that cannot be represented as a rounded rectangle we
// default to use the bounding rectangle.
// TODO(amirh): fix this once we have a way to create a Scenic shape from
// an SkPath.
frame_rrect = SkRRect::MakeRect(path.getBounds());
}
set_frame_properties(frame_rrect, color_, /* opacity */ 1.0f);
SkRect rect;
if (path.isRect(&rect)) {
isRect_ = true;
frameRRect_ = SkRRect::MakeRect(rect);
} else if (path.isRRect(&frameRRect_)) {
isRect_ = frameRRect_.isRect();
} else if (path.isOval(&rect)) {
// isRRect returns false for ovals, so we need to explicitly check isOval
// as well.
frameRRect_ = SkRRect::MakeOval(rect);
} else {
// Scenic currently doesn't provide an easy way to create shapes from
// arbitrary paths.
// For shapes that cannot be represented as a rounded rectangle we
// default to use the bounding rectangle.
// TODO(amirh): fix this once we have a way to create a Scenic shape from
// an SkPath.
frameRRect_ = SkRRect::MakeRect(path.getBounds());
}
set_elevation(elevation);
}
PhysicalShapeLayer::~PhysicalShapeLayer() = default;
void PhysicalShapeLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
ContainerLayer::Preroll(context, matrix);
context->total_elevation += elevation_;
total_elevation_ = context->total_elevation;
SkRect child_paint_bounds;
PrerollChildren(context, matrix, &child_paint_bounds);
context->total_elevation -= elevation_;
// Compute paint bounds based on the layer's elevation.
set_paint_bounds(path_.getBounds());
if (elevation() == 0) {
return;
}
// If elevation is non-zero, compute the proper paint_bounds to allow drawing
// a shadow.
if (kRenderPhysicalShapeUsingSystemCompositor) {
// Let the system compositor draw all shadows for us, by popping us out as
// a new frame.
set_needs_system_composite(true);
// If the frame behind us is opaque, don't punch a hole in it for group
// opacity.
if (context->is_opaque) {
set_paint_bounds(SkRect());
}
if (elevation_ == 0) {
set_paint_bounds(path_.getBounds());
} else {
#if defined(OS_FUCHSIA)
// Let the system compositor draw all shadows for us.
set_needs_system_composite(true);
#else
// Add some margin to the paint bounds to leave space for the shadow.
// We fill this whole region and clip children to it so we don't need to
// join the child paint bounds.
@@ -115,46 +100,55 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context,
// t = tangent of AOB, i.e., multiplier for elevation to extent
SkRect bounds(path_.getBounds());
// tangent for x
double tx = (kLightRadius * context->frame_device_pixel_ratio +
bounds.width() * 0.5) /
double tx = (kLightRadius * device_pixel_ratio_ + bounds.width() * 0.5) /
kLightHeight;
// tangent for y
double ty = (kLightRadius * context->frame_device_pixel_ratio +
bounds.height() * 0.5) /
double ty = (kLightRadius * device_pixel_ratio_ + bounds.height() * 0.5) /
kLightHeight;
bounds.outset(elevation() * tx, elevation() * ty);
bounds.outset(elevation_ * tx, elevation_ * ty);
set_paint_bounds(bounds);
#endif // defined(OS_FUCHSIA)
}
}
#if defined(OS_FUCHSIA)
void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// Retained rendering: speedup by reusing a retained entity node if possible.
// When an entity node is reused, no paint layer is added to the frame so we
// won't call PhysicalShapeLayer::Paint.
LayerRasterCacheKey key(unique_id(), context.Matrix());
if (context.HasRetainedNode(key)) {
const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
FML_DCHECK(context.top_entity());
FML_DCHECK(retained_node.session() == context.session());
context.top_entity()->entity_node().AddChild(retained_node);
return;
}
// If we can't find an existing retained surface, create one.
SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_,
total_elevation_, viewport_depth_, this);
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
}
}
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void PhysicalShapeLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
FML_DCHECK(needs_painting());
// The compositor will paint this layer (which is a solid color) via the
// color on |SceneUpdateContext::Frame|.
//
// The child layers will be painted into the texture used by the Frame, so
// painting them here would actually cause them to be painted on the display
// twice -- once into the current canvas (which may be inside of another
// Frame) and once into the Frame's texture (which is then drawn on top of the
// current canvas).
if (kRenderPhysicalShapeUsingSystemCompositor) {
#if defined(OS_FUCHSIA)
// On Fuchsia, If we are being rendered into our own frame using the system
// compositor, then it is neccesary to "punch a hole" in the canvas/frame
// behind us so that single-pass group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
#endif
return;
}
if (elevation() != 0) {
DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation(),
SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio);
if (elevation_ != 0) {
DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
SkColorGetA(color_) != 0xff, device_pixel_ratio_);
}
// Call drawPath without clip if possible for better performance.
@@ -189,7 +183,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const {
context.leaf_nodes_canvas->drawPaint(paint);
}
ContainerLayer::Paint(context);
PaintChildren(context);
context.internal_nodes_canvas->restoreToCount(saveCount);
}
+19 -4
View File
@@ -13,13 +13,12 @@ class PhysicalShapeLayer : public ContainerLayer {
public:
PhysicalShapeLayer(SkColor color,
SkColor shadow_color,
SkScalar device_pixel_ratio,
float viewport_depth,
float elevation,
const SkPath& path,
Clip clip_behavior);
~PhysicalShapeLayer() override = default;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
~PhysicalShapeLayer() override;
static void DrawShadow(SkCanvas* canvas,
const SkPath& path,
@@ -28,11 +27,27 @@ class PhysicalShapeLayer : public ContainerLayer {
bool transparentOccluder,
SkScalar dpr);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkColor color_;
SkColor shadow_color_;
SkScalar device_pixel_ratio_;
float viewport_depth_;
float elevation_ = 0.0f;
float total_elevation_ = 0.0f;
SkPath path_;
bool isRect_;
SkRRect frameRRect_;
Clip clip_behavior_;
friend class PhysicalShapeLayer_TotalElevation_Test;
};
} // namespace flutter
@@ -16,6 +16,8 @@ TEST(PhysicalShapeLayer, TotalElevation) {
for (int i = 0; i < 4; i += 1) {
layers[i] =
std::make_shared<PhysicalShapeLayer>(dummy_color, dummy_color,
1.0f, // pixel ratio,
1.0f, // depth
(float)(i + 1), // elevation
dummy_path, Clip::none);
}
@@ -38,8 +40,6 @@ TEST(PhysicalShapeLayer, TotalElevation) {
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
false, // checkerboard_offscreen_layers
6.0f, // depth
1.0f, // pixel ratio
0.0f, // total elevation
};
@@ -55,14 +55,14 @@ TEST(PhysicalShapeLayer, TotalElevation) {
// | \
// | layers[2] +3.0f
// | |
// | layers[3] +4.0f (clamped to 6.0f)
// | layers[3] +4.0f
// |
// |
// layers[1] + 2.0f
EXPECT_EQ(layers[0]->total_elevation(), 1.0f);
EXPECT_EQ(layers[1]->total_elevation(), 3.0f);
EXPECT_EQ(layers[2]->total_elevation(), 4.0f);
EXPECT_EQ(layers[3]->total_elevation(), 6.0f);
EXPECT_EQ(layers[0]->total_elevation_, 1.0f);
EXPECT_EQ(layers[1]->total_elevation_, 3.0f);
EXPECT_EQ(layers[2]->total_elevation_, 4.0f);
EXPECT_EQ(layers[3]->total_elevation_, 8.0f);
}
} // namespace flutter

Some files were not shown because too many files have changed in this diff Show More