@@ -61,9 +61,9 @@ class PathRef {
6161 fBoundsIsDirty = true ; // this also invalidates fIsFinite
6262 fSegmentMask = 0 ;
6363 fIsOval = false ;
64- rrectRepresentation = null ;
64+ fIsRRect = false ;
6565 fIsRect = false ;
66- // The next two values don't matter unless fIsOval is true or rrectRepresentation is not null .
66+ // The next two values don't matter unless fIsOval or fIsRRect are true .
6767 fRRectOrOvalIsCCW = false ;
6868 fRRectOrOvalStartIdx = 0xAC ;
6969 assert (() {
@@ -104,7 +104,7 @@ class PathRef {
104104 }
105105 fSegmentMask = ref.fSegmentMask;
106106 fIsOval = ref.fIsOval;
107- rrectRepresentation = ref.rrectRepresentation ;
107+ fIsRRect = ref.fIsRRect ;
108108 fIsRect = ref.fIsRect;
109109 fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW;
110110 fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx;
@@ -153,9 +153,9 @@ class PathRef {
153153 int get isOval => fIsOval ? fRRectOrOvalStartIdx : - 1 ;
154154 bool get isOvalCCW => fRRectOrOvalIsCCW;
155155
156- int get isRRect => rrectRepresentation != null ? fRRectOrOvalStartIdx : - 1 ;
156+ int get isRRect => fIsRRect ? fRRectOrOvalStartIdx : - 1 ;
157157 int get isRect => fIsRect ? fRRectOrOvalStartIdx : - 1 ;
158- ui.RRect ? getRRect () => rrectRepresentation ;
158+ ui.RRect ? getRRect () => fIsRRect ? _getRRect () : null ;
159159 ui.Rect ? getRect () {
160160 /// Use _detectRect() for detection if explicity addRect was used (fIsRect) or
161161 /// it is a potential due to moveTo + 3 lineTo verbs.
@@ -227,6 +227,70 @@ class PathRef {
227227 return null ;
228228 }
229229
230+ /// Reconstructs RRect from path commands.
231+ ///
232+ /// Expect 4 Conics and lines between.
233+ /// Use conic points to calculate corner radius.
234+ ui.RRect _getRRect () {
235+ ui.Rect bounds = getBounds ();
236+ // Radii x,y of 4 corners
237+ final List <ui.Radius > radii = < ui.Radius > [];
238+ final PathRefIterator iter = PathRefIterator (this );
239+ final Float32List pts = Float32List (PathRefIterator .kMaxBufferSize);
240+ int verb = iter.next (pts);
241+ assert (SPath .kMoveVerb == verb);
242+ int cornerIndex = 0 ;
243+ while ((verb = iter.next (pts)) != SPath .kDoneVerb) {
244+ if (SPath .kConicVerb == verb) {
245+ final double controlPx = pts[2 ];
246+ final double controlPy = pts[3 ];
247+ double vector1_0x = controlPx - pts[0 ];
248+ double vector1_0y = controlPy - pts[1 ];
249+ double vector2_1x = pts[4 ] - pts[2 ];
250+ double vector2_1y = pts[5 ] - pts[3 ];
251+ double dx, dy;
252+ // Depending on the corner we have control point at same
253+ // horizontal position as startpoint or same vertical position.
254+ // The location delta of control point specifies corner radius.
255+ if (vector1_0x != 0.0 ) {
256+ // For CW : Top right or bottom left corners.
257+ assert (vector2_1x == 0.0 && vector1_0y == 0.0 );
258+ dx = vector1_0x.abs ();
259+ dy = vector2_1y.abs ();
260+ } else if (vector1_0y != 0.0 ) {
261+ assert (vector2_1x == 0.0 || vector2_1y == 0.0 );
262+ dx = vector2_1x.abs ();
263+ dy = vector1_0y.abs ();
264+ } else {
265+ assert (vector2_1y == 0.0 );
266+ dx = vector1_0x.abs ();
267+ dy = vector1_0y.abs ();
268+ }
269+ if (assertionsEnabled) {
270+ final int checkCornerIndex = _nearlyEqual (controlPx, bounds.left)
271+ ? (_nearlyEqual (controlPy, bounds.top)
272+ ? _Corner .kUpperLeft
273+ : _Corner .kLowerLeft)
274+ : (_nearlyEqual (controlPy, bounds.top)
275+ ? _Corner .kUpperRight
276+ : _Corner .kLowerRight);
277+ assert (checkCornerIndex == cornerIndex);
278+ }
279+ radii.add (ui.Radius .elliptical (dx, dy));
280+ ++ cornerIndex;
281+ } else {
282+ assert ((verb == SPath .kLineVerb &&
283+ ((pts[2 ] - pts[0 ]) == 0 || (pts[3 ] - pts[1 ]) == 0 )) ||
284+ verb == SPath .kCloseVerb);
285+ }
286+ }
287+ return ui.RRect .fromRectAndCorners (bounds,
288+ topLeft: radii[_Corner .kUpperLeft],
289+ topRight: radii[_Corner .kUpperRight],
290+ bottomRight: radii[_Corner .kLowerRight],
291+ bottomLeft: radii[_Corner .kLowerLeft]);
292+ }
293+
230294 bool operator == (Object other) {
231295 if (identical (this , other)) {
232296 return true ;
@@ -330,7 +394,7 @@ class PathRef {
330394 }
331395 fSegmentMask = source.fSegmentMask;
332396 fIsOval = source.fIsOval;
333- rrectRepresentation = source.rrectRepresentation ;
397+ fIsRRect = source.fIsRRect ;
334398 fIsRect = source.fIsRect;
335399 fRRectOrOvalIsCCW = source.fRRectOrOvalIsCCW;
336400 fRRectOrOvalStartIdx = source.fRRectOrOvalStartIdx;
@@ -363,7 +427,7 @@ class PathRef {
363427 }
364428 fSegmentMask = ref.fSegmentMask;
365429 fIsOval = ref.fIsOval;
366- rrectRepresentation = ref.rrectRepresentation ;
430+ fIsRRect = ref.fIsRRect ;
367431 fIsRect = ref.fIsRect;
368432 fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW;
369433 fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx;
@@ -714,7 +778,7 @@ class PathRef {
714778 /// points are added.
715779 void startEdit () {
716780 fIsOval = false ;
717- rrectRepresentation = null ;
781+ fIsRRect = false ;
718782 fIsRect = false ;
719783 cachedBounds = null ;
720784 fBoundsIsDirty = true ;
@@ -727,11 +791,7 @@ class PathRef {
727791 }
728792
729793 void setIsRRect (bool isRRect, bool isCCW, int start, ui.RRect rrect) {
730- if (isRRect) {
731- rrectRepresentation = rrect;
732- } else {
733- rrectRepresentation = null ;
734- }
794+ fIsRRect = isRRect;
735795 fRRectOrOvalIsCCW = isCCW;
736796 fRRectOrOvalStartIdx = start;
737797 }
@@ -753,11 +813,7 @@ class PathRef {
753813 bool fIsFinite = true ; // only meaningful if bounds are valid
754814
755815 bool fIsOval = false ;
756-
757- /// If the path is made of a single `RRect` , this field contains the original
758- /// `RRect` that was added to the path.
759- ui.RRect ? rrectRepresentation;
760-
816+ bool fIsRRect = false ;
761817 bool fIsRect = false ;
762818 // Both the circle and rrect special cases have a notion of direction and starting point
763819 // The next two variables store that information for either.
@@ -766,9 +822,9 @@ class PathRef {
766822 int fSegmentMask = 0 ;
767823
768824 bool get isValid {
769- if (fIsOval || rrectRepresentation != null ) {
825+ if (fIsOval || fIsRRect ) {
770826 // Currently we don't allow both of these to be set.
771- if (fIsOval == (rrectRepresentation != null ) ) {
827+ if (fIsOval == fIsRRect ) {
772828 return false ;
773829 }
774830 if (fIsOval) {
@@ -782,7 +838,7 @@ class PathRef {
782838 }
783839 }
784840 if (fIsRect) {
785- if (fIsOval || (rrectRepresentation != null ) ) {
841+ if (fIsOval || fIsRRect ) {
786842 return false ;
787843 }
788844 if (fRRectOrOvalStartIdx >= 4 ) {
@@ -1008,3 +1064,10 @@ class PathRefIterator {
10081064 ? pathRef._fVerbs[_verbIndex]
10091065 : SPath .kDoneVerb;
10101066}
1067+
1068+ class _Corner {
1069+ static const int kUpperLeft = 0 ;
1070+ static const int kUpperRight = 1 ;
1071+ static const int kLowerRight = 2 ;
1072+ static const int kLowerLeft = 3 ;
1073+ }
0 commit comments