diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_ref.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_ref.dart index 078f3d6de05..2b9c9f094ca 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_ref.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_ref.dart @@ -367,7 +367,7 @@ class PathRef { } else { _conicWeights!.setAll(0, ref._conicWeights!); } - assert(verbCount == 0 || _fVerbs[0] != 0); + assert(verbCount == 0 || _fVerbs[0] == ref._fVerbs[0]); fBoundsIsDirty = ref.fBoundsIsDirty; if (!fBoundsIsDirty) { fBounds = ref.fBounds; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_utils.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_utils.dart index 18abeefa239..9908cf52370 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_utils.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_utils.dart @@ -15,12 +15,12 @@ class SPathSegmentMask { /// Types of path operations. class SPathVerb { - static const int kMove = 1; // 1 point - static const int kLine = 2; // 2 points - static const int kQuad = 3; // 3 points - static const int kConic = 4; // 3 points + 1 weight - static const int kCubic = 5; // 4 points - static const int kClose = 6; // 0 points + static const int kMove = 0; // 1 point + static const int kLine = 1; // 2 points + static const int kQuad = 2; // 3 points + static const int kConic = 3; // 3 points + 1 weight + static const int kCubic = 4; // 4 points + static const int kClose = 5; // 0 points } class SPath { diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_windings.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_windings.dart index 23790890da7..554a5413c8e 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_windings.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/surface/path/path_windings.dart @@ -145,7 +145,8 @@ class PathWinding { } _QuadRoots quadRoots = _QuadRoots(); - final int n = quadRoots.findRoots(startY - 2 * y1 + endY, 2 * (y1 - startY), endY - y); + final int n = quadRoots.findRoots( + startY - 2 * y1 + endY, 2 * (y1 - startY), endY - y); assert(n <= 1); double xt; if (0 == n) { @@ -377,6 +378,9 @@ class PathIterator { int _verbIndex = 0; int _pointIndex = 0; + /// Maximum buffer size required for points in [next] calls. + static const int kMaxBufferSize = 8; + /// Returns true if first contour on path is closed. bool isClosedContour() { if (_verbCount == 0 || _verbIndex == _verbCount) { @@ -438,7 +442,17 @@ class PathIterator { pathRef.points[_pointIndex - 2], pathRef.points[_pointIndex - 1]); } - int peek() => pathRef._fVerbs[_verbIndex]; + int peek() { + if (_verbIndex < pathRef.countVerbs()) { + return pathRef._fVerbs[_verbIndex]; + } + if (_needClose && _segmentState == SPathSegmentState.kAfterPrimitive) { + return (_lastPointX != _moveToX || _lastPointY != _moveToY) + ? SPath.kLineVerb + : SPath.kCloseVerb; + } + return SPath.kDoneVerb; + } // Returns next verb and reads associated points into [outPts]. int next(Float32List outPts) { diff --git a/engine/src/flutter/lib/web_ui/test/engine/surface/path/path_iterator_test.dart b/engine/src/flutter/lib/web_ui/test/engine/surface/path/path_iterator_test.dart new file mode 100644 index 00000000000..28c3f261fce --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/engine/surface/path/path_iterator_test.dart @@ -0,0 +1,85 @@ +// 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. + +import 'dart:typed_data'; + +import 'package:ui/src/engine.dart'; +import 'package:test/test.dart'; + +void main() { + final Float32List points = Float32List(PathIterator.kMaxBufferSize); + + group('PathIterator', () { + test('Should return done verb for empty path', () { + final SurfacePath path = SurfacePath(); + final PathIterator iter = PathIterator(path.pathRef, false); + expect(iter.peek(), SPath.kDoneVerb); + expect(iter.next(points), SPath.kDoneVerb); + }); + + test('Should return done when moveTo is last instruction', () { + final SurfacePath path = SurfacePath(); + path.moveTo(10, 10); + final PathIterator iter = PathIterator(path.pathRef, false); + expect(iter.peek(), SPath.kMoveVerb); + expect(iter.next(points), SPath.kDoneVerb); + }); + + test('Should return lineTo', () { + final SurfacePath path = SurfacePath(); + path.moveTo(10, 10); + path.lineTo(20, 20); + final PathIterator iter = PathIterator(path.pathRef, false); + expect(iter.peek(), SPath.kMoveVerb); + expect(iter.next(points), SPath.kMoveVerb); + expect(points[0], 10); + expect(iter.next(points), SPath.kLineVerb); + expect(points[2], 20); + expect(iter.next(points), SPath.kDoneVerb); + }); + + test('Should return extra lineTo if iteration is closed', () { + final SurfacePath path = SurfacePath(); + path.moveTo(10, 10); + path.lineTo(20, 20); + final PathIterator iter = PathIterator(path.pathRef, true); + expect(iter.peek(), SPath.kMoveVerb); + expect(iter.next(points), SPath.kMoveVerb); + expect(points[0], 10); + expect(iter.next(points), SPath.kLineVerb); + expect(points[2], 20); + expect(iter.next(points), SPath.kLineVerb); + expect(points[2], 10); + expect(iter.next(points), SPath.kCloseVerb); + expect(iter.next(points), SPath.kDoneVerb); + }); + + test('Should not return extra lineTo if last point is starting point', () { + final SurfacePath path = SurfacePath(); + path.moveTo(10, 10); + path.lineTo(20, 20); + path.lineTo(10, 10); + final PathIterator iter = PathIterator(path.pathRef, true); + expect(iter.peek(), SPath.kMoveVerb); + expect(iter.next(points), SPath.kMoveVerb); + expect(points[0], 10); + expect(iter.next(points), SPath.kLineVerb); + expect(points[2], 20); + expect(iter.next(points), SPath.kLineVerb); + expect(points[2], 10); + expect(iter.next(points), SPath.kCloseVerb); + expect(iter.next(points), SPath.kDoneVerb); + }); + + test('peek should return lineTo if iteration is closed', () { + final SurfacePath path = SurfacePath(); + path.moveTo(10, 10); + path.lineTo(20, 20); + final PathIterator iter = PathIterator(path.pathRef, true); + expect(iter.next(points), SPath.kMoveVerb); + expect(iter.next(points), SPath.kLineVerb); + expect(iter.peek(), SPath.kLineVerb); + }); + }); +} diff --git a/engine/src/flutter/lib/web_ui/test/path_winding_test.dart b/engine/src/flutter/lib/web_ui/test/engine/surface/path/path_winding_test.dart similarity index 100% rename from engine/src/flutter/lib/web_ui/test/path_winding_test.dart rename to engine/src/flutter/lib/web_ui/test/engine/surface/path/path_winding_test.dart