mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Update canvaskit backend (#12318)
* Improve the CanvasKit backend for Flutter Web - Improve font handling by trying to load a "normal" font face instead of using the first face matching the family. - Implement Vertices and drawVertices * Add license header to vertices.dart * Remove unused 'encodedPositions' * Delete commented old code. Don't use Skia by default * Add `vertices.dart` to licenses file
This commit is contained in:
parent
b790d48ebc
commit
d1692d4cc7
@ -372,6 +372,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/recording_canvas.dar
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/runtime_delegate.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/surface.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/util.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/vertices.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/compositor/viewport_metrics.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/conic.dart
|
||||
FILE: ../../../flutter/lib/web_ui/lib/src/engine/dom_canvas.dart
|
||||
|
||||
@ -41,6 +41,7 @@ part 'engine/compositor/recording_canvas.dart';
|
||||
part 'engine/compositor/runtime_delegate.dart';
|
||||
part 'engine/compositor/surface.dart';
|
||||
part 'engine/compositor/util.dart';
|
||||
part 'engine/compositor/vertices.dart';
|
||||
part 'engine/compositor/viewport_metrics.dart';
|
||||
part 'engine/conic.dart';
|
||||
part 'engine/dom_canvas.dart';
|
||||
|
||||
@ -73,13 +73,35 @@ class SkiaFontCollection {
|
||||
|
||||
js.JsObject getFont(String family, double size) {
|
||||
if (_registeredTypefaces[family] == null) {
|
||||
if (family == 'sans-serif') {
|
||||
// If it's the default font, return a default SkFont
|
||||
return js.JsObject(canvasKit['SkFont'], <dynamic>[null, size]);
|
||||
if (assertionsEnabled) {
|
||||
html.window.console.warn('Using unregistered font: $family');
|
||||
}
|
||||
throw Exception('Unregistered font: $family');
|
||||
return js.JsObject(canvasKit['SkFont'], <dynamic>[null, size]);
|
||||
}
|
||||
final js.JsObject skTypeface = _registeredTypefaces[family].values.first;
|
||||
|
||||
// We don't attempt to find a Typeface matching the text style. Instead, we
|
||||
// try to find the "default" typeface. The default typeface either has no
|
||||
// descriptors, or only has a descriptor of font-weight 400 (the default).
|
||||
final Map<Map<String, String>, js.JsObject> typefaces =
|
||||
_registeredTypefaces[family];
|
||||
js.JsObject skTypeface;
|
||||
|
||||
for (MapEntry<Map<String, String>, js.JsObject> entry
|
||||
in typefaces.entries) {
|
||||
final Map<String, String> descriptors = entry.key;
|
||||
if (descriptors.isEmpty ||
|
||||
(descriptors.length == 1 && descriptors['weight'] == '400')) {
|
||||
skTypeface = entry.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't find a suitable default, just use any typeface in the
|
||||
// family.
|
||||
if (skTypeface == null) {
|
||||
skTypeface = typefaces.values.first;
|
||||
}
|
||||
|
||||
return js.JsObject(canvasKit['SkFont'], <dynamic>[skTypeface, size]);
|
||||
}
|
||||
|
||||
|
||||
@ -220,6 +220,17 @@ class SkRecordingCanvas implements RecordingCanvas {
|
||||
drawSkShadow(skCanvas, path, color, elevation, transparentOccluder);
|
||||
}
|
||||
|
||||
@override
|
||||
void drawVertices(
|
||||
ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) {
|
||||
SkVertices skVertices = vertices;
|
||||
skCanvas.callMethod('drawVertices', <js.JsObject>[
|
||||
skVertices.skVertices,
|
||||
makeSkBlendMode(blendMode),
|
||||
makeSkPaint(paint)
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get hasArbitraryPaint => true;
|
||||
|
||||
|
||||
@ -17,6 +17,71 @@ js.JsArray<double> makeSkPoint(ui.Offset point) {
|
||||
return skPoint;
|
||||
}
|
||||
|
||||
js.JsObject makeSkBlendMode(ui.BlendMode blendMode) {
|
||||
switch (blendMode) {
|
||||
case ui.BlendMode.clear:
|
||||
return canvasKit['BlendMode']['Clear'];
|
||||
case ui.BlendMode.src:
|
||||
return canvasKit['BlendMode']['Src'];
|
||||
case ui.BlendMode.dst:
|
||||
return canvasKit['BlendMode']['Dst'];
|
||||
case ui.BlendMode.srcOver:
|
||||
return canvasKit['BlendMode']['SrcOver'];
|
||||
case ui.BlendMode.dstOver:
|
||||
return canvasKit['BlendMode']['DstOver'];
|
||||
case ui.BlendMode.srcIn:
|
||||
return canvasKit['BlendMode']['SrcIn'];
|
||||
case ui.BlendMode.dstIn:
|
||||
return canvasKit['BlendMode']['DstIn'];
|
||||
case ui.BlendMode.srcOut:
|
||||
return canvasKit['BlendMode']['SrcOut'];
|
||||
case ui.BlendMode.dstOut:
|
||||
return canvasKit['BlendMode']['DstOut'];
|
||||
case ui.BlendMode.srcATop:
|
||||
return canvasKit['BlendMode']['SrcATop'];
|
||||
case ui.BlendMode.dstATop:
|
||||
return canvasKit['BlendMode']['DstATop'];
|
||||
case ui.BlendMode.xor:
|
||||
return canvasKit['BlendMode']['Xor'];
|
||||
case ui.BlendMode.plus:
|
||||
return canvasKit['BlendMode']['Plus'];
|
||||
case ui.BlendMode.modulate:
|
||||
return canvasKit['BlendMode']['Modulate'];
|
||||
case ui.BlendMode.screen:
|
||||
return canvasKit['BlendMode']['Screen'];
|
||||
case ui.BlendMode.overlay:
|
||||
return canvasKit['BlendMode']['Overlay'];
|
||||
case ui.BlendMode.darken:
|
||||
return canvasKit['BlendMode']['Darken'];
|
||||
case ui.BlendMode.lighten:
|
||||
return canvasKit['BlendMode']['Lighten'];
|
||||
case ui.BlendMode.colorDodge:
|
||||
return canvasKit['BlendMode']['ColorDodge'];
|
||||
case ui.BlendMode.colorBurn:
|
||||
return canvasKit['BlendMode']['ColorBurn'];
|
||||
case ui.BlendMode.hardLight:
|
||||
return canvasKit['BlendMode']['HardLight'];
|
||||
case ui.BlendMode.softLight:
|
||||
return canvasKit['BlendMode']['SoftLight'];
|
||||
case ui.BlendMode.difference:
|
||||
return canvasKit['BlendMode']['Difference'];
|
||||
case ui.BlendMode.exclusion:
|
||||
return canvasKit['BlendMode']['Exclusion'];
|
||||
case ui.BlendMode.multiply:
|
||||
return canvasKit['BlendMode']['Multiply'];
|
||||
case ui.BlendMode.hue:
|
||||
return canvasKit['BlendMode']['Hue'];
|
||||
case ui.BlendMode.saturation:
|
||||
return canvasKit['BlendMode']['Saturation'];
|
||||
case ui.BlendMode.color:
|
||||
return canvasKit['BlendMode']['Color'];
|
||||
case ui.BlendMode.luminosity:
|
||||
return canvasKit['BlendMode']['Luminosity'];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
js.JsObject makeSkPaint(ui.Paint paint) {
|
||||
final dynamic skPaint = js.JsObject(canvasKit['SkPaint']);
|
||||
|
||||
@ -41,124 +106,7 @@ js.JsObject makeSkPaint(ui.Paint paint) {
|
||||
}
|
||||
skPaint.callMethod('setStyle', <js.JsObject>[skPaintStyle]);
|
||||
|
||||
js.JsObject skBlendMode;
|
||||
switch (paint.blendMode) {
|
||||
case ui.BlendMode.clear:
|
||||
skBlendMode = canvasKit['BlendMode']['Clear'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.src:
|
||||
skBlendMode = canvasKit['BlendMode']['Src'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.dst:
|
||||
skBlendMode = canvasKit['BlendMode']['Dst'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.srcOver:
|
||||
skBlendMode = canvasKit['BlendMode']['SrcOver'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.dstOver:
|
||||
skBlendMode = canvasKit['BlendMode']['DstOver'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.srcIn:
|
||||
skBlendMode = canvasKit['BlendMode']['SrcIn'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.dstIn:
|
||||
skBlendMode = canvasKit['BlendMode']['DstIn'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.srcOut:
|
||||
skBlendMode = canvasKit['BlendMode']['SrcOut'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.dstOut:
|
||||
skBlendMode = canvasKit['BlendMode']['DstOut'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.srcATop:
|
||||
skBlendMode = canvasKit['BlendMode']['SrcATop'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.dstATop:
|
||||
skBlendMode = canvasKit['BlendMode']['DstATop'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.xor:
|
||||
skBlendMode = canvasKit['BlendMode']['Xor'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.plus:
|
||||
skBlendMode = canvasKit['BlendMode']['Plus'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.modulate:
|
||||
skBlendMode = canvasKit['BlendMode']['Modulate'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.screen:
|
||||
skBlendMode = canvasKit['BlendMode']['Screen'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.overlay:
|
||||
skBlendMode = canvasKit['BlendMode']['Overlay'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.darken:
|
||||
skBlendMode = canvasKit['BlendMode']['Darken'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.lighten:
|
||||
skBlendMode = canvasKit['BlendMode']['Lighten'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.colorDodge:
|
||||
skBlendMode = canvasKit['BlendMode']['ColorDodge'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.colorBurn:
|
||||
skBlendMode = canvasKit['BlendMode']['ColorBurn'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.hardLight:
|
||||
skBlendMode = canvasKit['BlendMode']['HardLight'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.softLight:
|
||||
skBlendMode = canvasKit['BlendMode']['SoftLight'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.difference:
|
||||
skBlendMode = canvasKit['BlendMode']['Difference'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.exclusion:
|
||||
skBlendMode = canvasKit['BlendMode']['Exclusion'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.multiply:
|
||||
skBlendMode = canvasKit['BlendMode']['Multiply'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.hue:
|
||||
skBlendMode = canvasKit['BlendMode']['Hue'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.saturation:
|
||||
skBlendMode = canvasKit['BlendMode']['Saturation'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.color:
|
||||
skBlendMode = canvasKit['BlendMode']['Color'];
|
||||
break;
|
||||
|
||||
case ui.BlendMode.luminosity:
|
||||
skBlendMode = canvasKit['BlendMode']['Luminosity'];
|
||||
break;
|
||||
}
|
||||
js.JsObject skBlendMode = makeSkBlendMode(paint.blendMode);
|
||||
if (skBlendMode != null) {
|
||||
skPaint.callMethod('setBlendMode', <js.JsObject>[skBlendMode]);
|
||||
}
|
||||
|
||||
133
lib/web_ui/lib/src/engine/compositor/vertices.dart
Normal file
133
lib/web_ui/lib/src/engine/compositor/vertices.dart
Normal file
@ -0,0 +1,133 @@
|
||||
// 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.
|
||||
|
||||
part of engine;
|
||||
|
||||
Int32List _encodeColorList(List<ui.Color> colors) {
|
||||
final int colorCount = colors.length;
|
||||
final Int32List result = Int32List(colorCount);
|
||||
for (int i = 0; i < colorCount; ++i) result[i] = colors[i].value;
|
||||
return result;
|
||||
}
|
||||
|
||||
Float32List _encodePointList(List<ui.Offset> points) {
|
||||
assert(points != null);
|
||||
final int pointCount = points.length;
|
||||
final Float32List result = Float32List(pointCount * 2);
|
||||
for (int i = 0; i < pointCount; ++i) {
|
||||
final int xIndex = i * 2;
|
||||
final int yIndex = xIndex + 1;
|
||||
final ui.Offset point = points[i];
|
||||
assert(_offsetIsValid(point));
|
||||
result[xIndex] = point.dx;
|
||||
result[yIndex] = point.dy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class SkVertices implements ui.Vertices {
|
||||
js.JsObject skVertices;
|
||||
|
||||
SkVertices(
|
||||
ui.VertexMode mode,
|
||||
List<ui.Offset> positions, {
|
||||
List<ui.Offset> textureCoordinates,
|
||||
List<ui.Color> colors,
|
||||
List<int> indices,
|
||||
}) : assert(mode != null),
|
||||
assert(positions != null) {
|
||||
if (textureCoordinates != null &&
|
||||
textureCoordinates.length != positions.length)
|
||||
throw ArgumentError(
|
||||
'"positions" and "textureCoordinates" lengths must match.');
|
||||
if (colors != null && colors.length != positions.length)
|
||||
throw ArgumentError('"positions" and "colors" lengths must match.');
|
||||
if (indices != null &&
|
||||
indices.any((int i) => i < 0 || i >= positions.length))
|
||||
throw ArgumentError(
|
||||
'"indices" values must be valid indices in the positions list.');
|
||||
|
||||
final Float32List encodedPositions = _encodePointList(positions);
|
||||
final Float32List encodedTextureCoordinates = (textureCoordinates != null)
|
||||
? _encodePointList(textureCoordinates)
|
||||
: null;
|
||||
final Int32List encodedColors =
|
||||
colors != null ? _encodeColorList(colors) : null;
|
||||
final Uint16List encodedIndices =
|
||||
indices != null ? Uint16List.fromList(indices) : null;
|
||||
|
||||
if (!_init(mode, encodedPositions, encodedTextureCoordinates, encodedColors,
|
||||
encodedIndices))
|
||||
throw ArgumentError('Invalid configuration for vertices.');
|
||||
}
|
||||
|
||||
SkVertices.raw(
|
||||
ui.VertexMode mode,
|
||||
Float32List positions, {
|
||||
Float32List textureCoordinates,
|
||||
Int32List colors,
|
||||
Uint16List indices,
|
||||
}) : assert(mode != null),
|
||||
assert(positions != null) {
|
||||
if (textureCoordinates != null &&
|
||||
textureCoordinates.length != positions.length)
|
||||
throw ArgumentError(
|
||||
'"positions" and "textureCoordinates" lengths must match.');
|
||||
if (colors != null && colors.length * 2 != positions.length)
|
||||
throw ArgumentError('"positions" and "colors" lengths must match.');
|
||||
if (indices != null &&
|
||||
indices.any((int i) => i < 0 || i >= positions.length))
|
||||
throw ArgumentError(
|
||||
'"indices" values must be valid indices in the positions list.');
|
||||
|
||||
if (!_init(mode, positions, textureCoordinates, colors, indices))
|
||||
throw ArgumentError('Invalid configuration for vertices.');
|
||||
}
|
||||
|
||||
bool _init(ui.VertexMode mode, Float32List positions,
|
||||
Float32List textureCoordinates, Int32List colors, Uint16List indices) {
|
||||
js.JsObject skVertexMode;
|
||||
switch (mode) {
|
||||
case ui.VertexMode.triangles:
|
||||
skVertexMode = canvasKit['VertexMode']['Triangles'];
|
||||
break;
|
||||
case ui.VertexMode.triangleStrip:
|
||||
skVertexMode = canvasKit['VertexMode']['TrianglesStrip'];
|
||||
break;
|
||||
case ui.VertexMode.triangleFan:
|
||||
skVertexMode = canvasKit['VertexMode']['TriangleFan'];
|
||||
break;
|
||||
}
|
||||
|
||||
final js.JsObject vertices =
|
||||
canvasKit.callMethod('MakeSkVertices', <dynamic>[
|
||||
skVertexMode,
|
||||
_encodePoints(positions),
|
||||
_encodePoints(textureCoordinates),
|
||||
colors,
|
||||
null,
|
||||
null,
|
||||
indices,
|
||||
]);
|
||||
|
||||
if (vertices != null) {
|
||||
skVertices = vertices;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static _encodePoints(List<double> points) {
|
||||
if (points == null) return null;
|
||||
|
||||
js.JsArray<js.JsArray<double>> encodedPoints =
|
||||
js.JsArray<js.JsArray<double>>();
|
||||
encodedPoints.length = points.length ~/ 2;
|
||||
for (int i = 0; i < points.length; i += 2) {
|
||||
encodedPoints[i ~/ 2] = makeSkPoint(ui.Offset(points[i], points[i + 1]));
|
||||
}
|
||||
return encodedPoints;
|
||||
}
|
||||
}
|
||||
@ -347,6 +347,10 @@ class RecordingCanvas {
|
||||
_commands.add(PaintDrawShadow(path, color, elevation, transparentOccluder));
|
||||
}
|
||||
|
||||
void drawVertices(ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) {
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
int saveCount = 1;
|
||||
|
||||
/// Prints the commands recorded by this canvas to the console.
|
||||
|
||||
@ -59,23 +59,37 @@ enum VertexMode {
|
||||
|
||||
/// A set of vertex data used by [Canvas.drawVertices].
|
||||
class Vertices {
|
||||
Vertices(
|
||||
factory Vertices(
|
||||
VertexMode mode,
|
||||
List<Offset> positions, {
|
||||
List<Offset> textureCoordinates,
|
||||
List<Color> colors,
|
||||
List<int> indices,
|
||||
}) : assert(mode != null),
|
||||
assert(positions != null);
|
||||
}) {
|
||||
if (engine.experimentalUseSkia) {
|
||||
return engine.SkVertices(mode, positions,
|
||||
textureCoordinates: textureCoordinates,
|
||||
colors: colors,
|
||||
indices: indices);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Vertices.raw(
|
||||
factory Vertices.raw(
|
||||
VertexMode mode,
|
||||
Float32List positions, {
|
||||
Float32List textureCoordinates,
|
||||
Int32List colors,
|
||||
Uint16List indices,
|
||||
}) : assert(mode != null),
|
||||
assert(positions != null);
|
||||
}) {
|
||||
if (engine.experimentalUseSkia) {
|
||||
return engine.SkVertices.raw(mode, positions,
|
||||
textureCoordinates: textureCoordinates,
|
||||
colors: colors,
|
||||
indices: indices);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Records a [Picture] containing a sequence of graphical operations.
|
||||
@ -877,7 +891,7 @@ class Canvas {
|
||||
assert(vertices != null); // vertices is checked on the engine side
|
||||
assert(paint != null);
|
||||
assert(blendMode != null);
|
||||
throw UnimplementedError();
|
||||
_canvas.drawVertices(vertices, blendMode, paint);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user