mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Improve check to render (or not) a DRRect when inner falls outside of outer on RecordingCanvas (flutter/engine#12229)
* Improve check to determine if a rrect is fully contained within another in RecordingCanvas. * Add unit tests. Fixes https://github.com/flutter/flutter/issues/37772 (and others)
This commit is contained in:
parent
36107f11b8
commit
0d2e83cde2
@ -7,6 +7,9 @@ part of engine;
|
||||
/// Enable this to print every command applied by a canvas.
|
||||
const bool _debugDumpPaintCommands = false;
|
||||
|
||||
// Similar to [Offset.distance]
|
||||
double _getDistance(double x, double y) => math.sqrt(x * x + y * y);
|
||||
|
||||
/// Records canvas commands to be applied to a [EngineCanvas].
|
||||
///
|
||||
/// See [Canvas] for docs for these methods.
|
||||
@ -228,12 +231,31 @@ class RecordingCanvas {
|
||||
}
|
||||
|
||||
void drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) {
|
||||
// If inner rect is not contained inside outer, flutter engine skips
|
||||
// painting rectangle.
|
||||
if (!(outer.contains(ui.Offset(inner.left, inner.top)) &&
|
||||
outer.contains(ui.Offset(inner.right, inner.bottom)))) {
|
||||
return;
|
||||
// Ensure inner is fully contained within outer, by comparing its
|
||||
// defining points (including its border radius)
|
||||
ui.Rect innerRect = inner.outerRect;
|
||||
if (outer.outerRect.intersect(innerRect) != innerRect) {
|
||||
return; // inner is not fully contained within outer
|
||||
}
|
||||
|
||||
// Compare radius "length" of the rectangles that are going to be actually drawn
|
||||
final ui.RRect scaledOuter = outer.scaleRadii();
|
||||
final ui.RRect scaledInner = inner.scaleRadii();
|
||||
|
||||
final double outerTl = _getDistance(scaledOuter.tlRadiusX, scaledOuter.tlRadiusY);
|
||||
final double outerTr = _getDistance(scaledOuter.trRadiusX, scaledOuter.trRadiusY);
|
||||
final double outerBl = _getDistance(scaledOuter.blRadiusX, scaledOuter.blRadiusY);
|
||||
final double outerBr = _getDistance(scaledOuter.brRadiusX, scaledOuter.brRadiusY);
|
||||
|
||||
final double innerTl = _getDistance(scaledInner.tlRadiusX, scaledInner.tlRadiusY);
|
||||
final double innerTr = _getDistance(scaledInner.trRadiusX, scaledInner.trRadiusY);
|
||||
final double innerBl = _getDistance(scaledInner.blRadiusX, scaledInner.blRadiusY);
|
||||
final double innerBr = _getDistance(scaledInner.brRadiusX, scaledInner.brRadiusY);
|
||||
|
||||
if (innerTl >= outerTl || innerTr >= outerTr || innerBl >= outerBl || innerBr >= outerBr) {
|
||||
return; // Some inner radius is overlapping some outer radius
|
||||
}
|
||||
|
||||
_hasArbitraryPaint = true;
|
||||
_didDraw = true;
|
||||
final double strokeWidth =
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
// 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 'package:ui/ui.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../mock_engine_canvas.dart';
|
||||
|
||||
void main() {
|
||||
|
||||
RecordingCanvas underTest;
|
||||
MockEngineCanvas mockCanvas;
|
||||
|
||||
setUp(() {
|
||||
underTest = RecordingCanvas(Rect.largest);
|
||||
mockCanvas = MockEngineCanvas();
|
||||
});
|
||||
|
||||
group('drawDRRect', () {
|
||||
final RRect rrect = RRect.fromLTRBR(10, 10, 50, 50, Radius.circular(3));
|
||||
final Paint somePaint = Paint()..color = const Color(0xFFFF0000);
|
||||
|
||||
test('Happy case', () {
|
||||
underTest.drawDRRect(rrect, rrect.deflate(1), somePaint);
|
||||
underTest.apply(mockCanvas);
|
||||
// Expect drawDRRect to be called
|
||||
expect(mockCanvas.methodCallLog.length, equals(1));
|
||||
MockCanvasCall mockCall = mockCanvas.methodCallLog[0];
|
||||
expect(mockCall.methodName, equals('drawDRRect'));
|
||||
expect(mockCall.arguments, equals({
|
||||
'outer': rrect,
|
||||
'inner': rrect.deflate(1),
|
||||
'paint': somePaint.webOnlyPaintData,
|
||||
}));
|
||||
});
|
||||
|
||||
test('Inner RRect > Outer RRect', () {
|
||||
underTest.drawDRRect(rrect, rrect.inflate(1), somePaint);
|
||||
underTest.apply(mockCanvas);
|
||||
// Expect nothing to be called
|
||||
expect(mockCanvas.methodCallLog.length, equals(0));
|
||||
});
|
||||
|
||||
test('Inner RRect not completely inside Outer RRect', () {
|
||||
underTest.drawDRRect(rrect, rrect.deflate(1).shift(const Offset(0.0, 10)), somePaint);
|
||||
underTest.apply(mockCanvas);
|
||||
// Expect nothing to be called
|
||||
expect(mockCanvas.methodCallLog.length, equals(0));
|
||||
});
|
||||
|
||||
test('Inner RRect same as Outer RRect', () {
|
||||
underTest.drawDRRect(rrect, rrect, somePaint);
|
||||
underTest.apply(mockCanvas);
|
||||
// Expect nothing to be called
|
||||
expect(mockCanvas.methodCallLog.length, equals(0));
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user