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/opacity_layer.h" |
6 | |
7 | #include "flutter/fml/trace_event.h" |
8 | #include "third_party/skia/include/core/SkPaint.h" |
9 | |
10 | namespace flutter { |
11 | |
12 | OpacityLayer::OpacityLayer(SkAlpha alpha, const SkPoint& offset) |
13 | : alpha_(alpha), offset_(offset) {} |
14 | |
15 | void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { |
16 | TRACE_EVENT0("flutter" , "OpacityLayer::Preroll" ); |
17 | |
18 | ContainerLayer* container = GetChildContainer(); |
19 | FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf. |
20 | |
21 | const bool parent_is_opaque = context->is_opaque; |
22 | SkMatrix child_matrix = matrix; |
23 | child_matrix.postTranslate(offset_.fX, offset_.fY); |
24 | |
25 | // Similar to what's done in TransformLayer::Preroll, we have to apply the |
26 | // reverse transformation to the cull rect to properly cull child layers. |
27 | context->cull_rect = context->cull_rect.makeOffset(-offset_.fX, -offset_.fY); |
28 | |
29 | context->is_opaque = parent_is_opaque && (alpha_ == SK_AlphaOPAQUE); |
30 | context->mutators_stack.PushTransform( |
31 | SkMatrix::Translate(offset_.fX, offset_.fY)); |
32 | context->mutators_stack.PushOpacity(alpha_); |
33 | Layer::AutoPrerollSaveLayerState save = |
34 | Layer::AutoPrerollSaveLayerState::Create(context); |
35 | ContainerLayer::Preroll(context, child_matrix); |
36 | context->mutators_stack.Pop(); |
37 | context->mutators_stack.Pop(); |
38 | context->is_opaque = parent_is_opaque; |
39 | |
40 | { |
41 | set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY)); |
42 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
43 | child_matrix = RasterCache::GetIntegralTransCTM(child_matrix); |
44 | #endif |
45 | TryToPrepareRasterCache(context, GetCacheableChild(), child_matrix); |
46 | } |
47 | |
48 | // Restore cull_rect |
49 | context->cull_rect = context->cull_rect.makeOffset(offset_.fX, offset_.fY); |
50 | } |
51 | |
52 | void OpacityLayer::Paint(PaintContext& context) const { |
53 | TRACE_EVENT0("flutter" , "OpacityLayer::Paint" ); |
54 | FML_DCHECK(needs_painting()); |
55 | |
56 | SkPaint paint; |
57 | paint.setAlpha(alpha_); |
58 | |
59 | SkAutoCanvasRestore save(context.internal_nodes_canvas, true); |
60 | context.internal_nodes_canvas->translate(offset_.fX, offset_.fY); |
61 | |
62 | #ifndef SUPPORT_FRACTIONAL_TRANSLATION |
63 | context.internal_nodes_canvas->setMatrix(RasterCache::GetIntegralTransCTM( |
64 | context.leaf_nodes_canvas->getTotalMatrix())); |
65 | #endif |
66 | |
67 | if (context.raster_cache && |
68 | context.raster_cache->Draw(GetCacheableChild(), |
69 | *context.leaf_nodes_canvas, &paint)) { |
70 | return; |
71 | } |
72 | |
73 | // Skia may clip the content with saveLayerBounds (although it's not a |
74 | // guaranteed clip). So we have to provide a big enough saveLayerBounds. To do |
75 | // so, we first remove the offset from paint bounds since it's already in the |
76 | // matrix. Then we round out the bounds. |
77 | // |
78 | // Note that the following lines are only accessible when the raster cache is |
79 | // not available (e.g., when we're using the software backend in golden |
80 | // tests). |
81 | SkRect saveLayerBounds; |
82 | paint_bounds() |
83 | .makeOffset(-offset_.fX, -offset_.fY) |
84 | .roundOut(&saveLayerBounds); |
85 | |
86 | Layer::AutoSaveLayer save_layer = |
87 | Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint); |
88 | PaintChildren(context); |
89 | } |
90 | |
91 | #if defined(LEGACY_FUCHSIA_EMBEDDER) |
92 | |
93 | void OpacityLayer::UpdateScene(SceneUpdateContext& context) { |
94 | float saved_alpha = context.alphaf(); |
95 | context.set_alphaf(context.alphaf() * (alpha_ / 255.f)); |
96 | ContainerLayer::UpdateScene(context); |
97 | context.set_alphaf(saved_alpha); |
98 | } |
99 | |
100 | #endif |
101 | |
102 | } // namespace flutter |
103 | |