Flutter Engine
image_filter_layer.cc
Go to the documentation of this file.
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 #include "flutter/flow/layers/image_filter_layer.h"
6 
7 namespace flutter {
8 
9 ImageFilterLayer::ImageFilterLayer(sk_sp<SkImageFilter> filter)
10  : filter_(std::move(filter)),
11  transformed_filter_(nullptr),
12  render_count_(1) {}
13 
14 #ifdef FLUTTER_ENABLE_DIFF_CONTEXT
15 
16 void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
17  DiffContext::AutoSubtreeRestore subtree(context);
18  auto* prev = static_cast<const ImageFilterLayer*>(old_layer);
19  if (!context->IsSubtreeDirty()) {
20  FML_DCHECK(prev);
21  if (filter_ != prev->filter_) {
22  context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
23  }
24  }
25 
26  if (filter_) {
27  auto filter = filter_->makeWithLocalMatrix(context->GetTransform());
28  if (filter) {
29  // This transform will be applied to every child rect in the subtree
30  context->PushFilterBoundsAdjustment([filter](SkRect rect) {
31  return SkRect::Make(
32  filter->filterBounds(rect.roundOut(), SkMatrix::I(),
33  SkImageFilter::kForward_MapDirection));
34  });
35  }
36  }
37  DiffChildren(context, prev);
38  context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
39 }
40 
41 #endif // FLUTTER_ENABLE_DIFF_CONTEXT
42 
44  const SkMatrix& matrix) {
45  TRACE_EVENT0("flutter", "ImageFilterLayer::Preroll");
48 
49  SkRect child_bounds = SkRect::MakeEmpty();
50  PrerollChildren(context, matrix, &child_bounds);
51 
52  if (!filter_) {
53  set_paint_bounds(child_bounds);
54  return;
55  }
56 
57  const SkIRect filter_input_bounds = child_bounds.roundOut();
58  SkIRect filter_output_bounds = filter_->filterBounds(
59  filter_input_bounds, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
60  child_bounds = SkRect::Make(filter_output_bounds);
61 
62  set_paint_bounds(child_bounds);
63 
64  transformed_filter_ = nullptr;
65  if (render_count_ >= kMinimumRendersBeforeCachingFilterLayer) {
66  // We have rendered this same ImageFilterLayer object enough
67  // times to consider its properties and children to be stable
68  // from frame to frame so we try to cache the layer itself
69  // for maximum performance.
70  TryToPrepareRasterCache(context, this, matrix);
71  } else {
72  // This ImageFilterLayer is not yet considered stable so we
73  // increment the count to measure how many times it has been
74  // seen from frame to frame.
75  render_count_++;
76 
77  // Now we will try to pre-render the children into the cache.
78  // To apply the filter to pre-rendered children, we must first
79  // modify the filter to be aware of the transform under which
80  // the cached bitmap was produced. Some SkImageFilter
81  // instances can do this operation on some transforms and some
82  // (filters or transforms) cannot. We can only cache the children
83  // and apply the filter on the fly if this operation succeeds.
84  transformed_filter_ = filter_->makeWithLocalMatrix(matrix);
85  if (transformed_filter_) {
86  // With a modified SkImageFilter we can now try to cache the
87  // children to avoid their rendering costs if they remain
88  // stable between frames and also avoiding a rendering surface
89  // switch during the Paint phase even if they are not stable.
90  // This benefit is seen most during animations.
91  TryToPrepareRasterCache(context, GetCacheableChild(), matrix);
92  }
93  }
94 }
95 
96 void ImageFilterLayer::Paint(PaintContext& context) const {
97  TRACE_EVENT0("flutter", "ImageFilterLayer::Paint");
98  FML_DCHECK(needs_painting(context));
99 
100  if (context.raster_cache) {
101  if (context.raster_cache->Draw(this, *context.leaf_nodes_canvas)) {
102  return;
103  }
104  if (transformed_filter_) {
105  SkPaint paint;
106  paint.setImageFilter(transformed_filter_);
107 
108  if (context.raster_cache->Draw(GetCacheableChild(),
109  *context.leaf_nodes_canvas, &paint)) {
110  return;
111  }
112  }
113  }
114 
115  SkPaint paint;
116  paint.setImageFilter(filter_);
117 
118  // Normally a save_layer is sized to the current layer bounds, but in this
119  // case the bounds of the child may not be the same as the filtered version
120  // so we use the bounds of the child container which do not include any
121  // modifications that the filter might apply.
123  context, GetChildContainer()->paint_bounds(), &paint);
124  PaintChildren(context);
125 }
126 
127 } // namespace flutter
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
#define FML_DCHECK(condition)
Definition: logging.h:86
ImageFilterLayer(sk_sp< SkImageFilter > filter)
Definition: ref_ptr.h:252
void PrerollChildren(PrerollContext *context, const SkMatrix &child_matrix, SkRect *child_paint_bounds)
bool needs_painting(PaintContext &context) const
Definition: layer.h:249
Layer * GetCacheableChild() const
Returns the best choice for a Layer object that can be used in RasterCache operations to cache the ch...
const RasterCache * raster_cache
Definition: layer.h:151
ContainerLayer * GetChildContainer() const
Returns the ContainerLayer used to hold all of the children of the MergedContainerLayer. Note that this may not be the best layer to use for caching the children.
bool Draw(const SkPicture &picture, SkCanvas &canvas) const
static AutoPrerollSaveLayerState Create(PrerollContext *preroll_context, bool save_layer_is_active=true, bool layer_itself_performs_readback=false)
Definition: layer.cc:44
const SkRect & paint_bounds() const
Definition: layer.h:227
SkCanvas * leaf_nodes_canvas
Definition: layer.h:145
void set_paint_bounds(const SkRect &paint_bounds)
Definition: layer.h:240
void Preroll(PrerollContext *context, const SkMatrix &matrix) override
void Paint(PaintContext &context) const override
static void TryToPrepareRasterCache(PrerollContext *context, Layer *layer, const SkMatrix &matrix)
void PaintChildren(PaintContext &context) const
static AutoSaveLayer Create(const PaintContext &paint_context, const SkRect &bounds, const SkPaint *paint, SaveMode save_mode=SaveMode::kInternalNodesCanvas)
Definition: layer.cc:82