Flutter Engine
The Flutter Engine
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
21static constexpr DlRect kEmpty = DlRect();
22
23static const DlRect& ProtectEmpty(const SkRect& rect) {
24 // isEmpty protects us against NaN while we normalize any empty cull rects
25 return rect.isEmpty() ? kEmpty : ToDlRect(rect);
26}
27
28static const DlRect& ProtectEmpty(const DlRect& rect) {
29 // isEmpty protects us against NaN while we normalize any empty cull rects
30 return rect.IsEmpty() ? kEmpty : rect;
31}
32
34 const DlMatrix& matrix)
35 : cull_rect_(ProtectEmpty(cull_rect)), matrix_(matrix) {}
36
38 : cull_rect_(ProtectEmpty(cull_rect)), matrix_(DlMatrix()) {}
39
41 const SkMatrix& matrix)
42 : cull_rect_(ProtectEmpty(cull_rect)), matrix_(ToDlMatrix(matrix)) {}
43
45 const SkM44& matrix)
46 : cull_rect_(ProtectEmpty(cull_rect)), matrix_(ToDlMatrix(matrix)) {}
47
49 const DisplayListMatrixClipState& tracker) {
50 if (tracker.is_matrix_invertable()) {
51 matrix_ = matrix_ * tracker.matrix_.Invert();
52 return true;
53 }
54 return false;
55}
56
58 SkRect* mapped) const {
59 DlRect dl_mapped = ToDlRect(src).TransformAndClipBounds(matrix_);
60 auto dl_intersected = dl_mapped.Intersection(cull_rect_);
61 if (dl_intersected.has_value()) {
62 *mapped = ToSkRect(dl_intersected.value());
63 return true;
64 }
65 mapped->setEmpty();
66 return false;
67}
68
70 ClipOp op,
71 bool is_aa) {
72 if (rect.IsFinite()) {
73 adjustCullRect(rect, op, is_aa);
74 }
75}
76
78 ClipOp op,
79 bool is_aa) {
81 if (rrect.isRect()) {
82 return clipRect(bounds, op, is_aa);
83 }
84 switch (op) {
86 adjustCullRect(bounds, op, is_aa);
87 break;
90 cull_rect_ = DlRect();
91 return;
92 }
93 auto upper_left = rrect.radii(SkRRect::kUpperLeft_Corner);
94 auto upper_right = rrect.radii(SkRRect::kUpperRight_Corner);
95 auto lower_left = rrect.radii(SkRRect::kLowerLeft_Corner);
96 auto lower_right = rrect.radii(SkRRect::kLowerRight_Corner);
97 DlRect safe = bounds.Expand(-std::max(upper_left.fX, lower_left.fX), 0,
98 -std::max(upper_right.fX, lower_right.fX), 0);
99 adjustCullRect(safe, op, is_aa);
100 safe = bounds.Expand(0, -std::max(upper_left.fY, upper_right.fY), //
101 0, -std::max(lower_left.fY, lower_right.fY));
102 adjustCullRect(safe, op, is_aa);
103 break;
104 }
105 }
106}
107
109 ClipOp op,
110 bool is_aa) {
111 // Map "kDifference of inverse path" to "kIntersect of the original path" and
112 // map "kIntersect of inverse path" to "kDifference of the original path"
113 if (path.isInverseFillType()) {
114 switch (op) {
117 break;
120 break;
121 }
122 }
123
124 DlRect bounds = ToDlRect(path.getBounds());
125 if (path.isRect(nullptr)) {
126 return clipRect(bounds, op, is_aa);
127 }
128 switch (op) {
130 adjustCullRect(bounds, op, is_aa);
131 break;
133 break;
134 }
135}
136
138 const DlRect& content_bounds) const {
139 if (cull_rect_.IsEmpty() || content_bounds.IsEmpty()) {
140 return true;
141 }
142 if (!is_matrix_invertable()) {
143 return true;
144 }
145 if (has_perspective()) {
146 return false;
147 }
148 DlRect mapped;
149 mapRect(content_bounds, &mapped);
150 return !mapped.IntersectsWithRect(cull_rect_);
151}
152
154 if (cull_rect.IsEmpty()) {
155 cull_rect_ = DlRect();
156 } else {
157 cull_rect_ = cull_rect;
158 }
159}
160
162 if (!cull_rect.IsEmpty()) {
163 mapRect(cull_rect, &cull_rect_);
164 if (!cull_rect_.IsEmpty()) {
165 return;
166 }
167 }
168 cull_rect_ = DlRect();
169}
170
171void DisplayListMatrixClipState::adjustCullRect(const DlRect& clip,
172 ClipOp op,
173 bool is_aa) {
174 if (cull_rect_.IsEmpty()) {
175 // No point in constraining further.
176 return;
177 }
178 if (matrix_.HasPerspective()) {
179 // We can conservatively ignore this clip.
180 return;
181 }
182 switch (op) {
183 case ClipOp::kIntersect: {
184 if (clip.IsEmpty()) {
185 cull_rect_ = DlRect();
186 break;
187 }
188 DlRect rect;
189 mapRect(clip, &rect);
190 if (is_aa) {
192 }
193 cull_rect_ = cull_rect_.Intersection(rect).value_or(DlRect());
194 break;
195 }
196 case ClipOp::kDifference: {
197 if (clip.IsEmpty()) {
198 break;
199 }
200 DlRect rect;
201 if (mapRect(clip, &rect)) {
202 // This technique only works if the transform is rect -> rect
203 if (is_aa) {
205 if (rect.IsEmpty()) {
206 break;
207 }
208 }
209 cull_rect_ = cull_rect_.CutoutOrEmpty(rect);
210 }
211 break;
212 }
213 }
214}
215
217 if (cull_rect_.IsEmpty()) {
218 return SkRect::MakeEmpty();
219 }
220 if (!is_matrix_invertable()) {
221 return SkRect::MakeEmpty();
222 }
223 if (matrix_.HasPerspective2D()) {
224 // We could do a 4-point long-form conversion, but since this is
225 // only used for culling, let's just return a non-constricting
226 // cull rect.
228 }
229 DlMatrix inverse = matrix_.Invert();
230 // We eliminated perspective above so we can use the cheaper non-clipping
231 // bounds transform method.
232 return ToSkRect(cull_rect_.TransformBounds(inverse));
233}
234
236 if (content.IsEmpty()) {
237 return false;
238 }
239 if (cull_rect_.IsEmpty()) {
240 return true;
241 }
242 if (matrix_.IsAligned2D()) {
243 // This transform-to-device calculation is faster and more accurate
244 // for rect-to-rect aligned transformations, but not accurate under
245 // (non-quadrant) rotations and skews.
246 return content.TransformAndClipBounds(matrix_).Contains(cull_rect_);
247 }
248 DlPoint corners[4];
249 if (!getLocalCullCorners(corners)) {
250 return false;
251 }
252 for (auto corner : corners) {
253 if (!content.ContainsInclusive(corner)) {
254 return false;
255 }
256 }
257 return true;
258}
259
261 if (bounds.IsEmpty()) {
262 return false;
263 }
264 if (cull_rect_.IsEmpty()) {
265 return true;
266 }
267 DlPoint corners[4];
268 if (!getLocalCullCorners(corners)) {
269 return false;
270 }
271 DlPoint center = bounds.GetCenter();
272 DlSize scale = 2.0 / bounds.GetSize();
273 for (auto corner : corners) {
274 if (!bounds.Contains(corner)) {
275 return false;
276 }
277 if (((corner - center) * scale).GetLengthSquared() >= 1.0) {
278 return false;
279 }
280 }
281 return true;
282}
283
285 const SkRRect& content) const {
286 if (content.isEmpty()) {
287 return false;
288 }
289 if (cull_rect_.IsEmpty()) {
290 return true;
291 }
292 if (content.isRect()) {
293 return rect_covers_cull(content.getBounds());
294 }
295 if (content.isOval()) {
296 return oval_covers_cull(content.getBounds());
297 }
298 if (!content.isSimple()) {
299 return false;
300 }
301 DlPoint corners[4];
302 if (!getLocalCullCorners(corners)) {
303 return false;
304 }
305 auto outer = content.getBounds();
306 DlScalar x_center = outer.centerX();
307 DlScalar y_center = outer.centerY();
308 auto radii = content.getSimpleRadii();
309 DlScalar inner_x = outer.width() * 0.5f - radii.fX;
310 DlScalar inner_y = outer.height() * 0.5f - radii.fY;
311 DlScalar scale_x = 1.0 / radii.fX;
312 DlScalar scale_y = 1.0 / radii.fY;
313 for (auto corner : corners) {
314 if (!outer.contains(corner.x, corner.y)) {
315 return false;
316 }
317 DlScalar x_rel = std::abs(corner.x - x_center) - inner_x;
318 DlScalar y_rel = std::abs(corner.y - y_center) - inner_y;
319 if (x_rel > 0.0f && y_rel > 0.0f) {
320 x_rel *= scale_x;
321 y_rel *= scale_y;
322 if (x_rel * x_rel + y_rel * y_rel >= 1.0f) {
323 return false;
324 }
325 }
326 }
327 return true;
328}
329
330bool DisplayListMatrixClipState::getLocalCullCorners(DlPoint corners[4]) const {
331 if (!is_matrix_invertable()) {
332 return false;
333 }
334 DlMatrix inverse = matrix_.Invert();
335 corners[0] = inverse * cull_rect_.GetLeftTop();
336 corners[1] = inverse * cull_rect_.GetRightTop();
337 corners[2] = inverse * cull_rect_.GetRightBottom();
338 corners[3] = inverse * cull_rect_.GetLeftBottom();
339 return true;
340}
341
342} // namespace flutter
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
Definition: SkM44.h:150
Definition: SkPath.h:59
SkVector radii(Corner corner) const
Definition: SkRRect.h:271
@ kUpperLeft_Corner
index of top-left corner radii
Definition: SkRRect.h:252
@ kLowerRight_Corner
index of bottom-right corner radii
Definition: SkRRect.h:254
@ kUpperRight_Corner
index of top-right corner radii
Definition: SkRRect.h:253
@ kLowerLeft_Corner
index of bottom-left corner radii
Definition: SkRRect.h:255
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 mapAndClipRect(SkRect *rect) const
Maps the rect by the current matrix and then clips it against the current cull rect,...
bool inverseTransform(const DisplayListMatrixClipState &other_tracker)
void scale(SkScalar sx, SkScalar sy)
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)
bool oval_covers_cull(const DlRect &content_bounds) const
static bool is_3x3(const SkM44 &m44)
DisplayListMatrixClipState(const DlRect &cull_rect, const DlMatrix &matrix=DlMatrix())
bool rect_covers_cull(const DlRect &content) const
bool rrect_covers_cull(const SkRRect &content) const
static float max(float r, float g, float b)
Definition: hsl.cpp:49
union flutter::testing::@2836::KeyboardChange::@76 content
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DlCanvas::ClipOp ClipOp
impeller::Scalar DlScalar
static constexpr DlRect kEmpty
Definition: dl_builder.cc:117
constexpr DlMatrix ToDlMatrix(const SkMatrix &matrix)
impeller::Matrix DlMatrix
impeller::Rect DlRect
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 const DlRect & ProtectEmpty(const SkRect &rect)
Definition: dl_builder.cc:119
const DlRect & ToDlRect(const SkRect &rect)
const SkRect & ToSkRect(const DlRect &rect)
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
void setEmpty()
Definition: SkRect.h:842
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 bool IsAligned2D(Scalar tolerance=0) const
Definition: matrix.h:336
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:463
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:519
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:287
constexpr bool IntersectsWithRect(const TRect &o) const
Definition: rect.h:533
constexpr TRect CutoutOrEmpty(const TRect &o) const
Definition: rect.h:584
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:349
Round(const TRect< U > &r)
Definition: rect.h:674
RoundOut(const TRect< U > &r)
Definition: rect.h:666
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition: rect.h:429
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:361
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:357
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:353