Unverified Commit 80d6095d authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Fix ShapeDecoration (#14009)

And add a test that catches these problems.
parent e8b66624
......@@ -596,12 +596,12 @@ class _CompoundBorder extends ShapeBorder {
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
for (int index = 0; index < borders.length - 1; index += 1)
rect = borders[index].dimensions.resolve(textDirection).deflateRect(rect);
return borders.last.getInnerPath(rect);
return borders.last.getInnerPath(rect, textDirection: textDirection);
}
@override
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
return borders.first.getOuterPath(rect);
return borders.first.getOuterPath(rect, textDirection: textDirection);
}
@override
......
......@@ -25,7 +25,7 @@ class CircleBorder extends ShapeBorder {
/// Create a circle border.
///
/// The [side] argument must not be null.
const CircleBorder({ this.side = BorderSide.none }) : assert(side != null);
const CircleBorder({ this.side: BorderSide.none }) : assert(side != null);
/// The style of this border.
final BorderSide side;
......
......@@ -162,6 +162,11 @@ abstract class Decoration extends Diagnosticable {
/// `textDirection` argument should therefore be provided. If it is known that
/// the decoration is not affected by the text direction, then the argument
/// may be omitted or set to null.
///
/// When a [Decoration] is painted in a [Container] or [DecoratedBox] (which
/// is what [Container] uses), the `textDirection` parameter will be populated
/// based on the ambient [Directionality] (by way of the [RenderDecoratedBox]
/// renderer).
bool hitTest(Size size, Offset position, { TextDirection textDirection }) => true;
/// Returns a [BoxPainter] that will paint this decoration.
......@@ -207,6 +212,10 @@ abstract class BoxPainter {
/// Implementations should paint their decorations on the canvas in a
/// rectangle whose top left corner is at the given `offset` and whose size is
/// given by `configuration.size`.
///
/// When a [Decoration] is painted in a [Container] or [DecoratedBox] (which
/// is what [Container] uses), the [ImageConfiguration.textDirection] property
/// will be populated based on the ambient [Directionality].
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration);
/// Callback that is invoked if an asynchronously-loading resource used by the
......
......@@ -118,7 +118,7 @@ class ImageConfiguration {
if (devicePixelRatio != null) {
if (hasArguments)
result.write(', ');
result.write('devicePixelRatio: $devicePixelRatio');
result.write('devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}');
hasArguments = true;
}
if (locale != null) {
......
......@@ -323,13 +323,13 @@ class _ShapeDecorationPainter extends BoxPainter {
}
for (int index = 0; index < _shadowCount; index += 1) {
final BoxShadow shadow = _decoration.shadows[index];
_shadowPaths[index] = _decoration.shape.getOuterPath(rect.shift(shadow.offset).inflate(shadow.spreadRadius));
_shadowPaths[index] = _decoration.shape.getOuterPath(rect.shift(shadow.offset).inflate(shadow.spreadRadius), textDirection: textDirection);
}
}
if (_interiorPaint != null || _shadowCount != null)
_outerPath = _decoration.shape.getOuterPath(rect);
_outerPath = _decoration.shape.getOuterPath(rect, textDirection: textDirection);
if (_decoration.image != null)
_innerPath = _decoration.shape.getInnerPath(rect);
_innerPath = _decoration.shape.getInnerPath(rect, textDirection: textDirection);
_lastRect = rect;
_lastTextDirection = textDirection;
......
......@@ -24,9 +24,10 @@ class TestImageInfo implements ImageInfo {
}
class TestImageProvider extends ImageProvider<int> {
const TestImageProvider(this.key, this.imageValue);
const TestImageProvider(this.key, this.imageValue, { this.image });
final int key;
final int imageValue;
final ui.Image image;
@override
Future<int> obtainKey(ImageConfiguration configuration) {
......@@ -36,7 +37,7 @@ class TestImageProvider extends ImageProvider<int> {
@override
ImageStreamCompleter load(int key) {
return new OneFrameImageStreamCompleter(
new SynchronousFuture<ImageInfo>(new TestImageInfo(imageValue))
new SynchronousFuture<ImageInfo>(new TestImageInfo(imageValue, image: image))
);
}
......
// Copyright 2018 The Chromium 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 'dart:ui' as ui show Image;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../painting/image_data.dart';
import '../painting/mocks_for_image_cache.dart';
import '../rendering/mock_canvas.dart';
Future<Null> main() async {
final ui.Image rawImage = await decodeImageFromList(new Uint8List.fromList(kTransparentImage));
final ImageProvider image = new TestImageProvider(0, 0, image: rawImage);
testWidgets('ShapeDecoration.image', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
home: new DecoratedBox(
decoration: new ShapeDecoration(
shape: new Border.all(width: 1.0, color: Colors.white) +
new Border.all(width: 1.0, color: Colors.black),
image: new DecorationImage(
image: image,
),
),
),
),
);
expect(
find.byType(DecoratedBox),
paints
..drawImageRect(image: rawImage)
..rect(color: Colors.black)
..rect(color: Colors.white)
);
});
testWidgets('ShapeDecoration.color', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
home: new DecoratedBox(
decoration: new ShapeDecoration(
shape: new Border.all(width: 1.0, color: Colors.white) +
new Border.all(width: 1.0, color: Colors.black),
color: Colors.blue,
),
),
),
);
expect(
find.byType(DecoratedBox),
paints
..path(color: new Color(Colors.blue.value))
..rect(color: Colors.black)
..rect(color: Colors.white)
);
});
testWidgets('TestBorder and Directionality - 1', (WidgetTester tester) async {
final List<String> log = <String>[];
await tester.pumpWidget(
new MaterialApp(
home: new DecoratedBox(
decoration: new ShapeDecoration(
shape: new TestBorder(log.add),
color: Colors.green,
),
),
),
);
expect(
log,
<String>[
'getOuterPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.ltr',
'paint Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.ltr'
],
);
});
testWidgets('TestBorder and Directionality - 2', (WidgetTester tester) async {
final List<String> log = <String>[];
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.rtl,
child: new DecoratedBox(
decoration: new ShapeDecoration(
shape: new TestBorder(log.add),
image: new DecorationImage(
image: image,
),
),
),
),
);
expect(
log,
<String>[
'getInnerPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.rtl',
'paint Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.rtl'
],
);
});
}
typedef void Logger(String caller);
class TestBorder extends ShapeBorder {
const TestBorder(this.onLog) : assert(onLog != null);
final Logger onLog;
@override
EdgeInsetsGeometry get dimensions => const EdgeInsetsDirectional.only(start: 1.0);
@override
ShapeBorder scale(double t) => new TestBorder(onLog);
@override
Path getInnerPath(Rect rect, { TextDirection textDirection }) {
onLog('getInnerPath $rect $textDirection');
return new Path();
}
@override
Path getOuterPath(Rect rect, { TextDirection textDirection }) {
onLog('getOuterPath $rect $textDirection');
return new Path();
}
@override
void paint(Canvas canvas, Rect rect, { TextDirection textDirection }) {
onLog('paint $rect $textDirection');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment