Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5dc2469

Browse files
authored
Reland path vol tracker (#23840)
This time making sure to deref the native object on GC.
1 parent 7c19824 commit 5dc2469

25 files changed

+692
-133
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ FILE: ../../../flutter/lib/ui/painting/path.cc
359359
FILE: ../../../flutter/lib/ui/painting/path.h
360360
FILE: ../../../flutter/lib/ui/painting/path_measure.cc
361361
FILE: ../../../flutter/lib/ui/painting/path_measure.h
362+
FILE: ../../../flutter/lib/ui/painting/path_unittests.cc
362363
FILE: ../../../flutter/lib/ui/painting/picture.cc
363364
FILE: ../../../flutter/lib/ui/painting/picture.h
364365
FILE: ../../../flutter/lib/ui/painting/picture_recorder.cc
@@ -402,6 +403,8 @@ FILE: ../../../flutter/lib/ui/ui.dart
402403
FILE: ../../../flutter/lib/ui/ui_benchmarks.cc
403404
FILE: ../../../flutter/lib/ui/ui_dart_state.cc
404405
FILE: ../../../flutter/lib/ui/ui_dart_state.h
406+
FILE: ../../../flutter/lib/ui/volatile_path_tracker.cc
407+
FILE: ../../../flutter/lib/ui/volatile_path_tracker.h
405408
FILE: ../../../flutter/lib/ui/window.dart
406409
FILE: ../../../flutter/lib/ui/window/platform_configuration.cc
407410
FILE: ../../../flutter/lib/ui/window/platform_configuration.h

fml/trace_event.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,19 @@
6868
::fml::tracing::TraceCounter((category_group), (name), (counter_id), (arg1), \
6969
__VA_ARGS__);
7070

71+
// Avoid using the same `name` and `argX_name` for nested traces, which can
72+
// lead to double free errors. E.g. the following code should be avoided:
73+
//
74+
// ```cpp
75+
// {
76+
// TRACE_EVENT1("flutter", "Foo::Bar", "count", "initial_count_value");
77+
// ...
78+
// TRACE_EVENT_INSTANT1("flutter", "Foo::Bar",
79+
// "count", "updated_count_value");
80+
// }
81+
// ```
82+
//
83+
// Instead, either use different `name` or `arg1` parameter names.
7184
#define FML_TRACE_EVENT(category_group, name, ...) \
7285
::fml::tracing::TraceEvent((category_group), (name), __VA_ARGS__); \
7386
__FML__AUTO_TRACE_END(name)

lib/ui/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ source_set("ui") {
9191
"text/text_box.h",
9292
"ui_dart_state.cc",
9393
"ui_dart_state.h",
94+
"volatile_path_tracker.cc",
95+
"volatile_path_tracker.h",
9496
"window/platform_configuration.cc",
9597
"window/platform_configuration.h",
9698
"window/platform_message.cc",
@@ -191,6 +193,7 @@ if (enable_unittests) {
191193
sources = [
192194
"painting/image_dispose_unittests.cc",
193195
"painting/image_encoding_unittests.cc",
196+
"painting/path_unittests.cc",
194197
"painting/vertices_unittests.cc",
195198
"window/platform_configuration_unittests.cc",
196199
"window/pointer_data_packet_converter_unittests.cc",

lib/ui/fixtures/ui_test.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ void createVertices() {
3737
}
3838
void _validateVertices(Vertices vertices) native 'ValidateVertices';
3939

40+
@pragma('vm:entry-point')
41+
void createPath() {
42+
final Path path = Path()..lineTo(10, 10);
43+
_validatePath(path);
44+
// Arbitrarily hold a reference to the path to make sure it does not get
45+
// garbage collected.
46+
Future<void>.delayed(const Duration(days: 100)).then((_) {
47+
path.lineTo(100, 100);
48+
});
49+
}
50+
void _validatePath(Path path) native 'ValidatePath';
51+
4052
@pragma('vm:entry-point')
4153
void frameCallback(FrameInfo info) {
4254
print('called back');

lib/ui/painting/path.cc

Lines changed: 90 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -67,43 +67,70 @@ void CanvasPath::RegisterNatives(tonic::DartLibraryNatives* natives) {
6767
FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
6868
}
6969

70-
CanvasPath::CanvasPath() {}
70+
CanvasPath::CanvasPath()
71+
: path_tracker_(UIDartState::Current()->GetVolatilePathTracker()),
72+
tracked_path_(std::make_shared<VolatilePathTracker::TrackedPath>()) {
73+
FML_DCHECK(path_tracker_);
74+
resetVolatility();
75+
}
76+
77+
CanvasPath::~CanvasPath() = default;
78+
79+
void CanvasPath::resetVolatility() {
80+
if (!tracked_path_->tracking_volatility) {
81+
mutable_path().setIsVolatile(true);
82+
tracked_path_->frame_count = 0;
83+
tracked_path_->tracking_volatility = true;
84+
path_tracker_->Insert(tracked_path_);
85+
}
86+
}
7187

72-
CanvasPath::~CanvasPath() {}
88+
void CanvasPath::ReleaseDartWrappableReference() const {
89+
FML_DCHECK(path_tracker_);
90+
path_tracker_->Erase(tracked_path_);
91+
RefCountedDartWrappable::ReleaseDartWrappableReference();
92+
}
7393

7494
int CanvasPath::getFillType() {
75-
return static_cast<int>(path_.getFillType());
95+
return static_cast<int>(path().getFillType());
7696
}
7797

7898
void CanvasPath::setFillType(int fill_type) {
79-
path_.setFillType(static_cast<SkPathFillType>(fill_type));
99+
mutable_path().setFillType(static_cast<SkPathFillType>(fill_type));
100+
resetVolatility();
80101
}
81102

82103
void CanvasPath::moveTo(float x, float y) {
83-
path_.moveTo(x, y);
104+
mutable_path().moveTo(x, y);
105+
resetVolatility();
84106
}
85107

86108
void CanvasPath::relativeMoveTo(float x, float y) {
87-
path_.rMoveTo(x, y);
109+
mutable_path().rMoveTo(x, y);
110+
resetVolatility();
88111
}
89112

90113
void CanvasPath::lineTo(float x, float y) {
91-
path_.lineTo(x, y);
114+
mutable_path().lineTo(x, y);
115+
resetVolatility();
92116
}
93117

94118
void CanvasPath::relativeLineTo(float x, float y) {
95-
path_.rLineTo(x, y);
119+
mutable_path().rLineTo(x, y);
120+
resetVolatility();
96121
}
97122

98123
void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) {
99-
path_.quadTo(x1, y1, x2, y2);
124+
mutable_path().quadTo(x1, y1, x2, y2);
125+
resetVolatility();
100126
}
101127

102128
void CanvasPath::relativeQuadraticBezierTo(float x1,
103129
float y1,
104130
float x2,
105131
float y2) {
106-
path_.rQuadTo(x1, y1, x2, y2);
132+
mutable_path().rQuadTo(x1, y1, x2, y2);
133+
resetVolatility();
107134
}
108135

109136
void CanvasPath::cubicTo(float x1,
@@ -112,7 +139,8 @@ void CanvasPath::cubicTo(float x1,
112139
float y2,
113140
float x3,
114141
float y3) {
115-
path_.cubicTo(x1, y1, x2, y2, x3, y3);
142+
mutable_path().cubicTo(x1, y1, x2, y2, x3, y3);
143+
resetVolatility();
116144
}
117145

118146
void CanvasPath::relativeCubicTo(float x1,
@@ -121,19 +149,22 @@ void CanvasPath::relativeCubicTo(float x1,
121149
float y2,
122150
float x3,
123151
float y3) {
124-
path_.rCubicTo(x1, y1, x2, y2, x3, y3);
152+
mutable_path().rCubicTo(x1, y1, x2, y2, x3, y3);
153+
resetVolatility();
125154
}
126155

127156
void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) {
128-
path_.conicTo(x1, y1, x2, y2, w);
157+
mutable_path().conicTo(x1, y1, x2, y2, w);
158+
resetVolatility();
129159
}
130160

131161
void CanvasPath::relativeConicTo(float x1,
132162
float y1,
133163
float x2,
134164
float y2,
135165
float w) {
136-
path_.rConicTo(x1, y1, x2, y2, w);
166+
mutable_path().rConicTo(x1, y1, x2, y2, w);
167+
resetVolatility();
137168
}
138169

139170
void CanvasPath::arcTo(float left,
@@ -143,9 +174,10 @@ void CanvasPath::arcTo(float left,
143174
float startAngle,
144175
float sweepAngle,
145176
bool forceMoveTo) {
146-
path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom),
147-
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
148-
forceMoveTo);
177+
mutable_path().arcTo(SkRect::MakeLTRB(left, top, right, bottom),
178+
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
179+
forceMoveTo);
180+
resetVolatility();
149181
}
150182

151183
void CanvasPath::arcToPoint(float arcEndX,
@@ -160,8 +192,9 @@ void CanvasPath::arcToPoint(float arcEndX,
160192
const auto direction =
161193
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
162194

163-
path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX,
164-
arcEndY);
195+
mutable_path().arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
196+
arcEndX, arcEndY);
197+
resetVolatility();
165198
}
166199

167200
void CanvasPath::relativeArcToPoint(float arcEndDeltaX,
@@ -175,16 +208,19 @@ void CanvasPath::relativeArcToPoint(float arcEndDeltaX,
175208
: SkPath::ArcSize::kSmall_ArcSize;
176209
const auto direction =
177210
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
178-
path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
179-
arcEndDeltaX, arcEndDeltaY);
211+
mutable_path().rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
212+
arcEndDeltaX, arcEndDeltaY);
213+
resetVolatility();
180214
}
181215

182216
void CanvasPath::addRect(float left, float top, float right, float bottom) {
183-
path_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
217+
mutable_path().addRect(SkRect::MakeLTRB(left, top, right, bottom));
218+
resetVolatility();
184219
}
185220

186221
void CanvasPath::addOval(float left, float top, float right, float bottom) {
187-
path_.addOval(SkRect::MakeLTRB(left, top, right, bottom));
222+
mutable_path().addOval(SkRect::MakeLTRB(left, top, right, bottom));
223+
resetVolatility();
188224
}
189225

190226
void CanvasPath::addArc(float left,
@@ -193,25 +229,29 @@ void CanvasPath::addArc(float left,
193229
float bottom,
194230
float startAngle,
195231
float sweepAngle) {
196-
path_.addArc(SkRect::MakeLTRB(left, top, right, bottom),
197-
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI);
232+
mutable_path().addArc(SkRect::MakeLTRB(left, top, right, bottom),
233+
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI);
234+
resetVolatility();
198235
}
199236

200237
void CanvasPath::addPolygon(const tonic::Float32List& points, bool close) {
201-
path_.addPoly(reinterpret_cast<const SkPoint*>(points.data()),
202-
points.num_elements() / 2, close);
238+
mutable_path().addPoly(reinterpret_cast<const SkPoint*>(points.data()),
239+
points.num_elements() / 2, close);
240+
resetVolatility();
203241
}
204242

205243
void CanvasPath::addRRect(const RRect& rrect) {
206-
path_.addRRect(rrect.sk_rrect);
244+
mutable_path().addRRect(rrect.sk_rrect);
245+
resetVolatility();
207246
}
208247

209248
void CanvasPath::addPath(CanvasPath* path, double dx, double dy) {
210249
if (!path) {
211250
Dart_ThrowException(ToDart("Path.addPath called with non-genuine Path."));
212251
return;
213252
}
214-
path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
253+
mutable_path().addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
254+
resetVolatility();
215255
}
216256

217257
void CanvasPath::addPathWithMatrix(CanvasPath* path,
@@ -227,8 +267,9 @@ void CanvasPath::addPathWithMatrix(CanvasPath* path,
227267
SkMatrix matrix = ToSkMatrix(matrix4);
228268
matrix.setTranslateX(matrix.getTranslateX() + dx);
229269
matrix.setTranslateY(matrix.getTranslateY() + dy);
230-
path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
270+
mutable_path().addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
231271
matrix4.Release();
272+
resetVolatility();
232273
}
233274

234275
void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) {
@@ -237,7 +278,8 @@ void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) {
237278
ToDart("Path.extendWithPath called with non-genuine Path."));
238279
return;
239280
}
240-
path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
281+
mutable_path().addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
282+
resetVolatility();
241283
}
242284

243285
void CanvasPath::extendWithPathAndMatrix(CanvasPath* path,
@@ -253,37 +295,43 @@ void CanvasPath::extendWithPathAndMatrix(CanvasPath* path,
253295
SkMatrix matrix = ToSkMatrix(matrix4);
254296
matrix.setTranslateX(matrix.getTranslateX() + dx);
255297
matrix.setTranslateY(matrix.getTranslateY() + dy);
256-
path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
298+
mutable_path().addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
257299
matrix4.Release();
300+
resetVolatility();
258301
}
259302

260303
void CanvasPath::close() {
261-
path_.close();
304+
mutable_path().close();
305+
resetVolatility();
262306
}
263307

264308
void CanvasPath::reset() {
265-
path_.reset();
309+
mutable_path().reset();
310+
resetVolatility();
266311
}
267312

268313
bool CanvasPath::contains(double x, double y) {
269-
return path_.contains(x, y);
314+
return path().contains(x, y);
270315
}
271316

272317
void CanvasPath::shift(Dart_Handle path_handle, double dx, double dy) {
273318
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
274-
path_.offset(dx, dy, &path->path_);
319+
auto& other_mutable_path = path->mutable_path();
320+
mutable_path().offset(dx, dy, &other_mutable_path);
321+
resetVolatility();
275322
}
276323

277324
void CanvasPath::transform(Dart_Handle path_handle,
278325
tonic::Float64List& matrix4) {
279326
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
280-
path_.transform(ToSkMatrix(matrix4), &path->path_);
327+
auto& other_mutable_path = path->mutable_path();
328+
mutable_path().transform(ToSkMatrix(matrix4), &other_mutable_path);
281329
matrix4.Release();
282330
}
283331

284332
tonic::Float32List CanvasPath::getBounds() {
285333
tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4));
286-
const SkRect& bounds = path_.getBounds();
334+
const SkRect& bounds = path().getBounds();
287335
rect[0] = bounds.left();
288336
rect[1] = bounds.top();
289337
rect[2] = bounds.right();
@@ -293,21 +341,22 @@ tonic::Float32List CanvasPath::getBounds() {
293341

294342
bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) {
295343
return Op(path1->path(), path2->path(), static_cast<SkPathOp>(operation),
296-
&path_);
344+
&tracked_path_->path);
345+
resetVolatility();
297346
}
298347

299348
void CanvasPath::clone(Dart_Handle path_handle) {
300349
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
301350
// per Skia docs, this will create a fast copy
302351
// data is shared until the source path or dest path are mutated
303-
path->path_ = path_;
352+
path->mutable_path() = this->path();
304353
}
305354

306355
// This is doomed to be called too early, since Paths are mutable.
307356
// However, it can help for some of the clone/shift/transform type methods
308357
// where the resultant path will initially have a meaningful size.
309358
size_t CanvasPath::GetAllocationSize() const {
310-
return sizeof(CanvasPath) + path_.approximateBytesUsed();
359+
return sizeof(CanvasPath) + path().approximateBytesUsed();
311360
}
312361

313362
} // namespace flutter

0 commit comments

Comments
 (0)