Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5aa2913
avoid unnecessary operations during indices check
timmaffett May 5, 2023
57781a2
fix indices check in raw() to correctly check <positions.length/2
timmaffett May 5, 2023
e80a3dc
formatting
timmaffett May 5, 2023
118a38a
add tests for ckVertices doing proper parameter checks
timmaffett May 5, 2023
d692f0f
add positions.length is even check to CkVertices.raw()
timmaffett May 5, 2023
046a729
made throws in vertices_test.dart throw ArgumentError to make linux a…
timmaffett May 5, 2023
930d9ea
fix tests expected error text
timmaffett May 5, 2023
fe4db2b
changed %2!=0 check to use isOdd
timmaffett May 16, 2023
7c42cc2
Merge branch 'main' into vertices.raw
timmaffett Jun 1, 2023
a1f133a
Merge branch 'flutter:main' into vertices.raw
timmaffett Jun 1, 2023
e15299a
change vertices_test.dart to only check CkVertices for argument check…
timmaffett Jun 2, 2023
702ff22
change web_ui vertices checks to asserts and add to skwasm_impl
timmaffett Jun 2, 2023
cfcf849
fix catch for ArgumentError
timmaffett Jun 2, 2023
217de1d
added vertices checks to html render_vertices.dart, formatting
timmaffett Jun 2, 2023
8e3dcec
tweaks to tests to properly identify exception text
timmaffett Jun 2, 2023
0b2f940
fix trailing space
timmaffett Jun 2, 2023
1ad8364
match assertionerror extra slashes
timmaffett Jun 2, 2023
010c78a
correct assertion match
timmaffett Jun 2, 2023
1bc170a
fix vertices.raw test
timmaffett Jun 2, 2023
edf7ba0
added debug code to print stacktrace so see what is generating unexpe…
timmaffett Jun 2, 2023
cfe76fb
move vertices checks in painting to asserts,fix indices asserts
timmaffett Jun 2, 2023
468c585
moving vertices checsk in paint to asserts
timmaffett Jun 2, 2023
2d9dbd3
remove trailing space
timmaffett Jun 2, 2023
eeca5e1
made assert expects dependent on asserts being enabled
timmaffett Jun 2, 2023
9532396
remove non assert checks from vertices code, tests check if asserts a…
timmaffett Jun 2, 2023
4640ed2
Merge branch 'main' into vertices.raw
timmaffett Jun 5, 2023
8b06199
change to using every instead of any
timmaffett Jun 7, 2023
d0c7a97
Merge branch 'vertices.raw' of https://github.com/timmaffett/engine i…
timmaffett Jun 7, 2023
e2cf427
Merge branch 'flutter:main' into vertices.raw
timmaffett Jun 7, 2023
d303c63
fix spacing
timmaffett Jun 7, 2023
3428566
Merge branch 'vertices.raw' of https://github.com/timmaffett/engine i…
timmaffett Jun 7, 2023
f82de2b
change any use to every in vertices checks
timmaffett Jun 7, 2023
3f1f1cb
remove negation on every
timmaffett Jun 7, 2023
371b2e6
fix spacing around ==
timmaffett Jun 8, 2023
e42938d
add space after if where missing
timmaffett Jun 8, 2023
f987b94
update AUTHORS
timmaffett Jun 8, 2023
a9e8e0f
add use and disposing of invalid Vertices objects when asserts not en…
timmaffett Nov 30, 2023
0db8427
dispose of invalid vertices objects (that would be created if asserts…
timmaffett Nov 30, 2023
d8a42d6
Merge branch 'main' into vertices.raw
timmaffett Nov 30, 2023
8197599
remove trailing space
timmaffett Dec 1, 2023
4050715
Update AUTHORS
kevmoo Feb 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ TheOneWithTheBraid <the-one@with-the-braid.cf>
Twin Sun, LLC <google-contrib@twinsunsolutions.com>
Qixing Cao <qixing.cao.83@gmail.com>
LinXunFeng <linxunfeng@yeah.net>
Amir Panahandeh <amirpanahandeh@gmail.com>
Amir Panahandeh <amirpanahandeh@gmail.com>
Tim Maffett <timmaffett@gmail.com>
46 changes: 7 additions & 39 deletions lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4737,24 +4737,9 @@ base class Vertices extends NativeFieldWrapperClass1 {
List<Color>? colors,
List<Offset>? textureCoordinates,
List<int>? indices,
}) {
if (colors != null && colors.length != positions.length) {
throw ArgumentError('"positions" and "colors" lengths must match.');
}
if (textureCoordinates != null && textureCoordinates.length != positions.length) {
throw ArgumentError('"positions" and "textureCoordinates" lengths must match.');
}
if (indices != null) {
for (int index = 0; index < indices.length; index += 1) {
if (indices[index] >= positions.length) {
throw ArgumentError(
'"indices" values must be valid indices in the positions list '
'(i.e. numbers in the range 0..${positions.length - 1}), '
'but indices[$index] is ${indices[index]}, which is too big.',
);
}
}
}
}) : assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.'),
assert(colors == null || colors.length == positions.length,'"positions" and "colors" lengths must match.'),
assert(indices == null || indices.every((int i) => i >= 0 && i < positions.length),'"indices" values must be valid indices in the positions list.') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could definitely let the indices check be an assert. I think at most you'll get graphical corruption.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, on iOS/Metal we have to unroll triangle fans. If we end up using the indices to look up positions an invalid index could still lead to a crash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonahwilliams Do you think I should go ahead and just close this ? - or would moving the checks to the c++ code closer where they are used make more sense ? (and possibly be faster?)

