Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
dl_matrix_clip_tracker.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/display_list/utils/dl_matrix_clip_tracker.h"
6
7#include "flutter/display_list/dl_builder.h"
8#include "flutter/fml/logging.h"
9
10namespace flutter {
11
13 // clang-format off
14 return ( m.rc(0, 2) == 0 &&
15 m.rc(1, 2) == 0 &&
16 m.rc(2, 0) == 0 && m.rc(2, 1) == 0 && m.rc(2, 2) == 1 && m.rc(2, 3) == 0 &&
17 m.rc(3, 2) == 0);
18 // clang-format on
19}
20
22 const DlMatrix& matrix)
23 : cull_rect_(cull_rect), matrix_(matrix) {}
24
26 const SkMatrix& matrix)
27 : cull_rect_(ToDlRect(cull_rect)), matrix_(ToDlMatrix(matrix)) {}
28
30 const SkM44& matrix)
31 : cull_rect_(ToDlRect(cull_rect)), matrix_(ToDlMatrix(matrix)) {}
32
34 const DlRect& cull_rect,
35 const DlMatrix& matrix) {
36 // isEmpty protects us against NaN as we normalize any empty cull rects
37 DlRect cull = cull_rect.IsEmpty() ? DlRect() : cull_rect;
38 saved_.emplace_back(cull, matrix);
39 current_ = &saved_.back();
40 save(); // saved_[0] will always be the initial settings
41}
42
44 const SkRect& cull_rect,
45 const SkMatrix& matrix) {
46 // isEmpty protects us against NaN as we normalize any empty cull rects
47 SkRect cull = cull_rect.isEmpty() ? SkRect::MakeEmpty() : cull_rect;
48 saved_.emplace_back(cull, matrix);
49 current_ = &saved_.back();
50 save(); // saved_[0] will always be the initial settings
51}
52
54 const SkRect& cull_rect,
55 const SkM44& m44) {
56 // isEmpty protects us against NaN as we normalize any empty cull rects
57 SkRect cull = cull_rect.isEmpty() ? SkRect::MakeEmpty() : cull_rect;
58 saved_.emplace_back(cull, m44);
59 current_ = &saved_.back();
60 save(); // saved_[0] will always be the initial settings
61}
62
64 saved_.emplace_back(*current_);
65 current_ = &saved_.back();
66}
67
69 if (saved_.size() > 2) {
70 saved_.pop_back();
71 current_ = &saved_.back();
72 }
73}
74
76 while (saved_.size() > 1) {
77 saved_.pop_back();
78 current_ = &saved_.back();
79 }
80 save(); // saved_[0] will always be the initial settings
81}
82
84 FML_DCHECK(restore_count <= getSaveCount());
85 if (restore_count < 1) {
86 restore_count = 1;
87 }
88 while (restore_count < getSaveCount()) {
89 restore();
90 }
91}
92
94 const DisplayListMatrixClipState& tracker) {
95 if (tracker.is_matrix_invertable()) {
96 matrix_ = matrix_ * tracker.matrix_.Invert();
97 return true;
98 }
99 return false;
100}
101
103 ClipOp op,
104 bool is_aa) {
105 adjustCullRect(rect, op, is_aa);
106}
107
109 ClipOp op,
110 bool is_aa) {
111 SkRect bounds = rrect.getBounds();
112 switch (op) {
113 case ClipOp::kIntersect:
114 break;
115 case ClipOp::kDifference:
116 if (!rrect.isRect()) {
117 return;
118 }
119 break;
120 }
121 adjustCullRect(ToDlRect(bounds), op, is_aa);
122}
123
125 ClipOp op,
126 bool is_aa) {
127 // Map "kDifference of inverse path" to "kIntersect of the original path" and
128 // map "kIntersect of inverse path" to "kDifference of the original path"
129 if (path.isInverseFillType()) {
130 switch (op) {
131 case ClipOp::kIntersect:
132 op = ClipOp::kDifference;
133 break;
134 case ClipOp::kDifference:
135 op = ClipOp::kIntersect;
136 break;
137 }
138 }
139
140 SkRect bounds;
141 switch (op) {
142 case ClipOp::kIntersect:
143 bounds = path.getBounds();
144 break;
145 case ClipOp::kDifference:
146 if (!path.isRect(&bounds)) {
147 return;
148 }
149 break;
150 }
151 adjustCullRect(ToDlRect(bounds), op, is_aa);
152}
153
155 const DlRect& content_bounds) const {
156 if (cull_rect_.IsEmpty() || content_bounds.IsEmpty()) {
157 return true;
158 }
159 if (!is_matrix_invertable()) {
160 return true;
161 }
162 if (has_perspective()) {
163 return false;
164 }
165 DlRect mapped;
166 mapRect(content_bounds, &mapped);
167 return !mapped.IntersectsWithRect(cull_rect_);
168}
169
171 if (cull_rect.IsEmpty()) {
172 cull_rect_ = DlRect();
173 } else {
174 cull_rect_ = cull_rect;
175 }
176}
177
179 if (!cull_rect.IsEmpty()) {
180 mapRect(cull_rect, &cull_rect_);
181 if (!cull_rect_.IsEmpty()) {
182 return;
183 }
184 }
185 cull_rect_ = DlRect();
186}
187
188void DisplayListMatrixClipState::adjustCullRect(const DlRect& clip,
189 ClipOp op,
190 bool is_aa) {
191 if (cull_rect_.IsEmpty()) {
192 // No point in constraining further.
193 return;
194 }
195 if (matrix_.HasPerspective()) {
196 // We can conservatively ignore this clip.
197 return;
198 }
199 switch (op) {
200 case ClipOp::kIntersect: {
201 if (clip.IsEmpty()) {
202 cull_rect_ = DlRect();
203 break;
204 }
205 DlRect rect;
206 mapRect(clip, &rect);
207 if (is_aa) {
208 rect = DlRect::RoundOut(rect);
209 }
210 cull_rect_ = cull_rect_.Intersection(rect).value_or(DlRect());
211 break;
212 }
213 case ClipOp::kDifference: {
214 if (clip.IsEmpty()) {
215 break;
216 }
217 DlRect rect;
218 if (mapRect(clip, &rect)) {
219 // This technique only works if the transform is rect -> rect
220 if (is_aa) {
221 rect = DlRect::Round(rect);
222 if (rect.IsEmpty()) {
223 break;
224 }
225 }
226 cull_rect_ = cull_rect_.CutoutOrEmpty(rect);
227 }
228 break;
229 }
230 }
231}
232
234 if (cull_rect_.IsEmpty()) {
235 return SkRect::MakeEmpty();
236 }
237 if (!is_matrix_invertable()) {
238 return SkRect::MakeEmpty();
239 }
240 if (matrix_.HasPerspective2D()) {
241 // We could do a 4-point long-form conversion, but since this is
242 // only used for culling, let's just return a non-constricting
243 // cull rect.
245 }
246 DlMatrix inverse = matrix_.Invert();
247 // We eliminated perspective above so we can use the cheaper non-clipping
248 // bounds transform method.
249 return ToSkRect(cull_rect_.TransformBounds(inverse));
250}
251
252} // namespace flutter
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
Definition SkM44.h:150
bool isRect() const
Definition SkRRect.h:84
const SkRect & getBounds() const
Definition SkRRect.h:279
static constexpr SkRect kMaxCullRect
Definition dl_builder.h:32
bool inverseTransform(const DisplayListMatrixClipState &other_tracker)
void clipRRect(const SkRRect &rrect, ClipOp op, bool is_aa)
void clipRect(const DlRect &rect, ClipOp op, bool is_aa)
void clipPath(const SkPath &path, ClipOp op, bool is_aa)
void resetLocalCullRect(const DlRect &cull_rect)
bool content_culled(const DlRect &content_bounds) const
void resetDeviceCullRect(const DlRect &cull_rect)
DisplayListMatrixClipState(const DlRect &cull_rect, const DlMatrix &matrix)
DisplayListMatrixClipTracker(const DlRect &cull_rect, const DlMatrix &matrix)
#define FML_DCHECK(condition)
Definition logging.h:103
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
bool isEmpty() const
Definition SkRect.h:693
A 4x4 matrix using column-major storage.
Definition matrix.h:37
Matrix Invert() const
Definition matrix.cc:97
constexpr bool HasPerspective2D() const
Definition matrix.h:326
constexpr bool HasPerspective() const
Definition matrix.h:330
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition rect.h:440
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition rect.h:496
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition rect.h:264
constexpr bool IntersectsWithRect(const TRect &o) const
Definition rect.h:510
constexpr TRect CutoutOrEmpty(const TRect &o) const
Definition rect.h:561
Round(const TRect< U > &r)
Definition rect.h:651
RoundOut(const TRect< U > &r)
Definition rect.h:643