99
1010namespace flutter {
1111
12- OpacityLayer::OpacityLayer (int alpha, const SkPoint& offset)
13- : alpha_(alpha), offset_(offset) {
12+ // The OpacityLayer has no real "elevation", but we want to avoid Z-fighting
13+ // when using the system compositor. Choose a small but non-zero value for
14+ // this.
15+ constexpr float kOpacityElevationWhenUsingSystemCompositor = 0 .0001f ;
16+
17+ #if !defined(OS_FUCHSIA)
18+ void OpacityLayerBase::Preroll (PrerollContext* context,
19+ const SkMatrix& matrix) {
20+ const SkAlpha alpha = SkColorGetA (color ());
21+ const float parent_is_opaque = context->is_opaque ;
22+
23+ context->mutators_stack .PushOpacity (alpha);
24+ context->is_opaque = parent_is_opaque && (alpha == 255 );
25+ ContainerLayer::Preroll (context, matrix);
26+ context->is_opaque = parent_is_opaque;
27+ context->mutators_stack .Pop ();
28+ }
29+ #endif
30+
31+ OpacityLayer::OpacityLayer (SkAlpha opacity, const SkPoint& offset)
32+ : OpacityLayerBase(SK_ColorBLACK,
33+ opacity,
34+ kOpacityElevationWhenUsingSystemCompositor ),
35+ offset_ (offset) {
1436 // Ensure OpacityLayer has only one direct child.
1537 //
1638 // This is needed to ensure that retained rendering can always be applied to
@@ -33,15 +55,30 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
3355 ContainerLayer* container = GetChildContainer ();
3456 FML_DCHECK (!container->layers ().empty ()); // OpacityLayer can't be a leaf.
3557
58+ // Factor in the offset during Preroll. |OpacityLayerBase| will handle the
59+ // opacity.
3660 SkMatrix child_matrix = matrix;
3761 child_matrix.postTranslate (offset_.fX , offset_.fY );
3862 context->mutators_stack .PushTransform (
3963 SkMatrix::MakeTrans (offset_.fX , offset_.fY ));
40- context->mutators_stack .PushOpacity (alpha_);
41- ContainerLayer::Preroll (context, child_matrix);
42- context->mutators_stack .Pop ();
64+ OpacityLayerBase::Preroll (context, child_matrix);
4365 context->mutators_stack .Pop ();
44- set_paint_bounds (paint_bounds ().makeOffset (offset_.fX , offset_.fY ));
66+
67+ // When using the system compositor, do not include the offset since we are
68+ // rendering as a separate piece of geometry and the offset will be baked into
69+ // that geometry's transform.
70+ if (OpacityLayerBase::can_system_composite ()) {
71+ set_dimensions (SkRRect::MakeRect (paint_bounds ()));
72+
73+ // If the frame behind us is opaque, don't punch a hole in it for group
74+ // opacity.
75+ if (context->is_opaque ) {
76+ set_paint_bounds (SkRect::MakeEmpty ());
77+ }
78+ set_needs_system_composite (true );
79+ } else {
80+ set_paint_bounds (paint_bounds ().makeOffset (offset_.fX , offset_.fY ));
81+ }
4582
4683 if (!context->has_platform_view && context->raster_cache &&
4784 SkRect::Intersects (context->cull_rect , paint_bounds ())) {
@@ -53,12 +90,38 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
5390 }
5491}
5592
93+ #if defined(OS_FUCHSIA)
94+
95+ void OpacityLayer::UpdateScene (SceneUpdateContext& context) {
96+ SceneUpdateContext::Transform transform (
97+ context, SkMatrix::MakeTrans (offset_.fX , offset_.fY ));
98+
99+ // OpacityLayerBase will handle applying the opacity itself.
100+ OpacityLayerBase::UpdateScene (context);
101+ }
102+
103+ #endif
104+
56105void OpacityLayer::Paint (PaintContext& context) const {
57106 TRACE_EVENT0 (" flutter" , " OpacityLayer::Paint" );
58107 FML_DCHECK (needs_painting ());
59108
109+ // The compositor will paint this layer (which is |Sk_ColorBLACK| with alpha
110+ // scaled by opacity) via the model color on |SceneUpdateContext::Frame|.
111+ //
112+ // The child layers will be painted into the texture used by the Frame, so
113+ // painting them here would actually cause them to be painted on the display
114+ // twice -- once into the current canvas (which may be inside of another
115+ // Frame) and once into the Frame's texture (which is then drawn on top of the
116+ // current canvas).
117+ if (OpacityLayerBase::can_system_composite ()) {
118+ FML_DCHECK (needs_system_composite ());
119+ OpacityLayerBase::Paint (context);
120+ return ;
121+ }
122+
60123 SkPaint paint;
61- paint.setAlpha (alpha_ );
124+ paint.setAlpha (opacity () );
62125
63126 SkAutoCanvasRestore save (context.internal_nodes_canvas , true );
64127 context.internal_nodes_canvas ->translate (offset_.fX , offset_.fY );
@@ -85,16 +148,15 @@ void OpacityLayer::Paint(PaintContext& context) const {
85148 // RasterCache::GetIntegralTransCTM optimization.
86149 //
87150 // Note that the following lines are only accessible when the raster cache is
88- // not available (e.g., when we're using the software backend in golden
89- // tests).
151+ // not available, or when a cache miss occurs.
90152 SkRect saveLayerBounds;
91153 paint_bounds ()
92154 .makeOffset (-offset_.fX , -offset_.fY )
93155 .roundOut (&saveLayerBounds);
94156
95157 Layer::AutoSaveLayer save_layer =
96158 Layer::AutoSaveLayer::Create (context, saveLayerBounds, &paint);
97- PaintChildren (context);
159+ OpacityLayerBase::Paint (context);
98160}
99161
100162ContainerLayer* OpacityLayer::GetChildContainer () const {
0 commit comments