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/transform_layer.h"
6 #include "include/core/SkMatrix.h"
7
8 namespace flutter {
9
TransformLayer(const SkMatrix & transform)10 TransformLayer::TransformLayer(const SkMatrix& transform)
11 : transform_(transform) {
12 // Checks (in some degree) that SkMatrix transform_ is valid and initialized.
13 //
14 // If transform_ is uninitialized, this assert may look flaky as it doesn't
15 // fail all the time, and some rerun may make it pass. But don't ignore it and
16 // just rerun the test if this is triggered, since even a flaky failure here
17 // may signify a potentially big problem in the code.
18 //
19 // We have to write this flaky test because there is no reliable way to test
20 // whether a variable is initialized or not in C++.
21 FML_DCHECK(transform_.isFinite());
22 if (!transform_.isFinite()) {
23 FML_LOG(ERROR) << "TransformLayer is constructed with an invalid matrix.";
24 transform_.setIdentity();
25 }
26 }
27
28 TransformLayer::~TransformLayer() = default;
29
Preroll(PrerollContext * context,const SkMatrix & matrix)30 void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
31 SkMatrix child_matrix;
32 child_matrix.setConcat(matrix, transform_);
33 context->mutators_stack.PushTransform(transform_);
34 SkRect previous_cull_rect = context->cull_rect;
35 SkMatrix inverse_transform_;
36 // Perspective projections don't produce rectangles that are useful for
37 // culling for some reason.
38 if (!transform_.hasPerspective() && transform_.invert(&inverse_transform_)) {
39 inverse_transform_.mapRect(&context->cull_rect);
40 } else {
41 context->cull_rect = kGiantRect;
42 }
43
44 SkRect child_paint_bounds = SkRect::MakeEmpty();
45 PrerollChildren(context, child_matrix, &child_paint_bounds);
46
47 transform_.mapRect(&child_paint_bounds);
48 set_paint_bounds(child_paint_bounds);
49
50 context->cull_rect = previous_cull_rect;
51 context->mutators_stack.Pop();
52 }
53
54 #if defined(OS_FUCHSIA)
55
UpdateScene(SceneUpdateContext & context)56 void TransformLayer::UpdateScene(SceneUpdateContext& context) {
57 FML_DCHECK(needs_system_composite());
58
59 SceneUpdateContext::Transform transform(context, transform_);
60 UpdateSceneChildren(context);
61 }
62
63 #endif // defined(OS_FUCHSIA)
64
Paint(PaintContext & context) const65 void TransformLayer::Paint(PaintContext& context) const {
66 TRACE_EVENT0("flutter", "TransformLayer::Paint");
67 FML_DCHECK(needs_painting());
68
69 SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
70 context.internal_nodes_canvas->concat(transform_);
71
72 PaintChildren(context);
73 }
74
MapRect(const SkRect & rect)75 SkRect TransformLayer::MapRect(const SkRect& rect) {
76 SkRect dst_rect;
77 if (transform_.mapRect(&dst_rect, rect)) {
78 return dst_rect;
79 }
80 return rect;
81 }
82
MergeParentHole()83 void TransformLayer::MergeParentHole() {
84 auto* parent_layer = parent();
85 if (!parent_layer) {
86 return;
87 }
88 SkMatrix inverse_mat = transform_;
89 if (!inverse_mat.invert(&inverse_mat)) {
90 return;
91 }
92 for (const auto& [id, rect] : parent_layer->HoleRegions()) {
93 SkRect dst_rect;
94 if (inverse_mat.mapRect(&dst_rect, rect)) {
95 hole_regions_.try_emplace(id, dst_rect);
96 }
97 }
98 }
99
100 } // namespace flutter
101