diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6eaaf9ed09c06..20f5b456aac7f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -446,7 +446,6 @@ FILE: ../../../flutter/lib/ui/window/window.h FILE: ../../../flutter/lib/web_ui/lib/src/engine.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/alarm_clock.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/assets.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/bitmap_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/browser_detection.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvas_pool.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvas.dart @@ -482,16 +481,17 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/color_filter.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/dom_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/dom_renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/engine_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/font_change_util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/frame_reference.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/backdrop_filter.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/clip.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/color_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/debug_canvas_reuse_overlay.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/dom_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/image_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/offscreen_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/offset.dart @@ -515,6 +515,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/render_vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/scene.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shader_mask.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/shader.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 7431a9799d5c1..a09e1bb6f99b1 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -41,7 +41,6 @@ export 'engine/browser_detection.dart'; import 'engine/html_image_codec.dart'; export 'engine/html_image_codec.dart'; -import 'engine/html/offscreen_canvas.dart'; export 'engine/html/offscreen_canvas.dart'; import 'engine/html/painting.dart'; @@ -77,16 +76,21 @@ export 'engine/html/path/path_windings.dart'; import 'engine/html/path/tangent.dart'; export 'engine/html/path/tangent.dart'; -import 'engine/html/shaders/normalized_gradient.dart'; +import 'engine/html/render_vertices.dart'; +export 'engine/html/render_vertices.dart'; + +import 'engine/html/shaders/image_shader.dart'; +export 'engine/html/shaders/image_shader.dart'; + export 'engine/html/shaders/normalized_gradient.dart'; -import 'engine/html/shaders/shader_builder.dart'; +import 'engine/html/shaders/shader.dart'; +export 'engine/html/shaders/shader.dart'; + export 'engine/html/shaders/shader_builder.dart'; -import 'engine/html/shaders/vertex_shaders.dart'; export 'engine/html/shaders/vertex_shaders.dart'; -import 'engine/html/shaders/webgl_context.dart'; export 'engine/html/shaders/webgl_context.dart'; import 'engine/mouse_cursor.dart'; @@ -131,9 +135,6 @@ export 'engine/shadow.dart'; import 'engine/test_embedding.dart'; export 'engine/test_embedding.dart'; -import 'engine/ulps.dart'; -export 'engine/ulps.dart'; - import 'engine/util.dart'; export 'engine/util.dart'; @@ -147,7 +148,7 @@ import 'engine/web_experiments.dart'; export 'engine/web_experiments.dart'; part 'engine/assets.dart'; -part 'engine/bitmap_canvas.dart'; +part 'engine/html/bitmap_canvas.dart'; part 'engine/canvaskit/canvas.dart'; part 'engine/canvaskit/canvaskit_canvas.dart'; part 'engine/canvaskit/canvaskit_api.dart'; @@ -182,7 +183,7 @@ part 'engine/canvaskit/viewport_metrics.dart'; part 'engine/canvas_pool.dart'; part 'engine/clipboard.dart'; part 'engine/color_filter.dart'; -part 'engine/dom_canvas.dart'; +part 'engine/html/dom_canvas.dart'; part 'engine/dom_renderer.dart'; part 'engine/engine_canvas.dart'; part 'engine/font_change_util.dart'; @@ -199,11 +200,9 @@ part 'engine/html/path/path.dart'; part 'engine/html/picture.dart'; part 'engine/html/platform_view.dart'; part 'engine/html/recording_canvas.dart'; -part 'engine/html/render_vertices.dart'; part 'engine/html/scene.dart'; part 'engine/html/scene_builder.dart'; part 'engine/html/shader_mask.dart'; -part 'engine/html/shaders/shader.dart'; part 'engine/html/surface.dart'; part 'engine/html/surface_stats.dart'; part 'engine/html/transform.dart'; @@ -247,14 +246,13 @@ part 'engine/window.dart'; // The mode the app is running in. // Keep these in sync with the same constants on the framework-side under foundation/constants.dart. -const bool kReleaseMode = bool.fromEnvironment('dart.vm.product', defaultValue: false); -const bool kProfileMode = bool.fromEnvironment('dart.vm.profile', defaultValue: false); +const bool kReleaseMode = + bool.fromEnvironment('dart.vm.product', defaultValue: false); +const bool kProfileMode = + bool.fromEnvironment('dart.vm.profile', defaultValue: false); const bool kDebugMode = !kReleaseMode && !kProfileMode; -String get buildMode => kReleaseMode - ? 'release' - : kProfileMode - ? 'profile' - : 'debug'; +String get buildMode => + kReleaseMode ? 'release' : kProfileMode ? 'profile' : 'debug'; /// A benchmark metric that includes frame-related computations prior to /// submitting layer and picture operations to the underlying renderer, such as diff --git a/lib/web_ui/lib/src/engine/bitmap_canvas.dart b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart similarity index 99% rename from lib/web_ui/lib/src/engine/bitmap_canvas.dart rename to lib/web_ui/lib/src/engine/html/bitmap_canvas.dart index b5af3350d356e..c40cdd8d03863 100644 --- a/lib/web_ui/lib/src/engine/bitmap_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart @@ -965,25 +965,25 @@ class BitmapCanvas extends EngineCanvas { // as well. assert(paint.shader == null || paint.shader is EngineImageShader, 'Linear/Radial/SweepGradient 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 && paint.style != ui.PaintingStyle.fill && paint.shader == 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); _canvasPool.contextHandle ..fillStyle = null ..strokeStyle = colorToCssString(color); - _glRenderer!.drawHairline(ctx, positions); + glRenderer!.drawHairline(ctx, positions); restore(); return; } - _glRenderer!.drawVertices(ctx, _widthInBitmapPixels, _heightInBitmapPixels, + glRenderer!.drawVertices(ctx, _widthInBitmapPixels, _heightInBitmapPixels, _canvasPool.currentTransform, vertices, blendMode, paint); } diff --git a/lib/web_ui/lib/src/engine/dom_canvas.dart b/lib/web_ui/lib/src/engine/html/dom_canvas.dart similarity index 100% rename from lib/web_ui/lib/src/engine/dom_canvas.dart rename to lib/web_ui/lib/src/engine/html/dom_canvas.dart diff --git a/lib/web_ui/lib/src/engine/html/recording_canvas.dart b/lib/web_ui/lib/src/engine/html/recording_canvas.dart index 861fd0c966630..85b7a4be932d6 100644 --- a/lib/web_ui/lib/src/engine/html/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/recording_canvas.dart @@ -321,7 +321,8 @@ class RecordingCanvas { void drawLine(ui.Offset p1, ui.Offset p2, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); final double paintSpread = math.max(_getPaintSpread(paint), 1.0); final PaintDrawLine command = PaintDrawLine(p1, p2, paint.paintData); // TODO(yjbanov): This can be optimized. Currently we create a box around @@ -345,7 +346,8 @@ class RecordingCanvas { void drawPaint(SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); renderStrategy.hasArbitraryPaint = true; _didDraw = true; final PaintDrawPaint command = PaintDrawPaint(paint.paintData); @@ -355,7 +357,8 @@ class RecordingCanvas { void drawRect(ui.Rect rect, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); if (paint.shader != null) { renderStrategy.hasArbitraryPaint = true; } @@ -372,7 +375,8 @@ class RecordingCanvas { void drawRRect(ui.RRect rrect, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); if (paint.shader != null || !rrect.webOnlyUniformRadii) { renderStrategy.hasArbitraryPaint = true; } @@ -389,7 +393,8 @@ class RecordingCanvas { void drawDRRect(ui.RRect outer, ui.RRect inner, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); // Check the inner bounds are contained within the outer bounds // see: https://cs.chromium.org/chromium/src/third_party/skia/src/core/SkCanvas.cpp?l=1787-1789 ui.Rect innerRect = inner.outerRect; @@ -448,7 +453,8 @@ class RecordingCanvas { void drawOval(ui.Rect rect, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); renderStrategy.hasArbitraryPaint = true; _didDraw = true; final double paintSpread = _getPaintSpread(paint); @@ -463,7 +469,8 @@ class RecordingCanvas { void drawCircle(ui.Offset c, double radius, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); renderStrategy.hasArbitraryPaint = true; _didDraw = true; final double paintSpread = _getPaintSpread(paint); @@ -481,7 +488,8 @@ class RecordingCanvas { void drawPath(ui.Path path, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); if (paint.shader == null) { // For Rect/RoundedRect paths use drawRect/drawRRect code paths for // DomCanvas optimization. @@ -518,7 +526,8 @@ class RecordingCanvas { void drawImage(ui.Image image, ui.Offset offset, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); renderStrategy.hasArbitraryPaint = true; renderStrategy.hasImageElements = true; _didDraw = true; @@ -556,7 +565,8 @@ class RecordingCanvas { void drawImageRect( ui.Image image, ui.Rect src, ui.Rect dst, SurfacePaint paint) { assert(!_recordingEnded); - assert(paint.shader == null || paint.shader is! EngineImageShader, 'ImageShader not supported yet'); + assert(paint.shader == null || paint.shader is! EngineImageShader, + 'ImageShader not supported yet'); renderStrategy.hasArbitraryPaint = true; renderStrategy.hasImageElements = true; _didDraw = true; @@ -613,7 +623,7 @@ class RecordingCanvas { _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); } diff --git a/lib/web_ui/lib/src/engine/html/render_vertices.dart b/lib/web_ui/lib/src/engine/html/render_vertices.dart index 8474d949fdb51..ed6a097d89f2f 100644 --- a/lib/web_ui/lib/src/engine/html/render_vertices.dart +++ b/lib/web_ui/lib/src/engine/html/render_vertices.dart @@ -2,41 +2,51 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -part of engine; +import 'dart:html' as html; +import 'dart:js_util' as js_util; +import 'dart:math' as math; +import 'dart:typed_data'; -_GlRenderer? _glRenderer; +import 'package:ui/ui.dart' as ui; + +import '../browser_detection.dart'; +import '../util.dart'; +import '../vector_math.dart'; +import 'painting.dart'; +import 'shaders/image_shader.dart'; +import 'shaders/shader_builder.dart'; +import 'shaders/normalized_gradient.dart'; +import 'shaders/vertex_shaders.dart'; +import 'shaders/webgl_context.dart'; + +GlRenderer? glRenderer; class SurfaceVertices implements ui.Vertices { - final ui.VertexMode _mode; - final Float32List _positions; - final Int32List? _colors; - final Uint16List? _indices; // ignore: unused_field + final ui.VertexMode mode; + final Float32List positions; + final Int32List? colors; + final Uint16List? indices; // ignore: unused_field SurfaceVertices( - ui.VertexMode mode, + this.mode, List positions, { List? colors, List? indices, }) : assert(mode != null), // ignore: unnecessary_null_comparison assert(positions != null), // ignore: unnecessary_null_comparison - _mode = mode, - _colors = colors != null ? _int32ListFromColors(colors) : null, - _indices = indices != null ? Uint16List.fromList(indices) : null, - _positions = offsetListToFloat32List(positions) { + this.colors = colors != null ? _int32ListFromColors(colors) : null, + this.indices = indices != null ? Uint16List.fromList(indices) : null, + this.positions = offsetListToFloat32List(positions) { initWebGl(); } SurfaceVertices.raw( - ui.VertexMode mode, - Float32List positions, { - Int32List? colors, - Uint16List? indices, + this.mode, + this.positions, { + this.colors, + this.indices, }) : assert(mode != null), // ignore: unnecessary_null_comparison - assert(positions != null), // ignore: unnecessary_null_comparison - _mode = mode, - _positions = positions, - _colors = colors, - _indices = indices { + assert(positions != null) { // ignore: unnecessary_null_comparison initWebGl(); } @@ -54,15 +64,15 @@ class SurfaceVertices implements ui.Vertices { /// Used to treeshake WebGlRenderer when user doesn't create Vertices object /// to use the API. void initWebGl() { - _glRenderer ??= _WebGlRenderer(); + glRenderer ??= _WebGlRenderer(); } void disposeWebGl() { GlContextCache.dispose(); - _glRenderer = null; + glRenderer = null; } -abstract class _GlRenderer { +abstract class GlRenderer { void drawVertices( html.CanvasRenderingContext2D? context, int canvasWidthInPixels, @@ -75,8 +85,13 @@ abstract class _GlRenderer { Object? drawRect(ui.Rect targetRect, GlContext gl, GlProgram glProgram, NormalizedGradient gradient, int widthInPixels, int heightInPixels); - String drawRectToImageUrl(ui.Rect targetRect, GlContext gl, GlProgram glProgram, - NormalizedGradient gradient, int widthInPixels, int heightInPixels); + String drawRectToImageUrl( + ui.Rect targetRect, + GlContext gl, + GlProgram glProgram, + NormalizedGradient gradient, + int widthInPixels, + int heightInPixels); void drawHairline(html.CanvasRenderingContext2D? _ctx, Float32List positions); } @@ -85,16 +100,20 @@ abstract class _GlRenderer { /// /// This class gets instantiated on demand by Vertices constructor. For apps /// that don't use Vertices WebGlRenderer will be removed from release binary. -class _WebGlRenderer implements _GlRenderer { - +class _WebGlRenderer implements GlRenderer { /// Cached vertex shader reused by [drawVertices] and gradients. static String? _textureVertexShader; - static void _setupVertexTransforms(GlContext gl, GlProgram glProgram, - double offsetX, double offsetY, double widthInPixels, - double heightInPixels, Matrix4 transform) { - Object transformUniform = gl.getUniformLocation(glProgram.program, - 'u_ctransform'); + static void _setupVertexTransforms( + GlContext gl, + GlProgram glProgram, + double offsetX, + double offsetY, + double widthInPixels, + double heightInPixels, + Matrix4 transform) { + Object transformUniform = + gl.getUniformLocation(glProgram.program, 'u_ctransform'); Matrix4 transformAtOffset = transform.clone() ..translate(-offsetX, -offsetY); gl.setUniformMatrix4fv(transformUniform, false, transformAtOffset.storage); @@ -108,14 +127,14 @@ class _WebGlRenderer implements _GlRenderer { gl.setUniform4f(shift, -1, 1, 0, 0); } - static void _setupTextureScalar(GlContext gl, GlProgram glProgram, - double sx, double sy) { + static void _setupTextureScalar( + GlContext gl, GlProgram glProgram, double sx, double sy) { Object scalar = gl.getUniformLocation(glProgram.program, 'u_texscale'); gl.setUniform2f(scalar, sx, sy); } static dynamic _tileModeToGlWrapping(GlContext gl, ui.TileMode tileMode) { - switch(tileMode) { + switch (tileMode) { case ui.TileMode.clamp: return gl.kClampToEdge; case ui.TileMode.decal: @@ -136,9 +155,8 @@ class _WebGlRenderer implements _GlRenderer { 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; @@ -170,17 +188,19 @@ class _WebGlRenderer implements _GlRenderer { final bool isWebGl2 = webGLVersion == WebGLVersion.webgl2; - final EngineImageShader? imageShader = paint.shader == null ? null - : paint.shader as EngineImageShader; + final EngineImageShader? imageShader = + paint.shader == null ? null : paint.shader as EngineImageShader; final String vertexShader = imageShader == null - ? VertexShaders.writeBaseVertexShader() : writeTextureVertexShader(); + ? VertexShaders.writeBaseVertexShader() + : writeTextureVertexShader(); final String fragmentShader = imageShader == null ? _writeVerticesFragmentShader() - : _writeVerticesTextureFragmentShader(isWebGl2, - imageShader.tileModeX, imageShader.tileModeY); + : _writeVerticesTextureFragmentShader( + isWebGl2, imageShader.tileModeX, imageShader.tileModeY); - GlContext gl = GlContextCache.createGlContext(widthInPixels, heightInPixels)!; + GlContext gl = + GlContextCache.createGlContext(widthInPixels, heightInPixels)!; GlProgram glProgram = gl.cacheProgram(vertexShader, fragmentShader); gl.useProgram(glProgram); @@ -189,14 +209,16 @@ class _WebGlRenderer implements _GlRenderer { gl.getAttributeLocation(glProgram.program, 'position'); _setupVertexTransforms(gl, glProgram, offsetX, offsetY, - widthInPixels.toDouble(), heightInPixels.toDouble(), - transform); + widthInPixels.toDouble(), heightInPixels.toDouble(), transform); if (imageShader != null) { /// To map from vertex position to texture coordinate in 0..1 range, /// we setup scalar to be used in vertex shader. - _setupTextureScalar(gl, glProgram, 1.0 / imageShader._image.width.toDouble(), - 1.0 / imageShader._image.height.toDouble()); + _setupTextureScalar( + gl, + glProgram, + 1.0 / imageShader.image.width.toDouble(), + 1.0 / imageShader.image.height.toDouble()); } // Setup geometry. @@ -220,9 +242,13 @@ class _WebGlRenderer implements _GlRenderer { gl.bindArrayBuffer(positionsBuffer); gl.bufferData(positions, gl.kStaticDraw); // Setup data format for attribute. - js_util.callMethod( - gl.glContext, 'vertexAttribPointer', [ - positionAttributeLocation, 2, gl.kFloat, false, 0, 0, + js_util.callMethod(gl.glContext, 'vertexAttribPointer', [ + positionAttributeLocation, + 2, + gl.kFloat, + false, + 0, + 0, ]); final int vertexCount = positions.length ~/ 2; @@ -234,7 +260,7 @@ class _WebGlRenderer implements _GlRenderer { gl.bindArrayBuffer(colorsBuffer); // Buffer kBGRA_8888. - if (vertices._colors == null) { + if (vertices.colors == null) { final ui.Color color = paint.color ?? ui.Color(0xFF000000); Uint32List vertexColors = Uint32List(vertexCount); for (int i = 0; i < vertexCount; i++) { @@ -242,7 +268,7 @@ class _WebGlRenderer implements _GlRenderer { } gl.bufferData(vertexColors, gl.kStaticDraw); } else { - gl.bufferData(vertices._colors, gl.kStaticDraw); + gl.bufferData(vertices.colors, gl.kStaticDraw); } Object colorLoc = gl.getAttributeLocation(glProgram.program, 'color'); js_util.callMethod(gl.glContext, 'vertexAttribPointer', @@ -260,14 +286,8 @@ class _WebGlRenderer implements _GlRenderer { gl.activeTexture(gl.kTexture0); gl.bindTexture(gl.kTexture2D, texture); - gl.texImage2D( - gl.kTexture2D, - 0, - gl.kRGBA, - gl.kRGBA, - gl.kUnsignedByte, - imageShader._image.imgElement - ); + gl.texImage2D(gl.kTexture2D, 0, gl.kRGBA, gl.kRGBA, gl.kUnsignedByte, + imageShader.image.imgElement); if (isWebGl2) { // Texture REPEAT and MIRROR is only supported in WebGL 2, for @@ -287,10 +307,8 @@ class _WebGlRenderer implements _GlRenderer { // value of a texel fetch is (0, 0, 0, 1), so we have to set // minifying function to filter. // See https://www.khronos.org/registry/webgl/specs/1.0.0/#5.13.8. - gl.texParameteri(gl.kTexture2D, gl.kTextureWrapS, - gl.kClampToEdge); - gl.texParameteri(gl.kTexture2D, gl.kTextureWrapT, - gl.kClampToEdge); + gl.texParameteri(gl.kTexture2D, gl.kTextureWrapS, gl.kClampToEdge); + gl.texParameteri(gl.kTexture2D, gl.kTextureWrapT, gl.kClampToEdge); gl.texParameteri(gl.kTexture2D, gl.kTextureMinFilter, gl.kLinear); } } @@ -298,9 +316,9 @@ class _WebGlRenderer implements _GlRenderer { // Finally render triangles. gl.clear(); - final Uint16List ?indices = vertices._indices; + final Uint16List? indices = vertices.indices; if (indices == null) { - gl.drawTriangles(vertexCount, vertices._mode); + gl.drawTriangles(vertexCount, vertices.mode); } else { /// If indices are specified to use shared vertices to reduce vertex /// data transfer, use drawElements to map from vertex indices to @@ -321,11 +339,8 @@ class _WebGlRenderer implements _GlRenderer { context.restore(); } - static final Uint16List _vertexIndicesForRect = Uint16List.fromList( - [ - 0, 1, 2, 2, 3, 0 - ] - ); + static final Uint16List _vertexIndicesForRect = + Uint16List.fromList([0, 1, 2, 2, 3, 0]); /// Renders a rectangle using given program into an image resource. /// @@ -333,7 +348,8 @@ class _WebGlRenderer implements _GlRenderer { /// will return ImageBitmap, otherwise will return CanvasElement. Object? drawRect(ui.Rect targetRect, GlContext gl, GlProgram glProgram, NormalizedGradient gradient, int widthInPixels, int heightInPixels) { - drawRectToGl(targetRect, gl, glProgram, gradient, widthInPixels, heightInPixels); + drawRectToGl( + targetRect, gl, glProgram, gradient, widthInPixels, heightInPixels); Object? image = gl.readPatternData(); gl.bindArrayBuffer(null); gl.bindElementArrayBuffer(null); @@ -342,9 +358,15 @@ class _WebGlRenderer implements _GlRenderer { /// Renders a rectangle using given program into an image resource and returns /// url. - String drawRectToImageUrl(ui.Rect targetRect, GlContext gl, GlProgram glProgram, - NormalizedGradient gradient, int widthInPixels, int heightInPixels) { - drawRectToGl(targetRect, gl, glProgram, gradient, widthInPixels, heightInPixels); + String drawRectToImageUrl( + ui.Rect targetRect, + GlContext gl, + GlProgram glProgram, + NormalizedGradient gradient, + int widthInPixels, + int heightInPixels) { + drawRectToGl( + targetRect, gl, glProgram, gradient, widthInPixels, heightInPixels); final String imageUrl = gl.toImageUrl(); // Cleanup buffers. gl.bindArrayBuffer(null); @@ -373,8 +395,8 @@ class _WebGlRenderer implements _GlRenderer { vertices[6] = left; vertices[7] = bottom; - Object transformUniform = gl.getUniformLocation( - glProgram.program, 'u_ctransform'); + Object transformUniform = + gl.getUniformLocation(glProgram.program, 'u_ctransform'); gl.setUniformMatrix4fv(transformUniform, false, Matrix4.identity().storage); // Set uniform to scale 0..width/height pixels coordinates to -1..1 @@ -391,8 +413,7 @@ class _WebGlRenderer implements _GlRenderer { gl.bindArrayBuffer(positionsBuffer); gl.bufferData(vertices, gl.kStaticDraw); // Point an attribute to the currently bound vertex buffer object. - js_util.callMethod( - gl.glContext, 'vertexAttribPointer', + js_util.callMethod(gl.glContext, 'vertexAttribPointer', [0, 2, gl.kFloat, false, 0, 0]); gl.enableVertexAttribArray(0); @@ -401,7 +422,10 @@ class _WebGlRenderer implements _GlRenderer { gl.bindArrayBuffer(colorsBuffer); // Buffer kBGRA_8888. final Int32List colors = Int32List.fromList([ - 0xFF00FF00, 0xFF0000FF, 0xFFFFFF00, 0xFF00FFFF, + 0xFF00FF00, + 0xFF0000FF, + 0xFFFFFF00, + 0xFF00FFFF, ]); gl.bufferData(colors, gl.kStaticDraw); js_util.callMethod(gl.glContext, 'vertexAttribPointer', @@ -421,10 +445,11 @@ class _WebGlRenderer implements _GlRenderer { gl.clear(); gl.viewport(0, 0, widthInPixels.toDouble(), heightInPixels.toDouble()); - gl.drawElements(gl.kTriangles, _vertexIndicesForRect.length, gl.kUnsignedShort); + gl.drawElements( + gl.kTriangles, _vertexIndicesForRect.length, gl.kUnsignedShort); } - static String writeTextureVertexShader() { + static String writeTextureVertexShader() { if (_textureVertexShader == null) { ShaderBuilder builder = ShaderBuilder(webGLVersion); builder.addIn(ShaderType.kVec4, name: 'position'); @@ -436,8 +461,7 @@ class _WebGlRenderer implements _GlRenderer { ShaderMethod method = builder.addMethod('main'); method.addStatement( 'gl_Position = ((u_ctransform * position) * u_scale) + u_shift;'); - method.addStatement( - 'v_texcoord = vec2(position.x * u_texscale.x, ' + method.addStatement('v_texcoord = vec2(position.x * u_texscale.x, ' '(position.y * u_texscale.y));'); _textureVertexShader = builder.build(); } @@ -456,22 +480,23 @@ class _WebGlRenderer implements _GlRenderer { String _writeVerticesFragmentShader() { ShaderBuilder builder = ShaderBuilder.fragment(webGLVersion); builder.floatPrecision = ShaderPrecision.kMedium; - builder.addIn(ShaderType.kVec4, name:'v_color'); + builder.addIn(ShaderType.kVec4, name: 'v_color'); ShaderMethod method = builder.addMethod('main'); method.addStatement('${builder.fragmentColor.name} = v_color;'); return builder.build(); } - String _writeVerticesTextureFragmentShader(bool isWebGl2, - ui.TileMode? tileModeX, ui.TileMode? tileModeY) { + String _writeVerticesTextureFragmentShader( + bool isWebGl2, ui.TileMode? tileModeX, ui.TileMode? tileModeY) { ShaderBuilder builder = ShaderBuilder.fragment(webGLVersion); builder.floatPrecision = ShaderPrecision.kMedium; - builder.addIn(ShaderType.kVec2, name:'v_texcoord'); + builder.addIn(ShaderType.kVec2, name: 'v_texcoord'); builder.addUniform(ShaderType.kSampler2D, name: 'u_texture'); ShaderMethod method = builder.addMethod('main'); - if (isWebGl2 - || tileModeX == null || tileModeY == null - || (tileModeX == ui.TileMode.clamp && tileModeY == ui.TileMode.clamp)) { + if (isWebGl2 || + tileModeX == null || + tileModeY == null || + (tileModeX == ui.TileMode.clamp && tileModeY == ui.TileMode.clamp)) { method.addStatement('${builder.fragmentColor.name} = ' '${builder.texture2DFunction}(u_texture, v_texcoord);'); } else { @@ -490,7 +515,8 @@ class _WebGlRenderer implements _GlRenderer { } @override - void drawHairline(html.CanvasRenderingContext2D? _ctx, Float32List positions) { + void drawHairline( + html.CanvasRenderingContext2D? _ctx, Float32List positions) { assert(positions != null); // ignore: unnecessary_null_comparison final int pointCount = positions.length ~/ 2; _ctx!.lineWidth = 1.0; @@ -564,7 +590,7 @@ ui.Rect _transformBounds( } // Converts from [VertexMode] triangleFan and triangleStrip to triangles. -Float32List _convertVertexPositions(ui.VertexMode mode, Float32List positions) { +Float32List convertVertexPositions(ui.VertexMode mode, Float32List positions) { assert(mode != ui.VertexMode.triangles); if (mode == ui.VertexMode.triangleFan) { final int coordinateCount = positions.length ~/ 2; diff --git a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart new file mode 100644 index 0000000000000..bc26ac0682bfe --- /dev/null +++ b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import '../../html_image_codec.dart'; + +class EngineImageShader implements ui.ImageShader { + EngineImageShader(ui.Image image, this.tileModeX, this.tileModeY, + this.matrix4, this.filterQuality) + : this.image = image as HtmlImage; + + final ui.TileMode tileModeX; + final ui.TileMode tileModeY; + final Float64List matrix4; + final ui.FilterQuality? filterQuality; + final HtmlImage image; +} diff --git a/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart b/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart index 2b1239783d445..98cd55396b022 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart @@ -4,10 +4,11 @@ import 'dart:typed_data'; -import 'package:ui/src/engine.dart'; - import 'package:ui/ui.dart' as ui; +import 'shader_builder.dart'; +import 'webgl_context.dart'; + /// Converts colors and stops to typed array of bias, scale and threshold to use /// in shaders. /// @@ -21,8 +22,8 @@ import 'package:ui/ui.dart' as ui; /// scale = (c2 - c1) / (t2 - t1) /// bias = c1 - t1 / (t2 - t1) * (c2 - c1) class NormalizedGradient { - NormalizedGradient._(this.thresholdCount, this._thresholds, this._scale, - this._bias); + NormalizedGradient._( + this.thresholdCount, this._thresholds, this._scale, this._bias); final Float32List _thresholds; final Float32List _bias; @@ -46,7 +47,8 @@ class NormalizedGradient { } final Float32List bias = Float32List(normalizedCount * 4); final Float32List scale = Float32List(normalizedCount * 4); - final Float32List thresholds = Float32List(4 * ((normalizedCount - 1)~/4 + 1)); + final Float32List thresholds = + Float32List(4 * ((normalizedCount - 1) ~/ 4 + 1)); int targetIndex = 0; int thresholdIndex = 0; if (addFirst) { @@ -102,13 +104,17 @@ class NormalizedGradient { void setupUniforms(GlContext gl, GlProgram glProgram) { for (int i = 0; i < thresholdCount; i++) { Object biasId = gl.getUniformLocation(glProgram.program, 'bias_$i'); - gl.setUniform4f(biasId, _bias[i * 4], _bias[i * 4 + 1], _bias[i * 4 + 2], _bias[i * 4 + 3]); + gl.setUniform4f(biasId, _bias[i * 4], _bias[i * 4 + 1], _bias[i * 4 + 2], + _bias[i * 4 + 3]); Object scaleId = gl.getUniformLocation(glProgram.program, 'scale_$i'); - gl.setUniform4f(scaleId, _scale[i * 4], _scale[i * 4 + 1], _scale[i * 4 + 2], _scale[i * 4 + 3]); + gl.setUniform4f(scaleId, _scale[i * 4], _scale[i * 4 + 1], + _scale[i * 4 + 2], _scale[i * 4 + 3]); } for (int i = 0; i < _thresholds.length; i += 4) { - Object thresId = gl.getUniformLocation(glProgram.program, 'threshold_${i ~/ 4}'); - gl.setUniform4f(thresId, _thresholds[i], _thresholds[i + 1], _thresholds[i + 2], _thresholds[i + 3]); + Object thresId = + gl.getUniformLocation(glProgram.program, 'threshold_${i ~/ 4}'); + gl.setUniform4f(thresId, _thresholds[i], _thresholds[i + 1], + _thresholds[i + 2], _thresholds[i + 3]); } } @@ -131,8 +137,9 @@ class NormalizedGradient { /// Bias and scale data are vec4 uniforms that hold color data. void writeUnrolledBinarySearch(ShaderMethod method, int start, int end, {required String probe, - required String sourcePrefix, required String biasName, - required String scaleName}) { + required String sourcePrefix, + required String biasName, + required String scaleName}) { if (start == end) { String biasSource = '${biasName}_${start}'; method.addStatement('${biasName} = ${biasSource};'); @@ -141,25 +148,29 @@ void writeUnrolledBinarySearch(ShaderMethod method, int start, int end, } else { // Add probe check. int mid = (start + end) ~/ 2; - String thresholdAtMid = '${sourcePrefix}_${(mid + 1)~/4}'; - thresholdAtMid += '.${_vectorComponentIndexToName((mid + 1) % 4)}'; + String thresholdAtMid = '${sourcePrefix}_${(mid + 1) ~/ 4}'; + thresholdAtMid += '.${vectorComponentIndexToName((mid + 1) % 4)}'; method.addStatement('if ($probe < $thresholdAtMid) {'); method.indent(); writeUnrolledBinarySearch(method, start, mid, - probe: probe, sourcePrefix: sourcePrefix, biasName: biasName, + probe: probe, + sourcePrefix: sourcePrefix, + biasName: biasName, scaleName: scaleName); method.unindent(); method.addStatement('} else {'); method.indent(); writeUnrolledBinarySearch(method, mid + 1, end, - probe: probe, sourcePrefix: sourcePrefix, biasName: biasName, + probe: probe, + sourcePrefix: sourcePrefix, + biasName: biasName, scaleName: scaleName); method.unindent(); method.addStatement('}'); } } -String _vectorComponentIndexToName(int index) { - assert(index >=0 && index <= 4); +String vectorComponentIndexToName(int index) { + assert(index >= 0 && index <= 4); return 'xyzw'[index]; } diff --git a/lib/web_ui/lib/src/engine/html/shaders/shader.dart b/lib/web_ui/lib/src/engine/html/shaders/shader.dart index de20261611474..dcadd6587d751 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/shader.dart @@ -2,7 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -part of engine; +import 'dart:html' as html; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import 'normalized_gradient.dart'; +import 'shader_builder.dart'; +import 'vertex_shaders.dart'; +import 'webgl_context.dart'; +import '../offscreen_canvas.dart'; +import '../path/path_utils.dart'; +import '../render_vertices.dart'; +import '../../browser_detection.dart'; +import '../../validators.dart'; +import '../../vector_math.dart'; +import '../../util.dart'; + +const double kFltEpsilon = 1.19209290E-07; // == 1 / (2 ^ 23) +const double kFltEpsilonSquared = 1.19209290E-07 * 1.19209290E-07; abstract class EngineGradient implements ui.Gradient { /// Hidden constructor to prevent subclassing. @@ -48,8 +67,7 @@ class GradientSweep extends EngineGradient { NormalizedGradient normalizedGradient = NormalizedGradient(colors, stops: colorStops); - GlProgram glProgram = gl.cacheProgram( - VertexShaders.writeBaseVertexShader(), + GlProgram glProgram = gl.cacheProgram(VertexShaders.writeBaseVertexShader(), _createSweepFragmentShader(normalizedGradient, tileMode)); gl.useProgram(glProgram); @@ -68,7 +86,7 @@ class GradientSweep extends EngineGradient { gl.setUniformMatrix4fv(gradientMatrix, false, matrix4!); } if (createDataUrl) { - return _glRenderer!.drawRectToImageUrl( + return glRenderer!.drawRectToImageUrl( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height), gl, glProgram, @@ -76,7 +94,7 @@ class GradientSweep extends EngineGradient { widthInPixels, heightInPixels); } else { - return _glRenderer!.drawRect( + return glRenderer!.drawRect( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height), gl, glProgram, @@ -132,18 +150,6 @@ class GradientSweep extends EngineGradient { final Float32List? matrix4; } -class EngineImageShader implements ui.ImageShader { - EngineImageShader(ui.Image image, this.tileModeX, this.tileModeY, this.matrix4, this.filterQuality) - : _image = image as HtmlImage; - - final ui.TileMode tileModeX; - final ui.TileMode tileModeY; - final Float64List matrix4; - final ui.FilterQuality? filterQuality; - final HtmlImage _image; -} - - class GradientLinear extends EngineGradient { GradientLinear( this.from, @@ -227,8 +233,7 @@ class GradientLinear extends EngineGradient { NormalizedGradient normalizedGradient = NormalizedGradient(colors, stops: colorStops); - GlProgram glProgram = gl.cacheProgram( - VertexShaders.writeBaseVertexShader(), + GlProgram glProgram = gl.cacheProgram(VertexShaders.writeBaseVertexShader(), _createLinearFragmentShader(normalizedGradient, tileMode)); gl.useProgram(glProgram); @@ -313,7 +318,7 @@ class GradientLinear extends EngineGradient { gl.setUniform2f(uRes, widthInPixels.toDouble(), heightInPixels.toDouble()); if (createDataUrl) { - return _glRenderer!.drawRectToImageUrl( + return glRenderer!.drawRectToImageUrl( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height) /* !! shaderBounds */, gl, @@ -323,7 +328,7 @@ class GradientLinear extends EngineGradient { heightInPixels, ); } else { - return _glRenderer!.drawRect( + return glRenderer!.drawRect( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height) /* !! shaderBounds */, gl, @@ -517,7 +522,7 @@ class GradientRadial extends EngineGradient { matrix4 == null ? Matrix4.identity().storage : matrix4!); if (createDataUrl) { - return _glRenderer!.drawRectToImageUrl( + return glRenderer!.drawRectToImageUrl( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height), gl, glProgram, @@ -525,7 +530,7 @@ class GradientRadial extends EngineGradient { widthInPixels, heightInPixels); } else { - return _glRenderer!.drawRect( + return glRenderer!.drawRect( ui.Rect.fromLTWH(0, 0, shaderBounds.width, shaderBounds.height), gl, glProgram,