未验证 提交 f581f428 编写于 作者: Y Yegor 提交者: GitHub

nullability clean-ups (#18880)

* nullability clean-ups
上级 9d60a3fa
......@@ -454,7 +454,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/plugins.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_binding.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_converter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/profiler.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/render_vertices.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/rrect_renderer.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart
......@@ -474,6 +473,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/shader.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/backdrop_filter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/clip.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/debug_canvas_reuse_overlay.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/image_filter.dart
......@@ -485,6 +485,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/path_metrics.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/platform_view.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/recording_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/render_vertices.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/scene.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/scene_builder.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/surface.dart
......
......@@ -314,15 +314,21 @@ class Offset extends OffsetBase {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Offset/*!*/ lerp(Offset/*?*/ a, Offset/*?*/ b, double/*!*/ t) {
static Offset/*?*/ lerp(Offset/*?*/ a, Offset/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return Offset(lerpDouble(a.dx, b.dx, t), lerpDouble(a.dy, b.dy, t));
if (b == null) {
if (a == null) {
return null;
} else {
return a * (1.0 - t);
}
} else {
if (a == null) {
return b * t;
} else {
return Offset(_lerpDouble(a.dx, b.dx, t), _lerpDouble(a.dy, b.dy, t));
}
}
}
/// Compares two Offsets for equality.
......@@ -579,15 +585,21 @@ class Size extends OffsetBase {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Size/*!*/ lerp(Size/*?*/ a, Size/*?*/ b, double/*!*/ t) {
static Size/*?*/ lerp(Size/*?*/ a, Size/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return Size(lerpDouble(a.width, b.width, t), lerpDouble(a.height, b.height, t));
if (b == null) {
if (a == null) {
return null;
} else {
return a * (1.0 - t);
}
} else {
if (a == null) {
return b * t;
} else {
return Size(_lerpDouble(a.width, b.width, t), _lerpDouble(a.height, b.height, t));
}
}
}
/// Compares two Sizes for equality.
......@@ -850,22 +862,27 @@ class Rect {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Rect/*!*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) {
static Rect/*?*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
if (b == null) {
final double k = 1.0 - t;
return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
}
} else {
if (a == null) {
return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
} else {
return Rect.fromLTRB(
_lerpDouble(a.left, b.left, t),
_lerpDouble(a.top, b.top, t),
_lerpDouble(a.right, b.right, t),
_lerpDouble(a.bottom, b.bottom, t),
);
}
}
return Rect.fromLTRB(
lerpDouble(a.left, b.left, t),
lerpDouble(a.top, b.top, t),
lerpDouble(a.right, b.right, t),
lerpDouble(a.bottom, b.bottom, t),
);
}
@override
......@@ -974,20 +991,25 @@ class Radius {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Radius/*!*/ lerp(Radius/*?*/ a, Radius/*?*/ b, double/*!*/ t) {
static Radius/*?*/ lerp(Radius/*?*/ a, Radius/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return Radius.elliptical(b.x * t, b.y * t);
if (b == null) {
final double k = 1.0 - t;
return Radius.elliptical(a.x * k, a.y * k);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return Radius.elliptical(a.x * k, a.y * k);
}
} else {
if (a == null) {
return Radius.elliptical(b.x * t, b.y * t);
} else {
return Radius.elliptical(
_lerpDouble(a.x, b.x, t),
_lerpDouble(a.y, b.y, t),
);
}
}
return Radius.elliptical(
lerpDouble(a.x, b.x, t),
lerpDouble(a.y, b.y, t),
);
}
@override
......@@ -1534,57 +1556,61 @@ class RRect {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static RRect/*!*/ lerp(RRect/*?*/ a, RRect/*?*/ b, double/*!*/ t) {
static RRect/*?*/ lerp(RRect/*?*/ a, RRect/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null) {
return RRect._raw(
left: b.left * t,
top: b.top * t,
right: b.right * t,
bottom: b.bottom * t,
tlRadiusX: b.tlRadiusX * t,
tlRadiusY: b.tlRadiusY * t,
trRadiusX: b.trRadiusX * t,
trRadiusY: b.trRadiusY * t,
brRadiusX: b.brRadiusX * t,
brRadiusY: b.brRadiusY * t,
blRadiusX: b.blRadiusX * t,
blRadiusY: b.blRadiusY * t,
);
}
if (b == null) {
final double k = 1.0 - t;
return RRect._raw(
left: a.left * k,
top: a.top * k,
right: a.right * k,
bottom: a.bottom * k,
tlRadiusX: a.tlRadiusX * k,
tlRadiusY: a.tlRadiusY * k,
trRadiusX: a.trRadiusX * k,
trRadiusY: a.trRadiusY * k,
brRadiusX: a.brRadiusX * k,
brRadiusY: a.brRadiusY * k,
blRadiusX: a.blRadiusX * k,
blRadiusY: a.blRadiusY * k,
);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return RRect._raw(
left: a.left * k,
top: a.top * k,
right: a.right * k,
bottom: a.bottom * k,
tlRadiusX: a.tlRadiusX * k,
tlRadiusY: a.tlRadiusY * k,
trRadiusX: a.trRadiusX * k,
trRadiusY: a.trRadiusY * k,
brRadiusX: a.brRadiusX * k,
brRadiusY: a.brRadiusY * k,
blRadiusX: a.blRadiusX * k,
blRadiusY: a.blRadiusY * k,
);
}
} else {
if (a == null) {
return RRect._raw(
left: b.left * t,
top: b.top * t,
right: b.right * t,
bottom: b.bottom * t,
tlRadiusX: b.tlRadiusX * t,
tlRadiusY: b.tlRadiusY * t,
trRadiusX: b.trRadiusX * t,
trRadiusY: b.trRadiusY * t,
brRadiusX: b.brRadiusX * t,
brRadiusY: b.brRadiusY * t,
blRadiusX: b.blRadiusX * t,
blRadiusY: b.blRadiusY * t,
);
} else {
return RRect._raw(
left: _lerpDouble(a.left, b.left, t),
top: _lerpDouble(a.top, b.top, t),
right: _lerpDouble(a.right, b.right, t),
bottom: _lerpDouble(a.bottom, b.bottom, t),
tlRadiusX: _lerpDouble(a.tlRadiusX, b.tlRadiusX, t),
tlRadiusY: _lerpDouble(a.tlRadiusY, b.tlRadiusY, t),
trRadiusX: _lerpDouble(a.trRadiusX, b.trRadiusX, t),
trRadiusY: _lerpDouble(a.trRadiusY, b.trRadiusY, t),
brRadiusX: _lerpDouble(a.brRadiusX, b.brRadiusX, t),
brRadiusY: _lerpDouble(a.brRadiusY, b.brRadiusY, t),
blRadiusX: _lerpDouble(a.blRadiusX, b.blRadiusX, t),
blRadiusY: _lerpDouble(a.blRadiusY, b.blRadiusY, t),
);
}
}
return RRect._raw(
left: lerpDouble(a.left, b.left, t),
top: lerpDouble(a.top, b.top, t),
right: lerpDouble(a.right, b.right, t),
bottom: lerpDouble(a.bottom, b.bottom, t),
tlRadiusX: lerpDouble(a.tlRadiusX, b.tlRadiusX, t),
tlRadiusY: lerpDouble(a.tlRadiusY, b.tlRadiusY, t),
trRadiusX: lerpDouble(a.trRadiusX, b.trRadiusX, t),
trRadiusY: lerpDouble(a.trRadiusY, b.trRadiusY, t),
brRadiusX: lerpDouble(a.brRadiusX, b.brRadiusX, t),
brRadiusY: lerpDouble(a.brRadiusY, b.brRadiusY, t),
blRadiusX: lerpDouble(a.blRadiusX, b.blRadiusX, t),
blRadiusY: lerpDouble(a.blRadiusY, b.blRadiusY, t),
);
}
@override
......
......@@ -112,7 +112,7 @@ int/*!*/ hashValues(
/// Combine the [Object.hashCode] values of an arbitrary number of objects from
/// an [Iterable] into one value. This function will return the same value if
/// given null as if given an empty list.
int/*!*/ hashList(Iterable<Object/*?*/>/*!*/ arguments) {
int/*!*/ hashList(Iterable<Object/*?*/>/*?*/ arguments) {
int result = 0;
if (arguments != null) {
for (Object argument in arguments)
......
......@@ -13,3 +13,29 @@ double/*!*/ lerpDouble(num/*?*/ a, num/*?*/ b, double/*!*/ t) {
b ??= 0.0;
return a + (b - a) * t as double;
}
/// Linearly interpolate between two doubles.
///
/// Same as [lerpDouble] but specialized for non-null `double` type.
double/*!*/ _lerpDouble(double/*!*/ a, double/*!*/ b, double/*!*/ t) {
return a + (b - a) * t;
}
/// Linearly interpolate between two integers.
///
/// Same as [lerpDouble] but specialized for non-null `int` type.
double/*!*/ _lerpInt(int/*!*/ a, int/*!*/ b, double/*!*/ t) {
return a + (b - a) * t;
}
/// Same as [num.clamp] but specialized for non-null [int].
int/*!*/ _clampInt(int/*!*/ value, int/*!*/ min, int/*!*/ max) {
assert(min <= max);
if (value < min) {
return min;
} else if (value > max) {
return max;
} else {
return value;
}
}
......@@ -259,18 +259,24 @@ class Color {
/// an [AnimationController].
static Color/*?*/ lerp(Color/*?*/ a, Color/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return _scaleAlpha(b, t);
if (b == null)
return _scaleAlpha(a, 1.0 - t);
return Color.fromARGB(
lerpDouble(a.alpha, b.alpha, t).toInt().clamp(0, 255) as int,
lerpDouble(a.red, b.red, t).toInt().clamp(0, 255) as int,
lerpDouble(a.green, b.green, t).toInt().clamp(0, 255) as int,
lerpDouble(a.blue, b.blue, t).toInt().clamp(0, 255) as int,
);
if (b == null) {
if (a == null) {
return null;
} else {
return _scaleAlpha(a, 1.0 - t);
}
} else {
if (a == null) {
return _scaleAlpha(b, t);
} else {
return Color.fromARGB(
_clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255),
);
}
}
}
/// Combine the foreground color as a transparent color over top
......@@ -4288,17 +4294,23 @@ class Shadow {
/// {@endtemplate}
static Shadow/*?*/ lerp(Shadow/*?*/ a, Shadow/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b.scale(t);
if (b == null)
return a.scale(1.0 - t);
return Shadow(
color: Color.lerp(a.color, b.color, t),
offset: Offset.lerp(a.offset, b.offset, t),
blurRadius: lerpDouble(a.blurRadius, b.blurRadius, t),
);
if (b == null) {
if (a == null) {
return null;
} else {
return a.scale(1.0 - t);
}
} else {
if (a == null) {
return b.scale(t);
} else {
return Shadow(
color: Color.lerp(a.color, b.color, t),
offset: Offset.lerp(a.offset, b.offset, t),
blurRadius: lerpDouble(a.blurRadius, b.blurRadius, t),
);
}
}
}
/// Linearly interpolate between two lists of shadows.
......
......@@ -70,7 +70,6 @@ part 'engine/plugins.dart';
part 'engine/pointer_binding.dart';
part 'engine/pointer_converter.dart';
part 'engine/profiler.dart';
part 'engine/render_vertices.dart';
part 'engine/rrect_renderer.dart';
part 'engine/semantics/accessibility.dart';
part 'engine/semantics/checkable.dart';
......@@ -90,6 +89,7 @@ part 'engine/services/serialization.dart';
part 'engine/shader.dart';
part 'engine/shadow.dart';
part 'engine/surface/backdrop_filter.dart';
part 'engine/surface/canvas.dart';
part 'engine/surface/clip.dart';
part 'engine/surface/debug_canvas_reuse_overlay.dart';
part 'engine/surface/image_filter.dart';
......@@ -100,6 +100,7 @@ part 'engine/surface/path_metrics.dart';
part 'engine/surface/picture.dart';
part 'engine/surface/platform_view.dart';
part 'engine/surface/recording_canvas.dart';
part 'engine/surface/render_vertices.dart';
part 'engine/surface/scene.dart';
part 'engine/surface/scene_builder.dart';
part 'engine/surface/surface.dart';
......
......@@ -761,20 +761,20 @@ class BitmapCanvas extends EngineCanvas {
/// and use a SkTriColorShader to render.
@override
void drawVertices(
ui.Vertices vertices, ui.BlendMode blendMode, SurfacePaintData paint) {
SurfaceVertices vertices, ui.BlendMode blendMode, SurfacePaintData paint) {
// TODO(flutter_web): Implement shaders for [Paint.shader] and
// blendMode. https://github.com/flutter/flutter/issues/40096
// Move rendering to OffscreenCanvas so that transform is preserved
// as well.
assert(paint.shader == null,
'Linear/Radial/SweepGradient and ImageShader not supported yet');
final Int32List colors = vertices.colors;
final ui.VertexMode mode = vertices.mode;
final Int32List colors = vertices._colors;
final ui.VertexMode mode = vertices._mode;
html.CanvasRenderingContext2D ctx = _canvasPool.context;
if (colors == null) {
final Float32List positions = mode == ui.VertexMode.triangles
? vertices.positions
: _convertVertexPositions(mode, vertices.positions);
? vertices._positions
: _convertVertexPositions(mode, vertices._positions);
// Draw hairline for vertices if no vertex colors are specified.
save();
final ui.Color color = paint.color ?? ui.Color(0xFF000000);
......
......@@ -15,7 +15,7 @@ class SkPictureRecorder implements ui.PictureRecorder {
_recorder = js.JsObject(canvasKit['SkPictureRecorder']);
final js.JsObject skRect = js.JsObject(canvasKit['LTRBRect'],
<double>[bounds.left, bounds.top, bounds.right, bounds.bottom]);
final js.JsObject skCanvas =
final js.JsObject/*!*/ skCanvas =
_recorder.callMethod('beginRecording', <js.JsObject>[skRect]);
_recordingCanvas = SkCanvas(skCanvas);
return _recordingCanvas;
......
......@@ -158,7 +158,7 @@ class SkSurface {
SkSurface(this._surface, this._glContext);
SkCanvas getCanvas() {
final js.JsObject skCanvas = _surface.callMethod('getCanvas');
final js.JsObject/*!*/ skCanvas = _surface.callMethod('getCanvas');
return SkCanvas(skCanvas);
}
......
......@@ -110,17 +110,4 @@ class SkVertices implements ui.Vertices {
return false;
}
}
@override
Int32List get colors => null;
@override
Float32List get positions => null;
@override
ui.VertexMode get mode => null;
Float32List get textureCoordinates => null;
Uint16List get indices => null;
}
......@@ -68,7 +68,7 @@ abstract class EngineCanvas {
void drawParagraph(EngineParagraph paragraph, ui.Offset offset);
void drawVertices(
ui.Vertices vertices, ui.BlendMode blendMode, SurfacePaintData paint);
SurfaceVertices vertices, ui.BlendMode blendMode, SurfacePaintData paint);
void drawPoints(ui.PointMode pointMode, Float32List points, SurfacePaintData paint);
......
// 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.
// @dart = 2.6
part of engine;
class SurfaceCanvas implements ui.Canvas {
RecordingCanvas/*!*/ _canvas;
SurfaceCanvas(EnginePictureRecorder recorder, [ui.Rect cullRect])
: assert(recorder != null) {
if (recorder.isRecording) {
throw ArgumentError(
'"recorder" must not already be associated with another Canvas.');
}
cullRect ??= ui.Rect.largest;
_canvas = recorder.beginRecording(cullRect);
}
@override
void save() {
_canvas.save();
}
@override
void saveLayer(ui.Rect/*?*/ bounds, ui.Paint/*!*/ paint) {
assert(paint != null);
if (bounds == null) {
_saveLayerWithoutBounds(paint);
} else {
assert(rectIsValid(bounds));
_saveLayer(bounds, paint);
}
}
void _saveLayerWithoutBounds(ui.Paint paint) {
_canvas.saveLayerWithoutBounds(paint);
}
void _saveLayer(ui.Rect bounds, ui.Paint paint) {
_canvas.saveLayer(bounds, paint);
}
@override
void restore() {
_canvas.restore();
}
@override
int/*!*/ getSaveCount() => _canvas.saveCount;
@override
void translate(double/*!*/ dx, double/*!*/ dy) {
_canvas.translate(dx, dy);
}
@override
void scale(double/*!*/ sx, [double/*?*/ sy]) => _scale(sx, sy ?? sx);
void _scale(double sx, double sy) {
_canvas.scale(sx, sy);
}
@override
void rotate(double/*!*/ radians) {
_canvas.rotate(radians);
}
@override
void skew(double/*!*/ sx, double/*!*/ sy) {
_canvas.skew(sx, sy);
}
@override
void transform(Float64List/*!*/ matrix4) {
assert(matrix4 != null);
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
_transform(toMatrix32(matrix4));
}
void _transform(Float32List matrix4) {
_canvas.transform(matrix4);
}
@override
void clipRect(ui.Rect/*!*/ rect,
{ui.ClipOp clipOp/*!*/ = ui.ClipOp.intersect, bool/*!*/ doAntiAlias = true}) {
assert(rectIsValid(rect));
assert(clipOp != null);
assert(doAntiAlias != null);
_clipRect(rect, clipOp, doAntiAlias);
}
void _clipRect(ui.Rect rect, ui.ClipOp clipOp, bool doAntiAlias) {
_canvas.clipRect(rect);
}
@override
void clipRRect(ui.RRect/*!*/ rrect, {bool/*!*/ doAntiAlias = true}) {
assert(rrectIsValid(rrect));
assert(doAntiAlias != null);
_clipRRect(rrect, doAntiAlias);
}
void _clipRRect(ui.RRect rrect, bool doAntiAlias) {
_canvas.clipRRect(rrect);
}
@override
void clipPath(ui.Path/*!*/ path, {bool/*!*/ doAntiAlias = true}) {
assert(path != null); // path is checked on the engine side
assert(doAntiAlias != null);
_clipPath(path, doAntiAlias);
}
void _clipPath(ui.Path path, bool doAntiAlias) {
_canvas.clipPath(path, doAntiAlias: doAntiAlias);
}
@override
void drawColor(ui.Color/*!*/ color, ui.BlendMode/*!*/ blendMode) {
assert(color != null);
assert(blendMode != null);
_drawColor(color, blendMode);
}
void _drawColor(ui.Color color, ui.BlendMode blendMode) {
_canvas.drawColor(color, blendMode);
}
@override
void drawLine(ui.Offset/*!*/ p1, ui.Offset/*!*/ p2, ui.Paint/*!*/ paint) {
assert(offsetIsValid(p1));
assert(offsetIsValid(p2));
assert(paint != null);
_drawLine(p1, p2, paint);
}
void _drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) {
_canvas.drawLine(p1, p2, paint);
}
@override
void drawPaint(ui.Paint/*!*/ paint) {
assert(paint != null);
_drawPaint(paint);
}
void _drawPaint(ui.Paint paint) {
_canvas.drawPaint(paint);
}
@override
void drawRect(ui.Rect/*!*/ rect, ui.Paint/*!*/ paint) {
assert(rectIsValid(rect));
assert(paint != null);
_drawRect(rect, paint);
}
void _drawRect(ui.Rect rect, ui.Paint paint) {
_canvas.drawRect(rect, paint);
}
@override
void drawRRect(ui.RRect/*!*/ rrect, ui.Paint/*!*/ paint) {
assert(rrectIsValid(rrect));
assert(paint != null);
_drawRRect(rrect, paint);
}
void _drawRRect(ui.RRect rrect, ui.Paint paint) {
_canvas.drawRRect(rrect, paint);
}
@override
void drawDRRect(ui.RRect/*!*/ outer, ui.RRect/*!*/ inner, ui.Paint/*!*/ paint) {
assert(rrectIsValid(outer));
assert(rrectIsValid(inner));
assert(paint != null);
_drawDRRect(outer, inner, paint);
}
void _drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) {
_canvas.drawDRRect(outer, inner, paint);
}
@override
void drawOval(ui.Rect/*!*/ rect, ui.Paint/*!*/ paint) {
assert(rectIsValid(rect));
assert(paint != null);
_drawOval(rect, paint);
}
void _drawOval(ui.Rect rect, ui.Paint paint) {
_canvas.drawOval(rect, paint);
}
@override
void drawCircle(ui.Offset/*!*/ c, double/*!*/ radius, ui.Paint/*!*/ paint) {
assert(offsetIsValid(c));
assert(paint != null);
_drawCircle(c, radius, paint);
}
void _drawCircle(ui.Offset c, double radius, ui.Paint paint) {
_canvas.drawCircle(c, radius, paint);
}
@override
void drawArc(ui.Rect/*!*/ rect, double/*!*/ startAngle, double/*!*/ sweepAngle, bool/*!*/ useCenter,
ui.Paint/*!*/ paint) {
assert(rectIsValid(rect));
assert(paint != null);
const double pi = math.pi;
const double pi2 = 2.0 * pi;
final ui.Path path = ui.Path();
if (useCenter) {
path.moveTo(
(rect.left + rect.right) / 2.0, (rect.top + rect.bottom) / 2.0);
}
bool forceMoveTo = !useCenter;
if (sweepAngle <= -pi2) {
path.arcTo(rect, startAngle, -pi, forceMoveTo);
startAngle -= pi;
path.arcTo(rect, startAngle, -pi, false);
startAngle -= pi;
forceMoveTo = false;
sweepAngle += pi2;
}
while (sweepAngle >= pi2) {
path.arcTo(rect, startAngle, pi, forceMoveTo);
startAngle += pi;
path.arcTo(rect, startAngle, pi, false);
startAngle += pi;
forceMoveTo = false;
sweepAngle -= pi2;
}
path.arcTo(rect, startAngle, sweepAngle, forceMoveTo);
if (useCenter) {
path.close();
}
_canvas.drawPath(path, paint);
}
@override
void drawPath(ui.Path/*!*/ path, ui.Paint/*!*/ paint) {
assert(path != null); // path is checked on the engine side
assert(paint != null);
_drawPath(path, paint);
}
void _drawPath(ui.Path path, ui.Paint paint) {
_canvas.drawPath(path, paint);
}
@override
void drawImage(ui.Image/*!*/ image, ui.Offset/*!*/ offset, ui.Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(offsetIsValid(offset));
assert(paint != null);
_drawImage(image, offset, paint);
}
void _drawImage(ui.Image image, ui.Offset p, ui.Paint paint) {
_canvas.drawImage(image, p, paint);
}
@override
void drawImageRect(ui.Image/*!*/ image, ui.Rect/*!*/ src, ui.Rect/*!*/ dst, ui.Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(rectIsValid(src));
assert(rectIsValid(dst));
assert(paint != null);
_drawImageRect(image, src, dst, paint);
}
void _drawImageRect(ui.Image image, ui.Rect src, ui.Rect dst, ui.Paint paint) {
_canvas.drawImageRect(image, src, dst, paint);
}
@override
void drawImageNine(ui.Image/*!*/ image, ui.Rect/*!*/ center, ui.Rect/*!*/ dst, ui.Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(rectIsValid(center));
assert(rectIsValid(dst));
assert(paint != null);
// Assert you can fit the scaled part of the image (exluding the
// center source).
assert(image.width - center.width < dst.width);
assert(image.height - center.height < dst.height);
// The four unscaled corner rectangles in the from the src.
final ui.Rect srcTopLeft = ui.Rect.fromLTWH(
0,
0,
center.left,
center.top,
);
final ui.Rect srcTopRight = ui.Rect.fromLTWH(
center.right,
0,
image.width - center.right,
center.top,
);
final ui.Rect srcBottomLeft = ui.Rect.fromLTWH(
0,
center.bottom,
center.left,
image.height - center.bottom,
);
final ui.Rect srcBottomRight = ui.Rect.fromLTWH(
center.right,
center.bottom,
image.width - center.right,
image.height - center.bottom,
);
final ui.Rect dstTopLeft = srcTopLeft.shift(dst.topLeft);
// The center rectangle in the dst region
final ui.Rect dstCenter = ui.Rect.fromLTWH(
dstTopLeft.right,
dstTopLeft.bottom,
dst.width - (srcTopLeft.width + srcTopRight.width),
dst.height - (srcTopLeft.height + srcBottomLeft.height),
);
drawImageRect(image, srcTopLeft, dstTopLeft, paint);
final ui.Rect dstTopRight = ui.Rect.fromLTWH(
dstCenter.right,
dst.top,
srcTopRight.width,
srcTopRight.height,
);
drawImageRect(image, srcTopRight, dstTopRight, paint);
final ui.Rect dstBottomLeft = ui.Rect.fromLTWH(
dst.left,
dstCenter.bottom,
srcBottomLeft.width,
srcBottomLeft.height,
);
drawImageRect(image, srcBottomLeft, dstBottomLeft, paint);
final ui.Rect dstBottomRight = ui.Rect.fromLTWH(
dstCenter.right,
dstCenter.bottom,
srcBottomRight.width,
srcBottomRight.height,
);
drawImageRect(image, srcBottomRight, dstBottomRight, paint);
// Draw the top center rectangle.
drawImageRect(
image,
ui.Rect.fromLTRB(
srcTopLeft.right,
srcTopLeft.top,
srcTopRight.left,
srcTopRight.bottom,
),
ui.Rect.fromLTRB(
dstTopLeft.right,
dstTopLeft.top,
dstTopRight.left,
dstTopRight.bottom,
),
paint,
);
// Draw the middle left rectangle.
drawImageRect(
image,
ui.Rect.fromLTRB(
srcTopLeft.left,
srcTopLeft.bottom,
srcBottomLeft.right,
srcBottomLeft.top,
),
ui.Rect.fromLTRB(
dstTopLeft.left,
dstTopLeft.bottom,
dstBottomLeft.right,
dstBottomLeft.top,
),
paint,
);
// Draw the center rectangle.
drawImageRect(image, center, dstCenter, paint);
// Draw the middle right rectangle.
drawImageRect(
image,
ui.Rect.fromLTRB(
srcTopRight.left,
srcTopRight.bottom,
srcBottomRight.right,
srcBottomRight.top,
),
ui.Rect.fromLTRB(
dstTopRight.left,
dstTopRight.bottom,
dstBottomRight.right,
dstBottomRight.top,
),
paint,
);
// Draw the bottom center rectangle.
drawImageRect(
image,
ui.Rect.fromLTRB(
srcBottomLeft.right,
srcBottomLeft.top,
srcBottomRight.left,
srcBottomRight.bottom,
),
ui.Rect.fromLTRB(
dstBottomLeft.right,
dstBottomLeft.top,
dstBottomRight.left,
dstBottomRight.bottom,
),
paint,
);
}
@override
void drawPicture(ui.Picture/*!*/ picture) {
assert(picture != null); // picture is checked on the engine side
// TODO(het): Support this
throw UnimplementedError();
}
@override
void drawParagraph(ui.Paragraph/*!*/ paragraph, ui.Offset/*!*/ offset) {
assert(paragraph != null);
assert(offsetIsValid(offset));
_drawParagraph(paragraph, offset);
}
void _drawParagraph(ui.Paragraph paragraph, ui.Offset offset) {
_canvas.drawParagraph(paragraph, offset);
}
@override
void drawPoints(ui.PointMode/*!*/ pointMode, List<ui.Offset/*!*/>/*!*/ points, ui.Paint/*!*/ paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
final Float32List pointList = offsetListToFloat32List(points);
drawRawPoints(pointMode, pointList, paint);
}
@override
void drawRawPoints(ui.PointMode/*!*/ pointMode, Float32List/*!*/ points, ui.Paint/*!*/ paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
if (points.length % 2 != 0) {
throw ArgumentError('"points" must have an even number of values.');
}
_canvas.drawRawPoints(pointMode, points, paint);
}
@override
void drawVertices(ui.Vertices/*!*/ vertices, ui.BlendMode/*!*/ blendMode, ui.Paint/*!*/ paint) {
if (vertices == null) {
return;
}
//assert(vertices != null); // vertices is checked on the engine side
assert(paint != null);
assert(blendMode != null);
_canvas.drawVertices(vertices, blendMode, paint);
}
@override
void drawAtlas(
ui.Image/*!*/ atlas,
List<ui.RSTransform/*!*/>/*!*/ transforms,
List<ui.Rect/*!*/>/*!*/ rects,
List<ui.Color/*!*/>/*!*/ colors,
ui.BlendMode/*!*/ blendMode,
ui.Rect/*?*/ cullRect,
ui.Paint/*!*/ paint,
) {
assert(atlas != null); // atlas is checked on the engine side
assert(transforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (transforms.length != rectCount) {
throw ArgumentError('"transforms" and "rects" lengths must match.');
}
if (colors.isNotEmpty && colors.length != rectCount) {
throw ArgumentError(
'If non-null, "colors" length must match that of "transforms" and "rects".');
}
// TODO(het): Do we need to support this?
throw UnimplementedError();
}
@override
void drawRawAtlas(
ui.Image/*!*/ atlas,
Float32List/*!*/ rstTransforms,
Float32List/*!*/ rects,
Int32List/*!*/ colors,
ui.BlendMode/*!*/ blendMode,
ui.Rect/*?*/ cullRect,
ui.Paint/*!*/ paint,
) {
assert(atlas != null); // atlas is checked on the engine side
assert(rstTransforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (rstTransforms.length != rectCount) {
throw ArgumentError('"rstTransforms" and "rects" lengths must match.');
}
if (rectCount % 4 != 0) {
throw ArgumentError(
'"rstTransforms" and "rects" lengths must be a multiple of four.');
}
if (colors != null && colors.length * 4 != rectCount) {
throw ArgumentError(
'If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');
}
// TODO(het): Do we need to support this?
throw UnimplementedError();
}
@override
void drawShadow(
ui.Path/*!*/ path,
ui.Color/*!*/ color,
double/*!*/ elevation,
bool/*!*/ transparentOccluder,
) {
assert(path != null); // path is checked on the engine side
assert(color != null);
assert(transparentOccluder != null);
_canvas.drawShadow(path, color, elevation, transparentOccluder);
}
}
......@@ -72,7 +72,7 @@ class DebugCanvasReuseOverlay {
}
static DebugCanvasReuseOverlay _instance;
static DebugCanvasReuseOverlay get instance {
static DebugCanvasReuseOverlay/*!*/ get instance {
if (_instance == null) {
// Only call the constructor when assertions are enabled to guard against
// mistakingly including this class in a release build.
......
......@@ -542,12 +542,12 @@ class RecordingCanvas {
}
void drawVertices(
ui.Vertices vertices, ui.BlendMode blendMode, SurfacePaint paint) {
SurfaceVertices vertices, ui.BlendMode blendMode, SurfacePaint paint) {
assert(!_debugRecordingEnded);
_hasArbitraryPaint = true;
_didDraw = true;
final PaintDrawVertices command = PaintDrawVertices(vertices, blendMode, paint.paintData);
_growPaintBoundsByPoints(vertices.positions, 0, paint, command);
_growPaintBoundsByPoints(vertices._positions, 0, paint, command);
_commands.add(command);
}
......
......@@ -7,6 +7,49 @@ part of engine;
_GlRenderer _glRenderer;
class SurfaceVertices implements ui.Vertices {
final ui.VertexMode _mode;
final Float32List _positions;
final Int32List/*?*/ _colors;
final Uint16List _indices; // ignore: unused_field
SurfaceVertices(
ui.VertexMode mode,
List<ui.Offset> positions, {
List<ui.Color> colors,
List<int> indices,
}) : assert(mode != null),
assert(positions != null),
_mode = mode,
_colors = colors != null ? _int32ListFromColors(colors) : null,
_indices = indices != null ? Uint16List.fromList(indices) : null,
_positions = offsetListToFloat32List(positions) {
initWebGl();
}
SurfaceVertices.raw(
ui.VertexMode mode,
Float32List positions, {
Int32List colors,
Uint16List indices,
}) : assert(mode != null),
assert(positions != null),
_mode = mode,
_positions = positions,
_colors = colors,
_indices = indices {
initWebGl();
}
static Int32List _int32ListFromColors(List<ui.Color> colors) {
Int32List list = Int32List(colors.length);
for (int i = 0, len = colors.length; i < len; i++) {
list[i] = colors[i].value;
}
return list;
}
}
void initWebGl() {
_glRenderer ??= _WebGlRenderer();
}
......@@ -22,7 +65,7 @@ abstract class _GlRenderer {
int canvasWidthInPixels,
int canvasHeightInPixels,
Matrix4 transform,
ui.Vertices vertices,
SurfaceVertices vertices,
ui.BlendMode blendMode,
SurfacePaintData paint);
......@@ -85,11 +128,11 @@ class _WebGlRenderer implements _GlRenderer {
int canvasWidthInPixels,
int canvasHeightInPixels,
Matrix4 transform,
ui.Vertices vertices,
SurfaceVertices vertices,
ui.BlendMode blendMode,
SurfacePaintData paint) {
// Compute bounds of vertices.
final Float32List positions = vertices.positions;
final Float32List positions = vertices._positions;
ui.Rect bounds = _computeVerticesBounds(positions, transform);
double minValueX = bounds.left;
double minValueY = bounds.top;
......@@ -152,14 +195,14 @@ class _WebGlRenderer implements _GlRenderer {
Object colorsBuffer = gl.createBuffer();
gl.bindArrayBuffer(colorsBuffer);
// Buffer kBGRA_8888.
gl.bufferData(vertices.colors, gl.kStaticDraw);
gl.bufferData(vertices._colors, gl.kStaticDraw);
js_util.callMethod(gl.glContext, 'vertexAttribPointer',
<dynamic>[1, 4, gl.kUnsignedByte, true, 0, 0]);
gl.enableVertexAttribArray(1);
gl.clear();
final int vertexCount = positions.length ~/ 2;
gl.drawTriangles(vertexCount, vertices.mode);
gl.drawTriangles(vertexCount, vertices._mode);
context.save();
context.resetTransform();
......
......@@ -35,7 +35,7 @@ typedef Callbacker<T> = String Function(Callback<T> callback);
/// return _futurize(_doSomethingAndCallback);
/// }
/// ```
Future<T> futurize<T>(Callbacker<T> callbacker) {
Future<T>/*!*/ futurize<T>(Callbacker<T> callbacker) {
final Completer<T> completer = Completer<T>.sync();
final String error = callbacker((T t) {
if (t == null) {
......
......@@ -59,31 +59,7 @@ enum VertexMode {
}
/// A set of vertex data used by [Canvas.drawVertices].
// TODO(yjbanov): move this to dart:_engine, https://github.com/flutter/flutter/issues/58813
class Vertices {
final VertexMode _mode;
final Float32List _positions;
final Float32List _textureCoordinates;
final Int32List _colors;
final Uint16List _indices; // ignore: unused_field
Vertices._(
VertexMode mode,
List<Offset> positions, {
List<Offset> textureCoordinates,
List<Color> colors,
List<int> indices,
}) : assert(mode != null),
assert(positions != null),
_mode = mode,
_colors = _int32ListFromColors(colors),
_indices = indices != null ? Uint16List.fromList(indices) : null,
_positions = engine.offsetListToFloat32List(positions),
_textureCoordinates =
engine.offsetListToFloat32List(textureCoordinates) {
engine.initWebGl();
}
/// Creates a set of vertex data for use with [Canvas.drawVertices].
///
/// The [mode] and [positions] parameters must not be null.
......@@ -106,36 +82,11 @@ class Vertices {
colors: colors,
indices: indices);
}
return Vertices._(mode, positions,
textureCoordinates: textureCoordinates,
return engine.SurfaceVertices(mode, positions,
colors: colors,
indices: indices);
}
Vertices._raw(
VertexMode mode,
Float32List positions, {
Float32List textureCoordinates,
Int32List colors,
Uint16List indices,
}) : assert(mode != null),
assert(positions != null),
_mode = mode,
_positions = positions,
_textureCoordinates = textureCoordinates,
_colors = colors,
_indices = indices {
engine.initWebGl();
}
static Int32List _int32ListFromColors(List<Color> colors) {
Int32List list = Int32List(colors.length);
for (int i = 0, len = colors.length; i < len; i++) {
list[i] = colors[i].value;
}
return list;
}
/// Creates a set of vertex data for use with [Canvas.drawVertices], directly
/// using the encoding methods of [new Vertices].
///
......@@ -167,17 +118,10 @@ class Vertices {
colors: colors,
indices: indices);
}
return Vertices._raw(mode, positions,
textureCoordinates: textureCoordinates,
return engine.SurfaceVertices.raw(mode, positions,
colors: colors,
indices: indices);
}
VertexMode/*!*/ get mode => _mode;
Float32List/*!*/ get positions => _positions;
Int32List/*?*/ get colors => _colors;
Float32List/*?*/ get textureCoordinates => _textureCoordinates;
Uint16List/*?*/ get indices => _indices;
}
/// Records a [Picture] containing a sequence of graphical operations.
......@@ -230,39 +174,15 @@ abstract class PictureRecorder {
///
/// The current transform and clip can be saved and restored using the stack
/// managed by the [save], [saveLayer], and [restore] methods.
class Canvas {
engine.RecordingCanvas _canvas;
abstract class Canvas {
factory Canvas(PictureRecorder/*!*/ recorder, [Rect/*?*/ cullRect]) {
if (engine.experimentalUseSkia) {
return engine.CanvasKitCanvas(recorder, cullRect);
} else {
return Canvas._(recorder, cullRect);
return engine.SurfaceCanvas(recorder, cullRect);
}
}
/// Creates a canvas for recording graphical operations into the
/// given picture recorder.
///
/// Graphical operations that affect pixels entirely outside the given
/// `cullRect` might be discarded by the implementation. However, the
/// implementation might draw outside these bounds if, for example, a command
/// draws partially inside and outside the `cullRect`. To ensure that pixels
/// outside a given region are discarded, consider using a [clipRect]. The
/// `cullRect` is optional; by default, all operations are kept.
///
/// To end the recording, call [PictureRecorder.endRecording] on the
/// given recorder.
Canvas._(engine.EnginePictureRecorder recorder, [Rect cullRect])
: assert(recorder != null) {
if (recorder.isRecording) {
throw ArgumentError(
'"recorder" must not already be associated with another Canvas.');
}
cullRect ??= Rect.largest;
_canvas = recorder.beginRecording(cullRect);
}
/// Saves a copy of the current transform and clip on the save stack.
///
/// Call [restore] to pop the save stack.
......@@ -271,9 +191,7 @@ class Canvas {
///
/// * [saveLayer], which does the same thing but additionally also groups the
/// commands done until the matching [restore].
void save() {
_canvas.save();
}
void save();
/// Saves a copy of the current transform and clip on the save stack, and then
/// creates a new group which subsequent calls will become a part of. When the
......@@ -384,23 +302,7 @@ class Canvas {
/// for subsequent commands.
/// * [BlendMode], which discusses the use of [Paint.blendMode] with
/// [saveLayer].
void saveLayer(Rect/*?*/ bounds, Paint/*!*/ paint) {
assert(paint != null);
if (bounds == null) {
_saveLayerWithoutBounds(paint);
} else {
assert(engine.rectIsValid(bounds));
_saveLayer(bounds, paint);
}
}
void _saveLayerWithoutBounds(Paint paint) {
_canvas.saveLayerWithoutBounds(paint);
}
void _saveLayer(Rect bounds, Paint paint) {
_canvas.saveLayer(bounds, paint);
}
void saveLayer(Rect/*?*/ bounds, Paint/*!*/ paint);
/// Pops the current save stack, if there is anything to pop.
/// Otherwise, does nothing.
......@@ -409,9 +311,7 @@ class Canvas {
///
/// If the state was pushed with with [saveLayer], then this call will also
/// cause the new layer to be composited into the previous layer.
void restore() {
_canvas.restore();
}
void restore();
/// Returns the number of items on the save stack, including the
/// initial state. This means it returns 1 for a clean canvas, and
......@@ -419,13 +319,11 @@ class Canvas {
/// each matching call to [restore] decrements it.
///
/// This number cannot go below 1.
int/*!*/ getSaveCount() => _canvas.saveCount;
int/*!*/ getSaveCount();
/// Add a translation to the current transform, shifting the coordinate space
/// horizontally by the first argument and vertically by the second argument.
void translate(double/*!*/ dx, double/*!*/ dy) {
_canvas.translate(dx, dy);
}
void translate(double/*!*/ dx, double/*!*/ dy);
/// Add an axis-aligned scale to the current transform, scaling by the first
/// argument in the horizontal direction and the second in the vertical
......@@ -433,38 +331,20 @@ class Canvas {
///
/// If [sy] is unspecified, [sx] will be used for the scale in both
/// directions.
void scale(double/*!*/ sx, [double/*?*/ sy]) => _scale(sx, sy ?? sx);
void _scale(double sx, double sy) {
_canvas.scale(sx, sy);
}
void scale(double/*!*/ sx, [double/*?*/ sy]);
/// Add a rotation to the current transform. The argument is in radians clockwise.
void rotate(double/*!*/ radians) {
_canvas.rotate(radians);
}
void rotate(double/*!*/ radians);
/// Add an axis-aligned skew to the current transform, with the first argument
/// being the horizontal skew in radians clockwise around the origin, and the
/// second argument being the vertical skew in radians clockwise around the
/// origin.
void skew(double/*!*/ sx, double/*!*/ sy) {
_canvas.skew(sx, sy);
}
void skew(double/*!*/ sx, double/*!*/ sy);
/// Multiply the current transform by the specified 4⨉4 transformation matrix
/// specified as a list of values in column-major order.
void transform(Float64List/*!*/ matrix4) {
assert(matrix4 != null);
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
_transform(engine.toMatrix32(matrix4));
}
void _transform(Float32List matrix4) {
_canvas.transform(matrix4);
}
void transform(Float64List/*!*/ matrix4);
/// Reduces the clip region to the intersection of the current clip and the
/// given rectangle.
......@@ -478,16 +358,7 @@ class Canvas {
/// Use [ClipOp.difference] to subtract the provided rectangle from the
/// current clip.
void clipRect(Rect/*!*/ rect,
{ClipOp clipOp/*!*/ = ClipOp.intersect, bool/*!*/ doAntiAlias = true}) {
assert(engine.rectIsValid(rect));
assert(clipOp != null);
assert(doAntiAlias != null);
_clipRect(rect, clipOp, doAntiAlias);
}
void _clipRect(Rect rect, ClipOp clipOp, bool doAntiAlias) {
_canvas.clipRect(rect);
}
{ClipOp clipOp/*!*/ = ClipOp.intersect, bool/*!*/ doAntiAlias = true});
/// Reduces the clip region to the intersection of the current clip and the
/// given rounded rectangle.
......@@ -497,15 +368,7 @@ class Canvas {
/// If multiple draw commands intersect with the clip boundary, this can result
/// in incorrect blending at the clip boundary. See [saveLayer] for a
/// discussion of how to address that and some examples of using [clipRRect].
void clipRRect(RRect/*!*/ rrect, {bool/*!*/ doAntiAlias = true}) {
assert(engine.rrectIsValid(rrect));
assert(doAntiAlias != null);
_clipRRect(rrect, doAntiAlias);
}
void _clipRRect(RRect rrect, bool doAntiAlias) {
_canvas.clipRRect(rrect);
}
void clipRRect(RRect/*!*/ rrect, {bool/*!*/ doAntiAlias = true});
/// Reduces the clip region to the intersection of the current clip and the
/// given [Path].
......@@ -516,123 +379,50 @@ class Canvas {
/// multiple draw commands intersect with the clip boundary, this can result
/// in incorrect blending at the clip boundary. See [saveLayer] for a
/// discussion of how to address that.
void clipPath(Path/*!*/ path, {bool/*!*/ doAntiAlias = true}) {
assert(path != null); // path is checked on the engine side
assert(doAntiAlias != null);
_clipPath(path, doAntiAlias);
}
void _clipPath(Path path, bool doAntiAlias) {
_canvas.clipPath(path, doAntiAlias: doAntiAlias);
}
void clipPath(Path/*!*/ path, {bool/*!*/ doAntiAlias = true});
/// Paints the given [Color] onto the canvas, applying the given
/// [BlendMode], with the given color being the source and the background
/// being the destination.
void drawColor(Color/*!*/ color, BlendMode/*!*/ blendMode) {
assert(color != null);
assert(blendMode != null);
_drawColor(color, blendMode);
}
void _drawColor(Color color, BlendMode blendMode) {
_canvas.drawColor(color, blendMode);
}
void drawColor(Color/*!*/ color, BlendMode/*!*/ blendMode);
/// Draws a line between the given points using the given paint. The line is
/// stroked, the value of the [Paint.style] is ignored for this call.
///
/// The `p1` and `p2` arguments are interpreted as offsets from the origin.
void drawLine(Offset/*!*/ p1, Offset/*!*/ p2, Paint/*!*/ paint) {
assert(engine.offsetIsValid(p1));
assert(engine.offsetIsValid(p2));
assert(paint != null);
_drawLine(p1, p2, paint);
}
void _drawLine(Offset p1, Offset p2, Paint paint) {
_canvas.drawLine(p1, p2, paint);
}
void drawLine(Offset/*!*/ p1, Offset/*!*/ p2, Paint/*!*/ paint);
/// Fills the canvas with the given [Paint].
///
/// To fill the canvas with a solid color and blend mode, consider
/// [drawColor] instead.
void drawPaint(Paint/*!*/ paint) {
assert(paint != null);
_drawPaint(paint);
}
void _drawPaint(Paint paint) {
_canvas.drawPaint(paint);
}
void drawPaint(Paint/*!*/ paint);
/// Draws a rectangle with the given [Paint]. Whether the rectangle is filled
/// or stroked (or both) is controlled by [Paint.style].
void drawRect(Rect/*!*/ rect, Paint/*!*/ paint) {
assert(engine.rectIsValid(rect));
assert(paint != null);
_drawRect(rect, paint);
}
void _drawRect(Rect rect, Paint paint) {
_canvas.drawRect(rect, paint);
}
void drawRect(Rect/*!*/ rect, Paint/*!*/ paint);
/// Draws a rounded rectangle with the given [Paint]. Whether the rectangle is
/// filled or stroked (or both) is controlled by [Paint.style].
void drawRRect(RRect/*!*/ rrect, Paint/*!*/ paint) {
assert(engine.rrectIsValid(rrect));
assert(paint != null);
_drawRRect(rrect, paint);
}
void _drawRRect(RRect rrect, Paint paint) {
_canvas.drawRRect(rrect, paint);
}
void drawRRect(RRect/*!*/ rrect, Paint/*!*/ paint);
/// Draws a shape consisting of the difference between two rounded rectangles
/// with the given [Paint]. Whether this shape is filled or stroked (or both)
/// is controlled by [Paint.style].
///
/// This shape is almost but not quite entirely unlike an annulus.
void drawDRRect(RRect/*!*/ outer, RRect/*!*/ inner, Paint/*!*/ paint) {
assert(engine.rrectIsValid(outer));
assert(engine.rrectIsValid(inner));
assert(paint != null);
_drawDRRect(outer, inner, paint);
}
void _drawDRRect(RRect outer, RRect inner, Paint paint) {
_canvas.drawDRRect(outer, inner, paint);
}
void drawDRRect(RRect/*!*/ outer, RRect/*!*/ inner, Paint/*!*/ paint);
/// Draws an axis-aligned oval that fills the given axis-aligned rectangle
/// with the given [Paint]. Whether the oval is filled or stroked (or both) is
/// controlled by [Paint.style].
void drawOval(Rect/*!*/ rect, Paint/*!*/ paint) {
assert(engine.rectIsValid(rect));
assert(paint != null);
_drawOval(rect, paint);
}
void _drawOval(Rect rect, Paint paint) {
_canvas.drawOval(rect, paint);
}
void drawOval(Rect/*!*/ rect, Paint/*!*/ paint);
/// Draws a circle centered at the point given by the first argument and
/// that has the radius given by the second argument, with the [Paint] given in
/// the third argument. Whether the circle is filled or stroked (or both) is
/// controlled by [Paint.style].
void drawCircle(Offset/*!*/ c, double/*!*/ radius, Paint/*!*/ paint) {
assert(engine.offsetIsValid(c));
assert(paint != null);
_drawCircle(c, radius, paint);
}
void _drawCircle(Offset c, double radius, Paint paint) {
_canvas.drawCircle(c, radius, paint);
}
void drawCircle(Offset/*!*/ c, double/*!*/ radius, Paint/*!*/ paint);
/// Draw an arc scaled to fit inside the given rectangle. It starts from
/// startAngle radians around the oval up to startAngle + sweepAngle
......@@ -645,66 +435,16 @@ class Canvas {
///
/// This method is optimized for drawing arcs and should be faster than [Path.arcTo].
void drawArc(Rect/*!*/ rect, double/*!*/ startAngle, double/*!*/ sweepAngle, bool/*!*/ useCenter,
Paint/*!*/ paint) {
assert(engine.rectIsValid(rect));
assert(paint != null);
const double pi = math.pi;
const double pi2 = 2.0 * pi;
final Path path = Path();
if (useCenter) {
path.moveTo(
(rect.left + rect.right) / 2.0, (rect.top + rect.bottom) / 2.0);
}
bool forceMoveTo = !useCenter;
if (sweepAngle <= -pi2) {
path.arcTo(rect, startAngle, -pi, forceMoveTo);
startAngle -= pi;
path.arcTo(rect, startAngle, -pi, false);
startAngle -= pi;
forceMoveTo = false;
sweepAngle += pi2;
}
while (sweepAngle >= pi2) {
path.arcTo(rect, startAngle, pi, forceMoveTo);
startAngle += pi;
path.arcTo(rect, startAngle, pi, false);
startAngle += pi;
forceMoveTo = false;
sweepAngle -= pi2;
}
path.arcTo(rect, startAngle, sweepAngle, forceMoveTo);
if (useCenter) {
path.close();
}
_canvas.drawPath(path, paint);
}
Paint/*!*/ paint);
/// Draws the given [Path] with the given [Paint]. Whether this shape is
/// filled or stroked (or both) is controlled by [Paint.style]. If the path is
/// filled, then subpaths within it are implicitly closed (see [Path.close]).
void drawPath(Path/*!*/ path, Paint/*!*/ paint) {
assert(path != null); // path is checked on the engine side
assert(paint != null);
_drawPath(path, paint);
}
void _drawPath(Path path, Paint paint) {
_canvas.drawPath(path, paint);
}
void drawPath(Path/*!*/ path, Paint/*!*/ paint);
/// Draws the given [Image] into the canvas with its top-left corner at the
/// given [Offset]. The image is composited into the canvas using the given [Paint].
void drawImage(Image/*!*/ image, Offset/*!*/ offset, Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(engine.offsetIsValid(offset));
assert(paint != null);
_drawImage(image, offset, paint);
}
void _drawImage(Image image, Offset p, Paint paint) {
_canvas.drawImage(image, p, paint);
}
void drawImage(Image/*!*/ image, Offset/*!*/ offset, Paint/*!*/ paint);
/// Draws the subset of the given image described by the `src` argument into
/// the canvas in the axis-aligned rectangle given by the `dst` argument.
......@@ -715,17 +455,7 @@ class Canvas {
/// Multiple calls to this method with different arguments (from the same
/// image) can be batched into a single call to [drawAtlas] to improve
/// performance.
void drawImageRect(Image/*!*/ image, Rect/*!*/ src, Rect/*!*/ dst, Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(engine.rectIsValid(src));
assert(engine.rectIsValid(dst));
assert(paint != null);
_drawImageRect(image, src, dst, paint);
}
void _drawImageRect(Image image, Rect src, Rect dst, Paint paint) {
_canvas.drawImageRect(image, src, dst, paint);
}
void drawImageRect(Image/*!*/ image, Rect/*!*/ src, Rect/*!*/ dst, Paint/*!*/ paint);
/// Draws the given [Image] into the canvas using the given [Paint].
///
......@@ -740,162 +470,11 @@ class Canvas {
/// five regions are drawn by stretching them to fit such that they exactly
/// cover the destination rectangle while maintaining their relative
/// positions.
void drawImageNine(Image/*!*/ image, Rect/*!*/ center, Rect/*!*/ dst, Paint/*!*/ paint) {
assert(image != null); // image is checked on the engine side
assert(engine.rectIsValid(center));
assert(engine.rectIsValid(dst));
assert(paint != null);
// Assert you can fit the scaled part of the image (exluding the
// center source).
assert(image.width - center.width < dst.width);
assert(image.height - center.height < dst.height);
// The four unscaled corner rectangles in the from the src.
final Rect srcTopLeft = Rect.fromLTWH(
0,
0,
center.left,
center.top,
);
final Rect srcTopRight = Rect.fromLTWH(
center.right,
0,
image.width - center.right,
center.top,
);
final Rect srcBottomLeft = Rect.fromLTWH(
0,
center.bottom,
center.left,
image.height - center.bottom,
);
final Rect srcBottomRight = Rect.fromLTWH(
center.right,
center.bottom,
image.width - center.right,
image.height - center.bottom,
);
final Rect dstTopLeft = srcTopLeft.shift(dst.topLeft);
// The center rectangle in the dst region
final Rect dstCenter = Rect.fromLTWH(
dstTopLeft.right,
dstTopLeft.bottom,
dst.width - (srcTopLeft.width + srcTopRight.width),
dst.height - (srcTopLeft.height + srcBottomLeft.height),
);
drawImageRect(image, srcTopLeft, dstTopLeft, paint);
final Rect dstTopRight = Rect.fromLTWH(
dstCenter.right,
dst.top,
srcTopRight.width,
srcTopRight.height,
);
drawImageRect(image, srcTopRight, dstTopRight, paint);
final Rect dstBottomLeft = Rect.fromLTWH(
dst.left,
dstCenter.bottom,
srcBottomLeft.width,
srcBottomLeft.height,
);
drawImageRect(image, srcBottomLeft, dstBottomLeft, paint);
final Rect dstBottomRight = Rect.fromLTWH(
dstCenter.right,
dstCenter.bottom,
srcBottomRight.width,
srcBottomRight.height,
);
drawImageRect(image, srcBottomRight, dstBottomRight, paint);
// Draw the top center rectangle.
drawImageRect(
image,
Rect.fromLTRB(
srcTopLeft.right,
srcTopLeft.top,
srcTopRight.left,
srcTopRight.bottom,
),
Rect.fromLTRB(
dstTopLeft.right,
dstTopLeft.top,
dstTopRight.left,
dstTopRight.bottom,
),
paint,
);
// Draw the middle left rectangle.
drawImageRect(
image,
Rect.fromLTRB(
srcTopLeft.left,
srcTopLeft.bottom,
srcBottomLeft.right,
srcBottomLeft.top,
),
Rect.fromLTRB(
dstTopLeft.left,
dstTopLeft.bottom,
dstBottomLeft.right,
dstBottomLeft.top,
),
paint,
);
// Draw the center rectangle.
drawImageRect(image, center, dstCenter, paint);
// Draw the middle right rectangle.
drawImageRect(
image,
Rect.fromLTRB(
srcTopRight.left,
srcTopRight.bottom,
srcBottomRight.right,
srcBottomRight.top,
),
Rect.fromLTRB(
dstTopRight.left,
dstTopRight.bottom,
dstBottomRight.right,
dstBottomRight.top,
),
paint,
);
// Draw the bottom center rectangle.
drawImageRect(
image,
Rect.fromLTRB(
srcBottomLeft.right,
srcBottomLeft.top,
srcBottomRight.left,
srcBottomRight.bottom,
),
Rect.fromLTRB(
dstBottomLeft.right,
dstBottomLeft.top,
dstBottomRight.left,
dstBottomRight.bottom,
),
paint,
);
}
void drawImageNine(Image/*!*/ image, Rect/*!*/ center, Rect/*!*/ dst, Paint/*!*/ paint);
/// Draw the given picture onto the canvas. To create a picture, see
/// [PictureRecorder].
void drawPicture(Picture/*!*/ picture) {
assert(picture != null); // picture is checked on the engine side
// TODO(het): Support this
throw UnimplementedError();
}
void drawPicture(Picture/*!*/ picture);
/// Draws the text in the given [Paragraph] into this canvas at the given
/// [Offset].
......@@ -917,15 +496,7 @@ class Canvas {
/// If the text is centered, the centering axis will be at the position
/// described by adding half of the [ParagraphConstraints.width] given to
/// [Paragraph.layout], to the `offset` argument's [Offset.dx] coordinate.
void drawParagraph(Paragraph/*!*/ paragraph, Offset/*!*/ offset) {
assert(paragraph != null);
assert(engine.offsetIsValid(offset));
_drawParagraph(paragraph, offset);
}
void _drawParagraph(Paragraph paragraph, Offset offset) {
_canvas.drawParagraph(paragraph, offset);
}
void drawParagraph(Paragraph/*!*/ paragraph, Offset/*!*/ offset);
/// Draws a sequence of points according to the given [PointMode].
///
......@@ -935,13 +506,7 @@ class Canvas {
///
/// * [drawRawPoints], which takes `points` as a [Float32List] rather than a
/// [List<Offset>].
void drawPoints(PointMode/*!*/ pointMode, List<Offset/*!*/>/*!*/ points, Paint/*!*/ paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
final Float32List pointList = engine.offsetListToFloat32List(points);
drawRawPoints(pointMode, pointList, paint);
}
void drawPoints(PointMode/*!*/ pointMode, List<Offset/*!*/>/*!*/ points, Paint/*!*/ paint);
/// Draws a sequence of points according to the given [PointMode].
///
......@@ -952,25 +517,9 @@ class Canvas {
///
/// * [drawPoints], which takes `points` as a [List<Offset>] rather than a
/// [List<Float32List>].
void drawRawPoints(PointMode/*!*/ pointMode, Float32List/*!*/ points, Paint/*!*/ paint) {
assert(pointMode != null);
assert(points != null);
assert(paint != null);
if (points.length % 2 != 0) {
throw ArgumentError('"points" must have an even number of values.');
}
_canvas.drawRawPoints(pointMode, points, paint);
}
void drawRawPoints(PointMode/*!*/ pointMode, Float32List/*!*/ points, Paint/*!*/ paint);
void drawVertices(Vertices/*!*/ vertices, BlendMode/*!*/ blendMode, Paint/*!*/ paint) {
if (vertices == null) {
return;
}
//assert(vertices != null); // vertices is checked on the engine side
assert(paint != null);
assert(blendMode != null);
_canvas.drawVertices(vertices, blendMode, paint);
}
void drawVertices(Vertices/*!*/ vertices, BlendMode/*!*/ blendMode, Paint/*!*/ paint);
/// Draws part of an image - the [atlas] - onto the canvas.
///
......@@ -992,26 +541,7 @@ class Canvas {
BlendMode/*!*/ blendMode,
Rect/*?*/ cullRect,
Paint/*!*/ paint,
) {
assert(atlas != null); // atlas is checked on the engine side
assert(transforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (transforms.length != rectCount) {
throw ArgumentError('"transforms" and "rects" lengths must match.');
}
if (colors.isNotEmpty && colors.length != rectCount) {
throw ArgumentError(
'If non-null, "colors" length must match that of "transforms" and "rects".');
}
// TODO(het): Do we need to support this?
throw UnimplementedError();
}
);
/// Draws part of an image - the [atlas] - onto the canvas.
///
......@@ -1041,30 +571,7 @@ class Canvas {
BlendMode/*!*/ blendMode,
Rect/*?*/ cullRect,
Paint/*!*/ paint,
) {
assert(atlas != null); // atlas is checked on the engine side
assert(rstTransforms != null);
assert(rects != null);
assert(colors != null);
assert(blendMode != null);
assert(paint != null);
final int rectCount = rects.length;
if (rstTransforms.length != rectCount) {
throw ArgumentError('"rstTransforms" and "rects" lengths must match.');
}
if (rectCount % 4 != 0) {
throw ArgumentError(
'"rstTransforms" and "rects" lengths must be a multiple of four.');
}
if (colors != null && colors.length * 4 != rectCount) {
throw ArgumentError(
'If non-null, "colors" length must be one fourth the length of "rstTransforms" and "rects".');
}
// TODO(het): Do we need to support this?
throw UnimplementedError();
}
);
/// Draws a shadow for a [Path] representing the given material elevation.
///
......@@ -1077,12 +584,7 @@ class Canvas {
Color/*!*/ color,
double/*!*/ elevation,
bool/*!*/ transparentOccluder,
) {
assert(path != null); // path is checked on the engine side
assert(color != null);
assert(transparentOccluder != null);
_canvas.drawShadow(path, color, elevation, transparentOccluder);
}
);
}
/// An object representing a sequence of recorded graphical operations.
......
......@@ -314,15 +314,21 @@ class Offset extends OffsetBase {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Offset/*!*/ lerp(Offset/*?*/ a, Offset/*?*/ b, double/*!*/ t) {
static Offset/*?*/ lerp(Offset/*?*/ a, Offset/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return Offset(lerpDouble(a.dx, b.dx, t), lerpDouble(a.dy, b.dy, t));
if (b == null) {
if (a == null) {
return null;
} else {
return a * (1.0 - t);
}
} else {
if (a == null) {
return b * t;
} else {
return Offset(_lerpDouble(a.dx, b.dx, t), _lerpDouble(a.dy, b.dy, t));
}
}
}
/// Compares two Offsets for equality.
......@@ -579,15 +585,21 @@ class Size extends OffsetBase {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Size/*!*/ lerp(Size/*?*/ a, Size/*?*/ b, double/*!*/ t) {
static Size/*?*/ lerp(Size/*?*/ a, Size/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0 - t);
return Size(lerpDouble(a.width, b.width, t), lerpDouble(a.height, b.height, t));
if (b == null) {
if (a == null) {
return null;
} else {
return a * (1.0 - t);
}
} else {
if (a == null) {
return b * t;
} else {
return Size(_lerpDouble(a.width, b.width, t), _lerpDouble(a.height, b.height, t));
}
}
}
/// Compares two Sizes for equality.
......@@ -847,22 +859,27 @@ class Rect {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Rect/*!*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) {
static Rect/*?*/ lerp(Rect/*?*/ a, Rect/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
if (b == null) {
final double k = 1.0 - t;
return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
}
} else {
if (a == null) {
return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
} else {
return Rect.fromLTRB(
_lerpDouble(a.left, b.left, t),
_lerpDouble(a.top, b.top, t),
_lerpDouble(a.right, b.right, t),
_lerpDouble(a.bottom, b.bottom, t),
);
}
}
return Rect.fromLTRB(
lerpDouble(a.left, b.left, t),
lerpDouble(a.top, b.top, t),
lerpDouble(a.right, b.right, t),
lerpDouble(a.bottom, b.bottom, t),
);
}
@override
......@@ -971,20 +988,25 @@ class Radius {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static Radius/*!*/ lerp(Radius/*?*/ a, Radius/*?*/ b, double/*!*/ t) {
static Radius/*?*/ lerp(Radius/*?*/ a, Radius/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return Radius.elliptical(b.x * t, b.y * t);
if (b == null) {
final double k = 1.0 - t;
return Radius.elliptical(a.x * k, a.y * k);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return Radius.elliptical(a.x * k, a.y * k);
}
} else {
if (a == null) {
return Radius.elliptical(b.x * t, b.y * t);
} else {
return Radius.elliptical(
_lerpDouble(a.x, b.x, t),
_lerpDouble(a.y, b.y, t),
);
}
}
return Radius.elliptical(
lerpDouble(a.x, b.x, t),
lerpDouble(a.y, b.y, t),
);
}
@override
......@@ -1540,57 +1562,61 @@ class RRect {
///
/// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController].
static RRect/*!*/ lerp(RRect/*?*/ a, RRect/*?*/ b, double/*!*/ t) {
static RRect/*?*/ lerp(RRect/*?*/ a, RRect/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null)
return null;
if (a == null) {
return RRect._raw(
left: b.left * t,
top: b.top * t,
right: b.right * t,
bottom: b.bottom * t,
tlRadiusX: b.tlRadiusX * t,
tlRadiusY: b.tlRadiusY * t,
trRadiusX: b.trRadiusX * t,
trRadiusY: b.trRadiusY * t,
brRadiusX: b.brRadiusX * t,
brRadiusY: b.brRadiusY * t,
blRadiusX: b.blRadiusX * t,
blRadiusY: b.blRadiusY * t,
);
}
if (b == null) {
final double k = 1.0 - t;
return RRect._raw(
left: a.left * k,
top: a.top * k,
right: a.right * k,
bottom: a.bottom * k,
tlRadiusX: a.tlRadiusX * k,
tlRadiusY: a.tlRadiusY * k,
trRadiusX: a.trRadiusX * k,
trRadiusY: a.trRadiusY * k,
brRadiusX: a.brRadiusX * k,
brRadiusY: a.brRadiusY * k,
blRadiusX: a.blRadiusX * k,
blRadiusY: a.blRadiusY * k,
);
if (a == null) {
return null;
} else {
final double k = 1.0 - t;
return RRect._raw(
left: a.left * k,
top: a.top * k,
right: a.right * k,
bottom: a.bottom * k,
tlRadiusX: a.tlRadiusX * k,
tlRadiusY: a.tlRadiusY * k,
trRadiusX: a.trRadiusX * k,
trRadiusY: a.trRadiusY * k,
brRadiusX: a.brRadiusX * k,
brRadiusY: a.brRadiusY * k,
blRadiusX: a.blRadiusX * k,
blRadiusY: a.blRadiusY * k,
);
}
} else {
if (a == null) {
return RRect._raw(
left: b.left * t,
top: b.top * t,
right: b.right * t,
bottom: b.bottom * t,
tlRadiusX: b.tlRadiusX * t,
tlRadiusY: b.tlRadiusY * t,
trRadiusX: b.trRadiusX * t,
trRadiusY: b.trRadiusY * t,
brRadiusX: b.brRadiusX * t,
brRadiusY: b.brRadiusY * t,
blRadiusX: b.blRadiusX * t,
blRadiusY: b.blRadiusY * t,
);
} else {
return RRect._raw(
left: _lerpDouble(a.left, b.left, t),
top: _lerpDouble(a.top, b.top, t),
right: _lerpDouble(a.right, b.right, t),
bottom: _lerpDouble(a.bottom, b.bottom, t),
tlRadiusX: _lerpDouble(a.tlRadiusX, b.tlRadiusX, t),
tlRadiusY: _lerpDouble(a.tlRadiusY, b.tlRadiusY, t),
trRadiusX: _lerpDouble(a.trRadiusX, b.trRadiusX, t),
trRadiusY: _lerpDouble(a.trRadiusY, b.trRadiusY, t),
brRadiusX: _lerpDouble(a.brRadiusX, b.brRadiusX, t),
brRadiusY: _lerpDouble(a.brRadiusY, b.brRadiusY, t),
blRadiusX: _lerpDouble(a.blRadiusX, b.blRadiusX, t),
blRadiusY: _lerpDouble(a.blRadiusY, b.blRadiusY, t),
);
}
}
return RRect._raw(
left: lerpDouble(a.left, b.left, t),
top: lerpDouble(a.top, b.top, t),
right: lerpDouble(a.right, b.right, t),
bottom: lerpDouble(a.bottom, b.bottom, t),
tlRadiusX: lerpDouble(a.tlRadiusX, b.tlRadiusX, t),
tlRadiusY: lerpDouble(a.tlRadiusY, b.tlRadiusY, t),
trRadiusX: lerpDouble(a.trRadiusX, b.trRadiusX, t),
trRadiusY: lerpDouble(a.trRadiusY, b.trRadiusY, t),
brRadiusX: lerpDouble(a.brRadiusX, b.brRadiusX, t),
brRadiusY: lerpDouble(a.brRadiusY, b.brRadiusY, t),
blRadiusX: lerpDouble(a.blRadiusX, b.blRadiusX, t),
blRadiusY: lerpDouble(a.blRadiusY, b.blRadiusY, t),
);
}
@override
......
......@@ -114,7 +114,7 @@ int/*!*/ hashValues(
/// Combine the [Object.hashCode] values of an arbitrary number of objects from
/// an [Iterable] into one value. This function will return the same value if
/// given null as if given an empty list.
int/*!*/ hashList(Iterable<Object/*?*/>/*!*/ arguments) {
int/*!*/ hashList(Iterable<Object/*?*/>/*?*/ arguments) {
int result = 0;
if (arguments != null) {
for (Object argument in arguments)
......
......@@ -45,7 +45,8 @@ Future<void> _initializePlatform({
_webOnlyIsInitialized = true;
}
/*late*/ engine.AssetManager/*!*/ _assetManager;
// TODO(yjbanov): can we make this late non-null? See https://github.com/dart-lang/sdk/issues/42214
engine.AssetManager/*?*/ _assetManager;
engine.FontCollection _fontCollection;
bool _webOnlyIsInitialized = false;
......@@ -106,7 +107,7 @@ set debugEmulateFlutterTesterEnvironment(bool/*!*/ value) {
bool _debugEmulateFlutterTesterEnvironment = false;
/// This class handles downloading assets over the network.
engine.AssetManager get webOnlyAssetManager => _assetManager;
engine.AssetManager/*!*/ get webOnlyAssetManager => _assetManager;
/// A collection of fonts that may be used by the platform.
engine.FontCollection get webOnlyFontCollection => _fontCollection;
engine.FontCollection/*!*/ get webOnlyFontCollection => _fontCollection;
......@@ -6,7 +6,7 @@
part of ui;
/// Linearly interpolate between two numbers.
double/*!*/ lerpDouble(num/*?*/ a, num/*?*/ b, double/*!*/ t) {
double/*?*/ lerpDouble(num/*?*/ a, num/*?*/ b, double/*!*/ t) {
if (a == null && b == null) {
return null;
}
......@@ -14,3 +14,23 @@ double/*!*/ lerpDouble(num/*?*/ a, num/*?*/ b, double/*!*/ t) {
b ??= 0.0;
return a + (b - a) * t;
}
double/*!*/ _lerpDouble(double/*!*/ a, double/*!*/ b, double/*!*/ t) {
return a + (b - a) * t;
}
double/*!*/ _lerpInt(int/*!*/ a, int/*!*/ b, double/*!*/ t) {
return a + (b - a) * t;
}
/// Same as [num.clamp] but specialized for [int].
int/*!*/ _clampInt(int/*!*/ value, int/*!*/ min, int/*!*/ max) {
assert(min <= max);
if (value < min) {
return min;
} else if (value > max) {
return max;
} else {
return value;
}
}
......@@ -33,7 +33,7 @@ void _validateColorStops(List<Color> colors, List<double> colorStops) {
}
Color _scaleAlpha(Color a, double factor) {
return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
return a.withAlpha(_clampInt((a.alpha * factor).round(), 0, 255));
}
/// An immutable 32 bit color value in ARGB
......@@ -172,21 +172,24 @@ class Color {
/// an [AnimationController].
static Color/*?*/ lerp(Color/*?*/ a, Color/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null) {
return null;
}
if (a == null) {
return _scaleAlpha(b, t);
}
if (b == null) {
return _scaleAlpha(a, 1.0 - t);
if (a == null) {
return null;
} else {
return _scaleAlpha(a, 1.0 - t);
}
} else {
if (a == null) {
return _scaleAlpha(b, t);
} else {
return Color.fromARGB(
_clampInt(_lerpInt(a.alpha, b.alpha, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.red, b.red, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.green, b.green, t).toInt(), 0, 255),
_clampInt(_lerpInt(a.blue, b.blue, t).toInt(), 0, 255),
);
}
}
return Color.fromARGB(
lerpDouble(a.alpha, b.alpha, t).toInt().clamp(0, 255),
lerpDouble(a.red, b.red, t).toInt().clamp(0, 255),
lerpDouble(a.green, b.green, t).toInt().clamp(0, 255),
lerpDouble(a.blue, b.blue, t).toInt().clamp(0, 255),
);
}
/// Combine the foreground color as a transparent color over top
......@@ -1187,7 +1190,7 @@ abstract class Gradient extends Shader {
Float64List/*?*/ matrix4,
]) =>
engine.GradientSweep(
center, colors, colorStops, tileMode, startAngle, endAngle, engine.toMatrix32(matrix4));
center, colors, colorStops, tileMode, startAngle, endAngle, matrix4 != null ? engine.toMatrix32(matrix4) : null);
}
/// Opaque handle to raw decoded image data (pixels).
......@@ -1528,7 +1531,7 @@ abstract class FrameInfo {
int get _durationMillis => 0;
/// The [Image] object for this frame.
Image get image => null;
Image/*!*/ get image;
}
/// A handle to an image codec.
......@@ -1555,7 +1558,7 @@ class Codec {
///
/// The returned future can complete with an error if the decoding has failed.
Future<FrameInfo/*!*/>/*!*/ getNextFrame() {
return engine.futurize(_getNextFrame);
return engine.futurize<FrameInfo/*!*/>(_getNextFrame);
}
/// Returns an error message on failure, null on success.
......@@ -1580,7 +1583,7 @@ Future<Codec/*!*/>/*!*/ instantiateImageCodec(
int/*?*/ targetWidth,
int/*?*/ targetHeight,
}) {
return engine.futurize((engine.Callback<Codec> callback) =>
return engine.futurize<Codec/*!*/>((engine.Callback<Codec> callback) =>
// TODO: Implement targetWidth and targetHeight support.
_instantiateImageCodec(list, callback, null));
}
......@@ -1604,9 +1607,9 @@ String/*?*/ _instantiateImageCodec(
return null;
}
Future<Codec/*?*/> webOnlyInstantiateImageCodecFromUrl(Uri/*!*/ uri,
Future<Codec/*?*/>/*!*/ webOnlyInstantiateImageCodecFromUrl(Uri/*!*/ uri,
{engine.WebOnlyImageCodecChunkCallback/*?*/ chunkCallback}) {
return engine.futurize((engine.Callback<Codec> callback) =>
return engine.futurize<Codec/*?*/>((engine.Callback<Codec> callback) =>
_instantiateImageCodecFromUrl(uri, chunkCallback, callback));
}
......@@ -1760,20 +1763,23 @@ class Shadow {
/// {@endtemplate}
static Shadow/*?*/ lerp(Shadow/*?*/ a, Shadow/*?*/ b, double/*!*/ t) {
assert(t != null);
if (a == null && b == null) {
return null;
}
if (a == null) {
return b.scale(t);
}
if (b == null) {
return a.scale(1.0 - t);
if (a == null) {
return null;
} else {
return a.scale(1.0 - t);
}
} else {
if (a == null) {
return b.scale(t);
} else {
return Shadow(
color: Color.lerp(a.color, b.color, t),
offset: Offset.lerp(a.offset, b.offset, t),
blurRadius: _lerpDouble(a.blurRadius, b.blurRadius, t),
);
}
}
return Shadow(
color: Color.lerp(a.color, b.color, t),
offset: Offset.lerp(a.offset, b.offset, t),
blurRadius: lerpDouble(a.blurRadius, b.blurRadius, t),
);
}
/// Linearly interpolate between two lists of shadows.
......@@ -1788,7 +1794,7 @@ class Shadow {
}
a ??= <Shadow>[];
b ??= <Shadow>[];
final List<Shadow> result = <Shadow>[];
final List<Shadow/*!*/> result = <Shadow/*!*/>[];
final int commonLength = math.min(a.length, b.length);
for (int i = 0; i < commonLength; i += 1)
result.add(Shadow.lerp(a[i], b[i], t));
......
......@@ -27,7 +27,8 @@ Future<dynamic>/*!*/ ensureTestPlatformInitializedThenRunTest(
/// Used to track when the platform is initialized. This ensures the test fonts
/// are available.
/*late*/ Future<void>/*!*/ _platformInitializedFuture;
// TODO(yjbanov): can we make this late non-null? See https://github.com/dart-lang/sdk/issues/42214
Future<void>/*?*/ _platformInitializedFuture;
/// Initializes domRenderer with specific devicePixelRatio and physicalSize.
Future<void>/*!*/ webOnlyInitializeTestDomRenderer({double/*!*/ devicePixelRatio = 3.0}) {
......
......@@ -135,7 +135,7 @@ class FontWeight {
assert(t != null);
if (a == null && b == null)
return null;
return values[lerpDouble(a?.index ?? normal.index, b?.index ?? normal.index, t).round().clamp(0, 8) as int];
return values[_clampInt(lerpDouble(a?.index ?? normal.index, b?.index ?? normal.index, t).round(), 0, 8)];
}
@override
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册