Flutter Engine
physical_shape_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/physical_shape_layer.h"
6 
7 #include "flutter/flow/paint_utils.h"
8 #include "third_party/skia/include/utils/SkShadowUtils.h"
9 
10 namespace flutter {
11 
12 const SkScalar kLightHeight = 600;
13 const SkScalar kLightRadius = 800;
14 
16  SkColor shadow_color,
17  float elevation,
18  const SkPath& path,
19  Clip clip_behavior)
20  : color_(color),
21  shadow_color_(shadow_color),
22  elevation_(elevation),
23  path_(path),
24  clip_behavior_(clip_behavior) {}
25 
26 #ifdef FLUTTER_ENABLE_DIFF_CONTEXT
27 
28 void PhysicalShapeLayer::Diff(DiffContext* context, const Layer* old_layer) {
29  DiffContext::AutoSubtreeRestore subtree(context);
30  auto* prev = static_cast<const PhysicalShapeLayer*>(old_layer);
31  if (!context->IsSubtreeDirty()) {
32  FML_DCHECK(prev);
33  if (color_ != prev->color_ || shadow_color_ != prev->shadow_color_ ||
34  elevation_ != prev->elevation() || path_ != prev->path_ ||
35  clip_behavior_ != prev->clip_behavior_) {
36  context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
37  }
38  }
39 
40  SkRect bounds;
41  if (elevation_ == 0) {
42  bounds = path_.getBounds();
43  } else {
44  bounds = ComputeShadowBounds(path_, elevation_,
45  context->frame_device_pixel_ratio(),
46  context->GetTransform());
47  }
48 
49  context->AddLayerBounds(bounds);
50 
51  if (context->PushCullRect(bounds)) {
52  DiffChildren(context, prev);
53  }
54  context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
55 }
56 
57 #endif // FLUTTER_ENABLE_DIFF_CONTEXT
58 
60  const SkMatrix& matrix) {
61  TRACE_EVENT0("flutter", "PhysicalShapeLayer::Preroll");
64 
65  SkRect child_paint_bounds;
66  PrerollChildren(context, matrix, &child_paint_bounds);
67 
68  if (elevation_ == 0) {
69  set_paint_bounds(path_.getBounds());
70  } else {
71  // We will draw the shadow in Paint(), so add some margin to the paint
72  // bounds to leave space for the shadow. We fill this whole region and clip
73  // children to it so we don't need to join the child paint bounds.
75  path_, elevation_, context->frame_device_pixel_ratio, matrix));
76  }
77 }
78 
80  TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
81  FML_DCHECK(needs_painting(context));
82 
83  if (elevation_ != 0) {
84  DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
85  SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio);
86  }
87 
88  // Call drawPath without clip if possible for better performance.
89  SkPaint paint;
90  paint.setColor(color_);
91  paint.setAntiAlias(true);
92  if (clip_behavior_ != Clip::antiAliasWithSaveLayer) {
93  context.leaf_nodes_canvas->drawPath(path_, paint);
94  }
95 
96  int saveCount = context.internal_nodes_canvas->save();
97  switch (clip_behavior_) {
98  case Clip::hardEdge:
99  context.internal_nodes_canvas->clipPath(path_, false);
100  break;
101  case Clip::antiAlias:
102  context.internal_nodes_canvas->clipPath(path_, true);
103  break;
105  context.internal_nodes_canvas->clipPath(path_, true);
106  context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
107  break;
108  case Clip::none:
109  break;
110  }
111 
112  if (UsesSaveLayer()) {
113  // If we want to avoid the bleeding edge artifact
114  // (https://github.com/flutter/flutter/issues/18057#issue-328003931)
115  // using saveLayer, we have to call drawPaint instead of drawPath as
116  // anti-aliased drawPath will always have such artifacts.
117  context.leaf_nodes_canvas->drawPaint(paint);
118  }
119 
120  PaintChildren(context);
121 
122  context.internal_nodes_canvas->restoreToCount(saveCount);
123 
124  if (UsesSaveLayer()) {
125  if (context.checkerboard_offscreen_layers) {
127  }
128  }
129 }
130 
132  float elevation,
133  SkScalar dpr,
134  const SkMatrix& ctm) {
135  SkRect shadow_bounds(path.getBounds());
136  SkShadowUtils::GetLocalBounds(
137  ctm, path, SkPoint3::Make(0, 0, dpr * elevation),
138  SkPoint3::Make(0, -1, 1), kLightRadius / kLightHeight,
139  SkShadowFlags::kDirectionalLight_ShadowFlag, &shadow_bounds);
140  return shadow_bounds;
141 }
142 
143 void PhysicalShapeLayer::DrawShadow(SkCanvas* canvas,
144  const SkPath& path,
145  SkColor color,
146  float elevation,
147  bool transparentOccluder,
148  SkScalar dpr) {
149  const SkScalar kAmbientAlpha = 0.039f;
150  const SkScalar kSpotAlpha = 0.25f;
151 
152  uint32_t flags = transparentOccluder
153  ? SkShadowFlags::kTransparentOccluder_ShadowFlag
154  : SkShadowFlags::kNone_ShadowFlag;
155  flags |= SkShadowFlags::kDirectionalLight_ShadowFlag;
156  SkColor inAmbient = SkColorSetA(color, kAmbientAlpha * SkColorGetA(color));
157  SkColor inSpot = SkColorSetA(color, kSpotAlpha * SkColorGetA(color));
158  SkColor ambientColor, spotColor;
159  SkShadowUtils::ComputeTonalColors(inAmbient, inSpot, &ambientColor,
160  &spotColor);
161  SkShadowUtils::DrawShadow(canvas, path, SkPoint3::Make(0, 0, dpr * elevation),
162  SkPoint3::Make(0, -1, 1),
163  kLightRadius / kLightHeight, ambientColor,
164  spotColor, flags);
165 }
166 
167 } // namespace flutter
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
const bool checkerboard_offscreen_layers
Definition: layer.h:152
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
#define FML_DCHECK(condition)
Definition: logging.h:86
const SkScalar kLightHeight
void PrerollChildren(PrerollContext *context, const SkMatrix &child_matrix, SkRect *child_paint_bounds)
static SkRect ComputeShadowBounds(const SkPath &path, float elevation, SkScalar dpr, const SkMatrix &ctm)
bool needs_painting(PaintContext &context) const
Definition: layer.h:249
void Preroll(PrerollContext *context, const SkMatrix &matrix) override
const float frame_device_pixel_ratio
Definition: layer.h:153
void Paint(PaintContext &context) const override
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
const float frame_device_pixel_ratio
Definition: layer.h:56
SkCanvas * leaf_nodes_canvas
Definition: layer.h:145
void set_paint_bounds(const SkRect &paint_bounds)
Definition: layer.h:240
const SkScalar kLightRadius
static void DrawShadow(SkCanvas *canvas, const SkPath &path, SkColor color, float elevation, bool transparentOccluder, SkScalar dpr)
Clip
Definition: layer.h:40
SkCanvas * internal_nodes_canvas
Definition: layer.h:144
PhysicalShapeLayer(SkColor color, SkColor shadow_color, float elevation, const SkPath &path, Clip clip_behavior)
void DrawCheckerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)
Definition: paint_utils.cc:29
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66
void PaintChildren(PaintContext &context) const