final Float32List encodedPositions = _encodePointList(positions);
final Float32List? encodedTextureCoordinates = (textureCoordinates != null)
? _encodePointList(textureCoordinates)
Expand Down Expand Up @@ -4821,27 +4806,10 @@ base class Vertices extends NativeFieldWrapperClass1 {
Int32List? colors,
Float32List? textureCoordinates,
Uint16List? indices,
}) {
if (positions.length % 2 != 0) {
throw ArgumentError('"positions" must have an even number of entries (each coordinate is an x,y pair).');
}
if (colors != null && colors.length * 2 != positions.length) {
throw ArgumentError('"positions" and "colors" lengths must match.');
}
if (textureCoordinates != null && textureCoordinates.length != positions.length) {
throw ArgumentError('"positions" and "textureCoordinates" lengths must match.');
}
if (indices != null) {
for (int index = 0; index < indices.length; index += 1) {
if (indices[index] * 2 >= positions.length) {
throw ArgumentError(
'"indices" values must be valid indices in the positions list '
'(i.e. numbers in the range 0..${positions.length ~/ 2 - 1}), '
'but indices[$index] is ${indices[index]}, which is too big.',
);
}
}
}
}) : assert(positions.length.isEven,'"positions" must have an even number of entries (each coordinate is an x,y pair).'),
assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.'),
assert(colors == null || colors.length * 2 == positions.length,'"colors" length must be half the length of "positions".'),
assert(indices == null || indices.every((int i) => i >= 0 && i*2 < positions.length),'"indices" values must be valid indices in the positions list.') {
if (!_init(this, mode.index, positions, textureCoordinates, colors, indices)) {
throw ArgumentError('Invalid configuration for vertices.');
}
Expand Down
35 changes: 7 additions & 28 deletions lib/web_ui/lib/src/engine/canvaskit/vertices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,9 @@ class CkVertices implements ui.Vertices {
List<ui.Color>? colors,
List<int>? indices,
}) {
if (textureCoordinates != null &&
textureCoordinates.length != positions.length) {
throw ArgumentError(
'"positions" and "textureCoordinates" lengths must match.');
}
if (colors != null && colors.length != positions.length) {
throw ArgumentError('"positions" and "colors" lengths must match.');
}
if (indices != null &&
indices.any((int i) => i < 0 || i >= positions.length)) {
throw ArgumentError(
'"indices" values must be valid indices in the positions list.');
}

assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.');
assert(colors == null || colors.length == positions.length,'"positions" and "colors" lengths must match.');
assert(indices == null || indices.every((int i) => i >= 0 && i < positions.length),'"indices" values must be valid indices in the positions list.');
return CkVertices._(
toSkVertexMode(mode),
toFlatSkPoints(positions),
Expand All @@ -47,20 +36,10 @@ class CkVertices implements ui.Vertices {
Int32List? colors,
Uint16List? indices,
}) {
if (textureCoordinates != null &&
textureCoordinates.length != positions.length) {
throw ArgumentError(
'"positions" and "textureCoordinates" lengths must match.');
}
if (colors != null && colors.length * 2 != positions.length) {
throw ArgumentError('"positions" and "colors" lengths must match.');
}
if (indices != null &&
indices.any((int i) => i < 0 || i >= positions.length)) {
throw ArgumentError(
'"indices" values must be valid indices in the positions list.');
}

assert(positions.length.isEven,'"positions" must have an even number of entries (each coordinate is an x,y pair).');
assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.');
assert(colors == null || colors.length * 2 == positions.length,'"colors" length must be half the length of "positions".');
assert(indices == null || indices.every((int i) => i >= 0 && i*2 < positions.length),'"indices" values must be valid indices in the positions list.');
Uint32List? unsignedColors;
if (colors != null) {
unsignedColors = colors.buffer.asUint32List(colors.offsetInBytes, colors.length);
Expand Down
8 changes: 6 additions & 2 deletions lib/web_ui/lib/src/engine/html/render_vertices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class SurfaceVertices implements ui.Vertices {
List<ui.Offset> positions, {
List<ui.Color>? colors,
List<int>? indices,
}) : colors = colors != null ? _int32ListFromColors(colors) : null,
}) : assert(colors == null || colors.length == positions.length,'"positions" and "colors" lengths must match.'),
assert(indices == null || indices.every((int i) => i >= 0 && i < positions.length),'"indices" values must be valid indices in the positions list.'),
colors = colors != null ? _int32ListFromColors(colors) : null,
indices = indices != null ? Uint16List.fromList(indices) : null,
positions = offsetListToFloat32List(positions) {
initWebGl();
Expand All @@ -37,7 +39,9 @@ class SurfaceVertices implements ui.Vertices {
this.positions, {
this.colors,
this.indices,
}) {
}) : assert(positions.length.isEven,'"positions" must have an even number of entries (each coordinate is an x,y pair).'),
assert(colors == null || colors.length * 2 == positions.length,'"colors" length must be half the length of "positions".'),
assert(indices == null || indices.every((int i) => i >= 0 && i*2 < positions.length),'"indices" values must be valid indices in the positions list.') {
initWebGl();
}

Expand Down
7 changes: 7 additions & 0 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class SkwasmVertices extends SkwasmObjectWrapper<RawVertices> implements ui.Vert
List<ui.Color>? colors,
List<int>? indices,
}) => withStackScope((StackScope scope) {
assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.');
assert(colors == null || colors.length == positions.length,'"positions" and "colors" lengths must match.');
assert(indices == null || indices.every((int i) => i >= 0 && i < positions.length),'"indices" values must be valid indices in the positions list.');
final RawPointArray rawPositions = scope.convertPointArrayToNative(positions);
final RawPointArray rawTextureCoordinates = textureCoordinates != null
? scope.convertPointArrayToNative(textureCoordinates)
Expand Down Expand Up @@ -47,6 +50,10 @@ class SkwasmVertices extends SkwasmObjectWrapper<RawVertices> implements ui.Vert
Int32List? colors,
Uint16List? indices,
}) => withStackScope((StackScope scope) {
assert(positions.length.isEven,'"positions" must have an even number of entries (each coordinate is an x,y pair).');
assert(textureCoordinates == null || textureCoordinates.length == positions.length,'"positions" and "textureCoordinates" lengths must match.');
assert(colors == null || colors.length * 2 == positions.length,'"colors" length must be half the length of "positions".');
assert(indices == null || indices.every((int i) => i >= 0 && i*2 < positions.length),'"indices" values must be valid indices in the positions list.');
final RawPointArray rawPositions = scope.convertDoublesToNative(positions);
final RawPointArray rawTextureCoordinates = textureCoordinates != null
? scope.convertDoublesToNative(textureCoordinates)
Expand Down
169 changes: 169 additions & 0 deletions lib/web_ui/test/ui/vertices_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'dart:typed_data';

import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart' show renderer;
import 'package:ui/ui.dart' as ui;
import 'package:web_engine_tester/golden_tester.dart';

Expand All @@ -17,6 +18,12 @@ void main() {
}

void testMain() {
bool assertsEnabled = false;
assert(() {
assertsEnabled = true;
return true;
}());

group('Vertices', () {
setUpUnitTests(setUpTestViewDimensions: false);

Expand Down Expand Up @@ -58,6 +65,148 @@ void testMain() {
await drawPictureUsingCurrentRenderer(recorder.endRecording());
await matchGoldenFile('ui_vertices_antialiased.png', region: region);
}, skip: isHtml); // https://github.com/flutter/flutter/issues/127454

test('Vertices assert checks', () {
// We don't test textureCoordinate assert checks on html render because HTML renderer's SurfaceVertices() does not support textureCoordinates
if (renderer.rendererTag != 'html') {
try {
final ui.Vertices invalidVertices = ui.Vertices(
ui.VertexMode.triangles,
const <ui.Offset>[ui.Offset.zero, ui.Offset.zero, ui.Offset.zero],
textureCoordinates: const <ui.Offset>[ui.Offset.zero],
);
if (assertsEnabled) {
throw AssertionError('Vertices did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"positions\" and \"textureCoordinates\" lengths must match.'));
}
}
try {
final ui.Vertices invalidVertices = ui.Vertices(
ui.VertexMode.triangles,
const <ui.Offset>[ui.Offset.zero, ui.Offset.zero, ui.Offset.zero],
colors: const <ui.Color>[ui.Color.fromRGBO(255, 0, 0, 1.0)],
);
if (assertsEnabled) {
throw AssertionError('Vertices did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"positions\" and \"colors\" lengths must match.'));
}
try {
final ui.Vertices invalidVertices = ui.Vertices(
ui.VertexMode.triangles,
const <ui.Offset>[ui.Offset.zero, ui.Offset.zero, ui.Offset.zero],
indices: Uint16List.fromList(const <int>[0, 2, 5]),
);
if (assertsEnabled) {
throw AssertionError('Vertices did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"indices\" values must be valid indices in the positions list.'));
}
ui.Vertices( // This one does not throw.
ui.VertexMode.triangles,
const <ui.Offset>[ui.Offset.zero],
).dispose();
ui.Vertices( // This one should not throw.
ui.VertexMode.triangles,
const <ui.Offset>[ui.Offset.zero, ui.Offset.zero, ui.Offset.zero],
indices: Uint16List.fromList(const <int>[0, 2, 1, 2, 0, 1, 2, 0]), // Uint16List implements List<int> so this is ok.
).dispose();
});

test('Vertices.raw assert checks', () {
try {
final ui.Vertices invalidVertices = ui.Vertices.raw(
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0]),
);
if (assertsEnabled) {
throw AssertionError('Vertices.raw did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"positions\" must have an even number of entries (each coordinate is an x,y pair).'));
}
// We don't test textureCoordinate assert checks on html render because HTML renderer's SurfaceVertices() does not support textureCoordinates
if (renderer.rendererTag != 'html') {
try {
final ui.Vertices invalidVertices = ui.Vertices.raw(
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
textureCoordinates: Float32List.fromList(const <double>[0.0, 0.0]),
);
if (assertsEnabled) {
throw AssertionError('Vertices did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"positions\" and \"textureCoordinates\" lengths must match.'));
}
}
try {
final ui.Vertices invalidVertices = ui.Vertices.raw(
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
colors: Int32List.fromList(const <int>[0xffff0000]),
);
if (assertsEnabled) {
throw AssertionError('Vertices did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"colors\" length must be half the length of \"positions\".'));
}
try {
final ui.Vertices invalidVertices = ui.Vertices.raw(
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
indices: Uint16List.fromList(const <int>[0, 2, 5]),
);
if (assertsEnabled) {
throw AssertionError('Vertices.raw did not throw the expected assert error.');
} else {
// Assertions are NOT ENABLED, so we will attempt to use this invalid ui.Vertices object
// we just created to check if that causes exceptions/problems.
useAndDisposeOfInvalidVerticesObject(invalidVertices);
}
} on AssertionError catch (e) {
expect('$e', contains(r'\"indices\" values must be valid indices in the positions list.'));
}
ui.Vertices.raw( // This one does not throw.
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0, 0.0]),
).dispose();
ui.Vertices.raw( // This one should not throw.
ui.VertexMode.triangles,
Float32List.fromList(const <double>[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
indices: Uint16List.fromList(const <int>[0, 2, 1, 2, 0, 1, 2, 0]),
).dispose();
});

}

ui.Vertices _testVertices() {
Expand Down Expand Up @@ -266,3 +415,23 @@ const List<int> _circularVertexIndices = <int>[
34,
36
];

// This function is used when asserts are NOT enabled and vertices() allows invalid
// vertices objects to be created. Here we attempt to use these invalid ui.Vertices
// objects to determine if they cause problems within drawVertices()
void useAndDisposeOfInvalidVerticesObject( ui.Vertices vertices ) {
expect(vertices.debugDisposed, isFalse);

final ui.PictureRecorder recorder = ui.PictureRecorder();
final ui.Canvas canvas = ui.Canvas(
recorder,
const ui.Rect.fromLTRB(0, 0, 100, 100)
);
canvas.drawVertices(
vertices,
ui.BlendMode.srcOver,
ui.Paint(),
);
vertices.dispose();
expect(vertices.debugDisposed, isTrue);
}
Loading