Implementation
@override
List<Radius>? get borderRadius {
final TextDirection currentDirection = direction;
final CSSWritingMode currentWritingMode = writingMode;
CSSBorderRadius? tl = _borderTopLeftRadius;
CSSBorderRadius? tr = _borderTopRightRadius;
CSSBorderRadius? br = _borderBottomRightRadius;
CSSBorderRadius? bl = _borderBottomLeftRadius;
void applyLogical(CSSBorderRadius? logical, int physicalCorner) {
if (logical == null) return;
switch (physicalCorner) {
case 0:
tl ??= logical;
break;
case 1:
tr ??= logical;
break;
case 2:
br ??= logical;
break;
case 3:
bl ??= logical;
break;
}
}
applyLogical(_borderStartStartRadius, _resolveStartStartCorner(currentDirection, currentWritingMode));
applyLogical(_borderStartEndRadius, _resolveStartEndCorner(currentDirection, currentWritingMode));
applyLogical(_borderEndStartRadius, _resolveEndStartCorner(currentDirection, currentWritingMode));
applyLogical(_borderEndEndRadius, _resolveEndEndCorner(currentDirection, currentWritingMode));
// Fast path: if all corners are zero, no radii.
final CSSBorderRadius tlResolved = tl ?? CSSBorderRadius.zero;
final CSSBorderRadius trResolved = tr ?? CSSBorderRadius.zero;
final CSSBorderRadius brResolved = br ?? CSSBorderRadius.zero;
final CSSBorderRadius blResolved = bl ?? CSSBorderRadius.zero;
final bool hasAnyRadius = !(tlResolved == CSSBorderRadius.zero &&
trResolved == CSSBorderRadius.zero &&
brResolved == CSSBorderRadius.zero &&
blResolved == CSSBorderRadius.zero);
if (!hasAnyRadius) return null;
// Cache to avoid recomputing per paint phase.
// When any axis uses percentages, the result depends on the border box size.
final bool tlPct = tlResolved.x.isPercentage || tlResolved.y.isPercentage;
final bool trPct = trResolved.x.isPercentage || trResolved.y.isPercentage;
final bool brPct = brResolved.x.isPercentage || brResolved.y.isPercentage;
final bool blPct = blResolved.x.isPercentage || blResolved.y.isPercentage;
final bool anyPct = tlPct || trPct || brPct || blPct;
final double? bw = borderBoxWidth ?? borderBoxLogicalWidth;
final double? bh = borderBoxHeight ?? borderBoxLogicalHeight;
// Reuse cached radii when inputs are identical and the size anchor (for %) is unchanged.
if (_cachedComputedBorderRadius != null &&
_cachedBorderRadiusDirection == currentDirection &&
_cachedBorderRadiusWritingMode == currentWritingMode &&
identical(_cachedTLRef, _borderTopLeftRadius) &&
identical(_cachedTRRef, _borderTopRightRadius) &&
identical(_cachedBRRef, _borderBottomRightRadius) &&
identical(_cachedBLRef, _borderBottomLeftRadius) &&
identical(_cachedStartStartRef, _borderStartStartRadius) &&
identical(_cachedStartEndRef, _borderStartEndRadius) &&
identical(_cachedEndStartRef, _borderEndStartRadius) &&
identical(_cachedEndEndRef, _borderEndEndRadius) &&
(!anyPct || (_cachedBorderRadiusW == bw && _cachedBorderRadiusH == bh))) {
return _cachedComputedBorderRadius;
}
final radii = <Radius>[
tlResolved.computedRadius,
trResolved.computedRadius,
brResolved.computedRadius,
blResolved.computedRadius,
];
_cachedComputedBorderRadius = radii;
_cachedBorderRadiusW = anyPct ? bw : _cachedBorderRadiusW; // only bind size when needed
_cachedBorderRadiusH = anyPct ? bh : _cachedBorderRadiusH;
_cachedTLRef = _borderTopLeftRadius;
_cachedTRRef = _borderTopRightRadius;
_cachedBRRef = _borderBottomRightRadius;
_cachedBLRef = _borderBottomLeftRadius;
_cachedStartStartRef = _borderStartStartRadius;
_cachedStartEndRef = _borderStartEndRadius;
_cachedEndStartRef = _borderEndStartRadius;
_cachedEndEndRef = _borderEndEndRadius;
_cachedBorderRadiusDirection = currentDirection;
_cachedBorderRadiusWritingMode = currentWritingMode;
if (DebugFlags.enableBorderRadiusLogs) {
try {
final el = target;
renderingLogger.finer('[BorderRadius] compute for <${el.tagName.toLowerCase()}> '
'borderBox=${(bw)?.toStringAsFixed(2) ?? 'null'}×${(bh)?.toStringAsFixed(2) ?? 'null'} '
'tl=(${radii[0].x.toStringAsFixed(2)},${radii[0].y.toStringAsFixed(2)}) '
'tr=(${radii[1].x.toStringAsFixed(2)},${radii[1].y.toStringAsFixed(2)}) '
'br=(${radii[2].x.toStringAsFixed(2)},${radii[2].y.toStringAsFixed(2)}) '
'bl=(${radii[3].x.toStringAsFixed(2)},${radii[3].y.toStringAsFixed(2)})');
} catch (_) {}
}
return radii;
}