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
7#include <optional>
8
9namespace flutter {
10
11TransformLayer::TransformLayer(const SkM44& transform) : transform_(transform) {
12 // Checks (in some degree) that SkM44 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
28void TransformLayer::Diff(DiffContext* context, const Layer* old_layer) {
29 DiffContext::AutoSubtreeRestore subtree(context);
30 auto* prev = static_cast<const TransformLayer*>(old_layer);
31 if (!context->IsSubtreeDirty()) {
32 FML_DCHECK(prev);
33 if (transform_ != prev->transform_) {
34 context->MarkSubtreeDirty(previous_paint_region: context->GetOldLayerPaintRegion(layer: old_layer));
35 }
36 }
37 context->PushTransform(transform: transform_);
38 DiffChildren(context, old_layer: prev);
39 context->SetLayerPaintRegion(layer: this, region: context->CurrentSubtreeRegion());
40}
41
42void TransformLayer::Preroll(PrerollContext* context) {
43 auto mutator = context->state_stack.save();
44 mutator.transform(m44: transform_);
45
46 SkRect child_paint_bounds = SkRect::MakeEmpty();
47 PrerollChildren(context, child_paint_bounds: &child_paint_bounds);
48
49 // We convert to a 3x3 matrix here primarily because the SkM44 object
50 // does not support a mapRect operation.
51 // https://bugs.chromium.org/p/skia/issues/detail?id=11720&q=mapRect&can=2
52 //
53 // All geometry is X,Y only which means the 3rd row of the 4x4 matrix
54 // is ignored and the output of the 3rd column is also ignored.
55 // So we can transform the rectangle using just the 3x3 SkMatrix
56 // equivalent without any loss of information.
57 //
58 // Performance consideration:
59 // Skia has an internal mapRect for their SkM44 object that is faster
60 // than what SkMatrix does when it has perspective elements. But SkMatrix
61 // is otherwise optimal for non-perspective matrices. If SkM44 ever exposes
62 // a mapRect operation, or if SkMatrix ever optimizes its handling of
63 // the perspective elements, this issue will become moot.
64 transform_.asM33().mapRect(rect: &child_paint_bounds);
65 set_paint_bounds(child_paint_bounds);
66}
67
68void TransformLayer::Paint(PaintContext& context) const {
69 FML_DCHECK(needs_painting(context));
70
71 auto mutator = context.state_stack.save();
72 mutator.transform(m44: transform_);
73
74 PaintChildren(context);
75}
76
77} // namespace flutter
78

source code of flutter_engine/flutter/flow/layers/transform_layer.cc