1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_
6#define FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_
7
8#include "flutter/flow/layers/cacheable_layer.h"
9#include "flutter/flow/layers/container_layer.h"
10#include "flutter/flow/paint_utils.h"
11
12namespace flutter {
13
14template <class T>
15class ClipShapeLayer : public CacheableContainerLayer {
16 public:
17 using ClipShape = T;
18 ClipShapeLayer(const ClipShape& clip_shape, Clip clip_behavior)
19 : CacheableContainerLayer(),
20 clip_shape_(clip_shape),
21 clip_behavior_(clip_behavior) {
22 FML_DCHECK(clip_behavior != Clip::none);
23 }
24
25 void Diff(DiffContext* context, const Layer* old_layer) override {
26 DiffContext::AutoSubtreeRestore subtree(context);
27 auto* prev = static_cast<const ClipShapeLayer<ClipShape>*>(old_layer);
28 if (!context->IsSubtreeDirty()) {
29 FML_DCHECK(prev);
30 if (clip_behavior_ != prev->clip_behavior_ ||
31 clip_shape_ != prev->clip_shape_) {
32 context->MarkSubtreeDirty(previous_paint_region: context->GetOldLayerPaintRegion(layer: old_layer));
33 }
34 }
35 if (UsesSaveLayer(enable_impeller: context->impeller_enabled()) &&
36 context->has_raster_cache()) {
37 context->WillPaintWithIntegralTransform();
38 }
39 if (context->PushCullRect(clip: clip_shape_bounds())) {
40 DiffChildren(context, old_layer: prev);
41 }
42 context->SetLayerPaintRegion(layer: this, region: context->CurrentSubtreeRegion());
43 }
44
45 void Preroll(PrerollContext* context) override {
46 bool uses_save_layer = UsesSaveLayer(enable_impeller: context->impeller_enabled);
47
48 // We can use the raster_cache for children only when the use_save_layer is
49 // true so if use_save_layer is false we pass the layer_raster_item is
50 // nullptr which mean we don't do raster cache logic.
51 AutoCache cache =
52 AutoCache(uses_save_layer ? layer_raster_cache_item_.get() : nullptr,
53 context, context->state_stack.transform_3x3());
54
55 Layer::AutoPrerollSaveLayerState save =
56 Layer::AutoPrerollSaveLayerState::Create(
57 preroll_context: context, save_layer_is_active: UsesSaveLayer(enable_impeller: context->impeller_enabled));
58
59 auto mutator = context->state_stack.save();
60 ApplyClip(mutator);
61
62 SkRect child_paint_bounds = SkRect::MakeEmpty();
63 PrerollChildren(context, child_paint_bounds: &child_paint_bounds);
64 if (child_paint_bounds.intersect(clip_shape_bounds())) {
65 set_paint_bounds(child_paint_bounds);
66 } else {
67 set_paint_bounds(SkRect::MakeEmpty());
68 }
69
70 // If we use a SaveLayer then we can accept opacity on behalf
71 // of our children and apply it in the saveLayer.
72 if (uses_save_layer) {
73 context->renderable_state_flags = kSaveLayerRenderFlags;
74 }
75 }
76
77 void Paint(PaintContext& context) const override {
78 FML_DCHECK(needs_painting(context));
79
80 auto mutator = context.state_stack.save();
81 ApplyClip(mutator);
82
83 if (!UsesSaveLayer(enable_impeller: context.impeller_enabled)) {
84 PaintChildren(context);
85 return;
86 }
87
88 if (context.raster_cache) {
89 mutator.integralTransform();
90 auto restore_apply = context.state_stack.applyState(
91 bounds: paint_bounds(), can_apply_flags: LayerStateStack::kCallerCanApplyOpacity);
92
93 DlPaint paint;
94 if (layer_raster_cache_item_->Draw(context,
95 context.state_stack.fill(paint))) {
96 return;
97 }
98 }
99
100 mutator.saveLayer(bounds: paint_bounds());
101 PaintChildren(context);
102 }
103
104 bool UsesSaveLayer(bool enable_impeller) const {
105 if (enable_impeller) {
106 return false;
107 }
108 return clip_behavior_ == Clip::antiAliasWithSaveLayer;
109 }
110
111 protected:
112 virtual const SkRect& clip_shape_bounds() const = 0;
113 virtual void ApplyClip(LayerStateStack::MutatorContext& mutator) const = 0;
114 virtual ~ClipShapeLayer() = default;
115
116 const ClipShape& clip_shape() const { return clip_shape_; }
117 Clip clip_behavior() const { return clip_behavior_; }
118
119 private:
120 const ClipShape clip_shape_;
121 Clip clip_behavior_;
122
123 FML_DISALLOW_COPY_AND_ASSIGN(ClipShapeLayer);
124};
125
126} // namespace flutter
127
128#endif // FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_
129

source code of flutter_engine/flutter/flow/layers/clip_shape_layer.h