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
6
10
11namespace flutter {
12
13static constexpr DlRect kEmpty = DlRect();
14
15static const DlRect& ProtectEmpty(const DlRect& rect) {
16 // isEmpty protects us against NaN while we normalize any empty cull rects
17 return rect.IsEmpty() ? kEmpty : rect;
18}
19
21 const DlMatrix& matrix)
22 : cull_rect_(ProtectEmpty(cull_rect)), matrix_(matrix) {}
23
25 const DisplayListMatrixClipState& tracker) {
26 if (tracker.is_matrix_invertable()) {
27 matrix_ = matrix_ * tracker.matrix_.Invert();
28 return true;
29 }
30 return false;
31}
32
34 DlRect* mapped) const {
35 DlRect dl_mapped = src.TransformAndClipBounds(matrix_);
36 auto dl_intersected = dl_mapped.Intersection(cull_rect_);
37 if (dl_intersected.has_value()) {
38 *mapped = dl_intersected.value();
39 return true;
40 }
41 *mapped = DlRect();
42 return false;
43}
44
46 DlClipOp op,
47 bool is_aa) {
48 if (rect.IsFinite()) {
49 adjustCullRect(rect, op, is_aa);
50 }
51}
52
54 DlClipOp op,
55 bool is_aa) {
56 if (!bounds.IsFinite()) {
57 return;
58 }
59 switch (op) {
61 adjustCullRect(bounds, op, is_aa);
62 break;
64 if (oval_covers_cull(bounds)) {
65 cull_rect_ = DlRect();
66 }
67 break;
68 }
69}
70
71namespace {
72inline std::array<DlRect, 2> RoundingRadiiSafeRects(
73 const DlRect& bounds,
74 const impeller::RoundingRadii& radii) {
75 return {
76 bounds.Expand( //
77 -std::max(radii.top_left.width, radii.bottom_left.width), 0,
78 -std::max(radii.top_right.width, radii.bottom_right.width), 0),
79 bounds.Expand(
80 0, -std::max(radii.top_left.height, radii.top_right.height), //
81 0, -std::max(radii.bottom_left.height, radii.bottom_right.height))};
82}
83} // namespace
84
86 DlClipOp op,
87 bool is_aa) {
88 DlRect bounds = rrect.GetBounds();
89 if (rrect.IsRect()) {
90 return clipRect(bounds, op, is_aa);
91 }
92 if (rrect.IsOval()) {
93 return clipOval(bounds, op, is_aa);
94 }
95 switch (op) {
97 adjustCullRect(bounds, op, is_aa);
98 break;
100 if (rrect_covers_cull(rrect)) {
101 cull_rect_ = DlRect();
102 return;
103 }
104 auto safe_rects = RoundingRadiiSafeRects(bounds, rrect.GetRadii());
105 adjustCullRect(safe_rects[0], op, is_aa);
106 adjustCullRect(safe_rects[1], op, is_aa);
107 break;
108 }
109 }
110}
111
113 const DlRoundSuperellipse& rse,
114 DlClipOp op,
115 bool is_aa) {
116 DlRect bounds = rse.GetBounds();
117 if (rse.IsRect()) {
118 return clipRect(bounds, op, is_aa);
119 }
120 if (rse.IsOval()) {
121 return clipOval(bounds, op, is_aa);
122 }
123 switch (op) {
125 adjustCullRect(bounds, op, is_aa);
126 break;
128 if (rsuperellipse_covers_cull(rse)) {
129 cull_rect_ = DlRect();
130 return;
131 }
132 auto safe_rects = RoundingRadiiSafeRects(bounds, rse.GetRadii());
133 adjustCullRect(safe_rects[0], op, is_aa);
134 adjustCullRect(safe_rects[1], op, is_aa);
135 break;
136 }
137 }
138}
139
141 DlClipOp op,
142 bool is_aa) {
143 DlRect bounds = path.GetBounds();
144 if (path.IsRect(nullptr)) {
145 return clipRect(bounds, op, is_aa);
146 }
147 switch (op) {
149 adjustCullRect(bounds, op, is_aa);
150 break;
152 break;
153 }
154}
155
157 const DlRect& content_bounds) const {
158 if (cull_rect_.IsEmpty() || content_bounds.IsEmpty()) {
159 return true;
160 }
161 if (!is_matrix_invertable()) {
162 return true;
163 }
164 if (has_perspective()) {
165 return false;
166 }
167 DlRect mapped;
168 mapRect(content_bounds, &mapped);
169 return !mapped.IntersectsWithRect(cull_rect_);
170}
171
173 if (cull_rect.IsEmpty()) {
174 cull_rect_ = DlRect();
175 } else {
176 cull_rect_ = cull_rect;
177 }
178}
179
181 if (!cull_rect.IsEmpty()) {
182 mapRect(cull_rect, &cull_rect_);
183 if (!cull_rect_.IsEmpty()) {
184 return;
185 }
186 }
187 cull_rect_ = DlRect();
188}
189
190void DisplayListMatrixClipState::adjustCullRect(const DlRect& clip,
191 DlClipOp op,
192 bool is_aa) {
193 if (cull_rect_.IsEmpty()) {
194 // No point in constraining further.
195 return;
196 }
197 if (matrix_.HasPerspective()) {
198 // We can conservatively ignore this clip.
199 return;
200 }
201 switch (op) {
203 if (clip.IsEmpty()) {
204 cull_rect_ = DlRect();
205 break;
206 }
207 DlRect rect;
208 mapRect(clip, &rect);
209 if (is_aa) {
210 rect = DlRect::RoundOut(rect);
211 }
212 cull_rect_ = cull_rect_.Intersection(rect).value_or(DlRect());
213 break;
214 }
216 if (clip.IsEmpty()) {
217 break;
218 }
219 DlRect rect;
220 if (mapRect(clip, &rect)) {
221 // This technique only works if the transform is rect -> rect
222 if (is_aa) {
223 rect = DlRect::Round(rect);
224 if (rect.IsEmpty()) {
225 break;
226 }
227 }
228 cull_rect_ = cull_rect_.CutoutOrEmpty(rect);
229 }
230 break;
231 }
232 }
233}
234
236 if (cull_rect_.IsEmpty()) {
237 return DlRect();
238 }
239 if (!is_matrix_invertable()) {
240 return DlRect();
241 }
242 if (matrix_.HasPerspective2D()) {
243 // We could do a 4-point long-form conversion, but since this is
244 // only used for culling, let's just return a non-constricting
245 // cull rect.
247 }
248 DlMatrix inverse = matrix_.Invert();
249 // We eliminated perspective above so we can use the cheaper non-clipping
250 // bounds transform method.
251 return cull_rect_.TransformBounds(inverse);
252}
253
255 return TransformedRectCoversBounds(content, matrix_, cull_rect_);
256}
257
259 const DlRect& local_rect,
260 const DlMatrix& matrix,
261 const DlRect& cull_bounds) {
262 if (local_rect.IsEmpty()) {
263 return false;
264 }
265 if (cull_bounds.IsEmpty()) {
266 return true;
267 }
268 if (matrix.IsAligned2D()) {
269 // This transform-to-device calculation is faster and more accurate
270 // for rect-to-rect aligned transformations, but not accurate under
271 // (non-quadrant) rotations and skews.
272 return local_rect.TransformAndClipBounds(matrix).Contains(cull_bounds);
273 }
274 DlPoint corners[4];
275 if (!GetLocalCorners(corners, cull_bounds, matrix)) {
276 return false;
277 }
278 for (auto corner : corners) {
279 if (!local_rect.ContainsInclusive(corner)) {
280 return false;
281 }
282 }
283 return true;
284}
285
287 return TransformedOvalCoversBounds(bounds, matrix_, cull_rect_);
288}
289
291 const DlRect& local_oval_bounds,
292 const DlMatrix& matrix,
293 const DlRect& cull_bounds) {
294 if (local_oval_bounds.IsEmpty()) {
295 return false;
296 }
297 if (cull_bounds.IsEmpty()) {
298 return true;
299 }
300 DlPoint corners[4];
301 if (!GetLocalCorners(corners, cull_bounds, matrix)) {
302 return false;
303 }
304 DlPoint center = local_oval_bounds.GetCenter();
305 DlSize scale = 2.0 / local_oval_bounds.GetSize();
306 for (auto corner : corners) {
307 if (!local_oval_bounds.Contains(corner)) {
308 return false;
309 }
310 if (((corner - center) * scale).GetLengthSquared() >= 1.0) {
311 return false;
312 }
313 }
314 return true;
315}
316
318 const DlRoundRect& content) const {
319 return TransformedRRectCoversBounds(content, matrix_, cull_rect_);
320}
321
323 const DlRoundRect& local_rrect,
324 const DlMatrix& matrix,
325 const DlRect& cull_bounds) {
326 if (local_rrect.IsEmpty()) {
327 return false;
328 }
329 if (cull_bounds.IsEmpty()) {
330 return true;
331 }
332 if (local_rrect.IsRect()) {
333 return TransformedRectCoversBounds(local_rrect.GetBounds(), matrix,
334 cull_bounds);
335 }
336 if (local_rrect.IsOval()) {
337 return TransformedOvalCoversBounds(local_rrect.GetBounds(), matrix,
338 cull_bounds);
339 }
340 if (!local_rrect.GetRadii().AreAllCornersSame()) {
341 return false;
342 }
343 DlPoint corners[4];
344 if (!GetLocalCorners(corners, cull_bounds, matrix)) {
345 return false;
346 }
347 auto outer = local_rrect.GetBounds();
348 auto center = outer.GetCenter();
349 auto radii = local_rrect.GetRadii().top_left;
350 auto inner = outer.GetSize() * 0.5 - radii;
351 auto scale = 1.0 / radii;
352 for (auto corner : corners) {
353 if (!outer.Contains(corner)) {
354 return false;
355 }
356 auto rel = (corner - center).Abs() - inner;
357 if (rel.x > 0.0f && rel.y > 0.0f &&
358 (rel * scale).GetLengthSquared() >= 1.0f) {
359 return false;
360 }
361 }
362 return true;
363}
364
369
371 const DlRoundSuperellipse& local_rse,
372 const DlMatrix& matrix,
373 const DlRect& cull_bounds) {
374 if (local_rse.IsEmpty()) {
375 return false;
376 }
377 if (cull_bounds.IsEmpty()) {
378 return true;
379 }
380 if (local_rse.IsRect()) {
381 return TransformedRectCoversBounds(local_rse.GetBounds(), matrix,
382 cull_bounds);
383 }
384 if (local_rse.IsOval()) {
385 return TransformedOvalCoversBounds(local_rse.GetBounds(), matrix,
386 cull_bounds);
387 }
388 DlPoint corners[4];
389 if (!GetLocalCorners(corners, cull_bounds, matrix)) {
390 return false;
391 }
392 auto outer = local_rse.GetBounds();
394 outer, local_rse.GetRadii());
395 for (auto corner : corners) {
396 if (!outer.Contains(corner)) {
397 return false;
398 }
399 if (!param.Contains(corner)) {
400 return false;
401 }
402 }
403 return true;
404}
405
406bool DisplayListMatrixClipState::GetLocalCorners(DlPoint corners[4],
407 const DlRect& rect,
408 const DlMatrix& matrix) {
409 if (!matrix.IsInvertible()) {
410 return false;
411 }
412 DlMatrix inverse = matrix.Invert();
413 corners[0] = inverse * rect.GetLeftTop();
414 corners[1] = inverse * rect.GetRightTop();
415 corners[2] = inverse * rect.GetRightBottom();
416 corners[3] = inverse * rect.GetLeftBottom();
417 return true;
418}
419
420} // namespace flutter
static constexpr DlRect kMaxCullRect
Definition dl_builder.h:32
static bool TransformedRectCoversBounds(const DlRect &local_rect, const DlMatrix &matrix, const DlRect &cull_bounds)
Checks if the local rect, when transformed by the matrix, completely covers the indicated culling bou...
bool inverseTransform(const DisplayListMatrixClipState &other_tracker)
void scale(DlScalar sx, DlScalar sy)
static bool TransformedRoundSuperellipseCoversBounds(const DlRoundSuperellipse &local_rse, const DlMatrix &matrix, const DlRect &cull_bounds)
Checks if the local round superellipse, when transformed by the matrix, completely covers the indicat...
bool rsuperellipse_covers_cull(const DlRoundSuperellipse &content) const
void clipRect(const DlRect &rect, DlClipOp op, bool is_aa)
bool rrect_covers_cull(const DlRoundRect &content) const
void clipRRect(const DlRoundRect &rrect, DlClipOp op, bool is_aa)
void clipRSuperellipse(const DlRoundSuperellipse &rse, DlClipOp op, bool is_aa)
void resetLocalCullRect(const DlRect &cull_rect)
static bool TransformedRRectCoversBounds(const DlRoundRect &local_rrect, const DlMatrix &matrix, const DlRect &cull_bounds)
Checks if the local round rect, when transformed by the matrix, completely covers the indicated culli...
bool content_culled(const DlRect &content_bounds) const
void clipPath(const DlPath &path, DlClipOp op, bool is_aa)
void resetDeviceCullRect(const DlRect &cull_rect)
bool mapAndClipRect(DlRect *rect) const
Maps the rect by the current matrix and then clips it against the current cull rect,...
bool oval_covers_cull(const DlRect &content_bounds) const
DisplayListMatrixClipState(const DlRect &cull_rect, const DlMatrix &matrix=DlMatrix())
bool rect_covers_cull(const DlRect &content) const
void clipOval(const DlRect &bounds, DlClipOp op, bool is_aa)
static bool TransformedOvalCoversBounds(const DlRect &local_oval_bounds, const DlMatrix &matrix, const DlRect &cull_bounds)
Checks if an oval defined by the local bounds, when transformed by the matrix, completely covers the ...
double height() const
Definition geometry.h:45
double width() const
Definition geometry.h:44
union flutter::testing::@2824::KeyboardChange::@78 content
static constexpr DlRect kEmpty
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 switch_defs.h:52
static const DlRect & ProtectEmpty(const DlRect &rect)
A 4x4 matrix using column-major storage.
Definition matrix.h:37
bool IsInvertible() const
Definition matrix.h:321
Matrix Invert() const
Definition matrix.cc:99
constexpr bool HasPerspective2D() const
Definition matrix.h:414
constexpr bool HasPerspective() const
Definition matrix.h:418
constexpr bool IsAligned2D(Scalar tolerance=0) const
Definition matrix.h:424
constexpr bool IsEmpty() const
Definition round_rect.h:65
constexpr bool IsRect() const
Definition round_rect.h:67
constexpr const RoundingRadii & GetRadii() const
Definition round_rect.h:55
constexpr const Rect & GetBounds() const
Definition round_rect.h:53
constexpr bool IsOval() const
Definition round_rect.h:71
constexpr const Rect & GetBounds() const
constexpr bool IsOval() const
constexpr bool IsEmpty() const
constexpr bool IsRect() const
constexpr const RoundingRadii & GetRadii() const
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
constexpr bool AreAllCornersSame(Scalar tolerance=kEhCloseEnough) const
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition rect.h:472
constexpr bool ContainsInclusive(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the closed-range interior of this rectangle.
Definition rect.h:250
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition rect.h:528
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition rect.h:327
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition rect.h:297
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition rect.h:231
constexpr bool IntersectsWithRect(const TRect &o) const
Definition rect.h:546
constexpr TRect CutoutOrEmpty(const TRect &o) const
Definition rect.h:597
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:359
Round(const TRect< U > &r)
Definition rect.h:695
RoundOut(const TRect< U > &r)
Definition rect.h:679
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition rect.h:288
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:438
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:371
constexpr TPoint< T > GetLeftBottom() const
Definition rect.h:367
constexpr TPoint< T > GetRightTop() const
Definition rect.h:363
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:618
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition rect.h:382