This repository has been archived by the owner on Feb 14, 2025. It is now read-only.
forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathview_slicer.cc
124 lines (104 loc) · 4.97 KB
/
view_slicer.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/flow/view_slicer.h"
#include <unordered_map>
#include "flow/embedded_views.h"
#include "fml/logging.h"
namespace flutter {
std::unordered_map<int64_t, SkRect> SliceViews(
DlCanvas* background_canvas,
const std::vector<int64_t>& composition_order,
const std::unordered_map<int64_t, std::unique_ptr<EmbedderViewSlice>>&
slices,
const std::unordered_map<int64_t, SkRect>& view_rects) {
std::unordered_map<int64_t, SkRect> overlay_layers;
auto current_frame_view_count = composition_order.size();
// Restore the clip context after exiting this method since it's changed
// below.
DlAutoCanvasRestore save(background_canvas, /*do_save=*/true);
for (size_t i = 0; i < current_frame_view_count; i++) {
int64_t view_id = composition_order[i];
EmbedderViewSlice* slice = slices.at(view_id).get();
if (slice->canvas() == nullptr) {
continue;
}
slice->end_recording();
SkRect full_joined_rect = SkRect::MakeEmpty();
// Determinate if Flutter UI intersects with any of the previous
// platform views stacked by z position.
//
// This is done by querying the r-tree that holds the records for the
// picture recorder corresponding to the flow layers added after a platform
// view layer.
for (int j = i; j >= 0; j--) {
int64_t current_view_id = composition_order[j];
auto maybe_rect = view_rects.find(current_view_id);
FML_DCHECK(maybe_rect != view_rects.end());
if (maybe_rect == view_rects.end()) {
continue;
}
SkRect current_view_rect = maybe_rect->second;
const SkIRect rounded_in_platform_view_rect = current_view_rect.roundIn();
// Each rect corresponds to a native view that renders Flutter UI.
std::vector<SkIRect> intersection_rects =
slice->region(current_view_rect).getRects();
// Ignore intersections of single width/height on the edge of the platform
// view.
// This is to address the following performance issue when interleaving
// adjacent platform views and layers: Since we `roundOut` both platform
// view rects and the layer rects, as long as the coordinate is
// fractional, there will be an intersection of a single pixel width (or
// height) after rounding out, even if they do not intersect before
// rounding out. We have to round out both platform view rect and the
// layer rect. Rounding in platform view rect will result in missing pixel
// on the intersection edge. Rounding in layer rect will result in missing
// pixel on the edge of the layer on top of the platform view.
for (auto it = intersection_rects.begin(); it != intersection_rects.end();
/*no-op*/) {
// If intersection_rect does not intersect with the *rounded in*
// platform view rect, then the intersection must be a single pixel
// width (or height) on edge.
if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) {
it = intersection_rects.erase(it);
} else {
++it;
}
}
// Limit the number of native views, so it doesn't grow forever.
//
// In this case, the rects are merged into a single one that is the union
// of all the rects.
SkRect partial_joined_rect = SkRect::MakeEmpty();
for (const SkIRect& rect : intersection_rects) {
partial_joined_rect.join(SkRect::Make(rect));
}
// Get the intersection rect with the `current_view_rect`,
if (partial_joined_rect.intersect(
SkRect::Make(current_view_rect.roundOut()))) {
// Join the `partial_joined_rect` into `full_joined_rect` to get the
// rect above the current `slice`, only if it intersects the indicated
// view. This should always be the case because we just deleted any
// rects that don't intersect the "rounded-in" view, so they must
// all intersect the "rounded-out" view (or the partial join could
// be empty in which case this would be a NOP). Either way, the
// penalty for not checking the return value of the intersect method
// would be to join a non-overlapping rectangle into the overlay
// bounds - if the above implementation ever changes - so we check it.
full_joined_rect.join(partial_joined_rect);
}
}
if (!full_joined_rect.isEmpty()) {
overlay_layers.insert({view_id, full_joined_rect});
// Clip the background canvas, so it doesn't contain any of the pixels
// drawn on the overlay layer.
background_canvas->ClipRect(full_joined_rect,
DlCanvas::ClipOp::kDifference);
}
slice->render_into(background_canvas);
}
// Manually trigger the DlAutoCanvasRestore before we submit the frame
save.Restore();
return overlay_layers;
}
} // namespace flutter