Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Initial support for images in Skwasm #42019

Merged
merged 11 commits into from
May 16, 2023
Merged
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2007,6 +2007,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.da
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_image.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart + ../../../flutter/LICENSE
Expand Down Expand Up @@ -2077,6 +2078,7 @@ ORIGIN: ../../../flutter/lib/web_ui/skwasm/data.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/export.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/fonts.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/helpers.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/image.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/paint.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/path.cpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/lib/web_ui/skwasm/picture.cpp + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4626,6 +4628,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_fonts.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_geometry.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_image.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_memory.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_paint.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_path.dart
Expand Down Expand Up @@ -4696,6 +4699,7 @@ FILE: ../../../flutter/lib/web_ui/skwasm/data.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/export.h
FILE: ../../../flutter/lib/web_ui/skwasm/fonts.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/helpers.h
FILE: ../../../flutter/lib/web_ui/skwasm/image.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/paint.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/path.cpp
FILE: ../../../flutter/lib/web_ui/skwasm/picture.cpp
Expand Down
20 changes: 18 additions & 2 deletions lib/web_ui/lib/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ class MaskFilter {
String toString() => 'MaskFilter.blur($_style, ${_sigma.toStringAsFixed(1)})';
}

// This needs to be kept in sync with the "_FilterQuality" enum in skwasm's canvas.cpp
enum FilterQuality {
none,
low,
Expand Down Expand Up @@ -438,16 +439,19 @@ enum ColorSpace {
extendedSRGB,
}

// This must be kept in sync with the `ImageByteFormat` enum in Skwasm's surface.cpp.
enum ImageByteFormat {
rawRgba,
rawStraightRgba,
rawUnmodified,
png,
}

// This must be kept in sync with the `PixelFormat` enum in Skwasm's image.cpp.
enum PixelFormat {
rgba8888,
bgra8888,
rgbaFloat32,
}

typedef ImageDecoderCallback = void Function(Image result);
Expand Down Expand Up @@ -561,6 +565,8 @@ Future<Codec> createBmp(
swapRedBlue = true;
case PixelFormat.rgba8888:
swapRedBlue = false;
case PixelFormat.rgbaFloat32:
throw UnimplementedError('RGB conversion from rgbaFloat32 data is not implemented');
}

// See https://en.wikipedia.org/wiki/BMP_file_format for format examples.
Expand Down Expand Up @@ -737,9 +743,19 @@ class Shadow {
}

abstract class ImageShader implements Shader {
factory ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4, {
factory ImageShader(
Image image,
TileMode tmx,
TileMode tmy,
Float64List matrix4, {
FilterQuality? filterQuality,
}) => engine.renderer.createImageShader(image, tmx, tmy, matrix4, filterQuality);
}) => engine.renderer.createImageShader(
image,
tmx,
tmy,
matrix4,
filterQuality
);

@override
void dispose();
Expand Down
4 changes: 1 addition & 3 deletions lib/web_ui/lib/src/engine/canvaskit/image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ void skiaDecodeImageFromPixels(
}

if (targetWidth != null || targetHeight != null) {
if (!validUpscale(allowUpscaling, targetWidth, targetHeight, width, height)) {
domWindow.console.warn('Cannot apply targetWidth/targetHeight when allowUpscaling is false.');
} else {
if (validUpscale(allowUpscaling, targetWidth, targetHeight, width, height)) {
return callback(scaleImage(skImage, targetWidth, targetHeight));
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export 'skwasm_impl/picture.dart';
export 'skwasm_impl/raw/raw_canvas.dart';
export 'skwasm_impl/raw/raw_fonts.dart';
export 'skwasm_impl/raw/raw_geometry.dart';
export 'skwasm_impl/raw/raw_image.dart';
export 'skwasm_impl/raw/raw_memory.dart';
export 'skwasm_impl/raw/raw_paint.dart';
export 'skwasm_impl/raw/raw_path.dart';
Expand Down
48 changes: 39 additions & 9 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,21 +183,51 @@ class SkwasmCanvas implements ui.Canvas {
}

@override
void drawImage(ui.Image uiImage, ui.Offset offset, ui.Paint uiPaint) {
throw UnimplementedError();
}
void drawImage(ui.Image image, ui.Offset offset, ui.Paint paint) =>
canvasDrawImage(
_handle,
(image as SkwasmImage).handle,
offset.dx,
offset.dy,
(paint as SkwasmPaint).handle,
paint.filterQuality.index,
);

@override
void drawImageRect(
ui.Image uiImage, ui.Rect src, ui.Rect dst, ui.Paint uiPaint) {
throw UnimplementedError();
}
ui.Image image,
ui.Rect src,
ui.Rect dst,
ui.Paint paint) => withStackScope((StackScope scope) {
final Pointer<Float> sourceRect = scope.convertRectToNative(src);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
canvasDrawImageRect(
_handle,
(image as SkwasmImage).handle,
sourceRect,
destRect,
(paint as SkwasmPaint).handle,
paint.filterQuality.index,
);
});

@override
void drawImageNine(
ui.Image uiImage, ui.Rect center, ui.Rect dst, ui.Paint uiPaint) {
throw UnimplementedError();
}
ui.Image image,
ui.Rect center,
ui.Rect dst,
ui.Paint paint) => withStackScope((StackScope scope) {
final Pointer<Int32> centerRect = scope.convertIRectToNative(center);
final Pointer<Float> destRect = scope.convertRectToNative(dst);
canvasDrawImageNine(
_handle,
(image as SkwasmImage).handle,
centerRect,
destRect,
(paint as SkwasmPaint).handle,
paint.filterQuality.index,
);
});

@override
void drawPicture(ui.Picture picture) {
Expand Down
50 changes: 39 additions & 11 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,67 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:ffi';
import 'dart:typed_data';

import 'package:ui/src/engine.dart';
import 'package:ui/src/engine/skwasm/skwasm_impl.dart';
import 'package:ui/ui.dart' as ui;

class SkwasmImage implements ui.Image {
@override
int get width {
throw UnimplementedError();
SkwasmImage(this.handle);

factory SkwasmImage.fromPixels(
Uint8List pixels,
int width,
int height,
ui.PixelFormat format, {
int? rowBytes,
}) {
final SkDataHandle dataHandle = skDataCreate(pixels.length);
final Pointer<Uint8> dataPointer = skDataGetPointer(dataHandle).cast<Uint8>();
for (int i = 0; i < pixels.length; i++) {
dataPointer[i] = pixels[i];
}
final ImageHandle imageHandle = imageCreateFromPixels(
dataHandle,
width,
height,
format.index,
rowBytes ?? 4 * width,
);
skDataDispose(dataHandle);
return SkwasmImage(imageHandle);
}

final ImageHandle handle;
bool _isDisposed = false;

@override
int get height {
throw UnimplementedError();
}
int get width => imageGetWidth(handle);

@override
int get height => imageGetHeight(handle);

@override
Future<ByteData?> toByteData(
{ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) {
throw UnimplementedError();
return (renderer as SkwasmRenderer).surface.rasterizeImage(this, format);
}

@override
ui.ColorSpace get colorSpace => ui.ColorSpace.sRGB;

@override
void dispose() {
throw UnimplementedError();
if (!_isDisposed) {
imageDispose(handle);
_isDisposed = true;
}
}

@override
bool get debugDisposed {
throw UnimplementedError();
}
bool get debugDisposed => _isDisposed;

@override
SkwasmImage clone() => this;
Expand Down
28 changes: 14 additions & 14 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/paint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,31 +76,31 @@ class SkwasmPaint implements ui.Paint {
@override
set strokeMiterLimit(double limit) => paintSetMiterLimit(_handle, limit);

// Unimplemented stuff below
@override
ui.ColorFilter? colorFilter;
ui.Shader? get shader => _shader;

@override
ui.FilterQuality filterQuality = ui.FilterQuality.none;
set shader(ui.Shader? uiShader) {
final SkwasmShader? skwasmShader = uiShader as SkwasmShader?;
_shader = skwasmShader;
final ShaderHandle shaderHandle =
skwasmShader != null ? skwasmShader.handle : nullptr;
paintSetShader(_handle, shaderHandle);
}

@override
ui.ImageFilter? imageFilter;
ui.FilterQuality filterQuality = ui.FilterQuality.none;

// Unimplemented stuff below
@override
bool invertColors = false;
ui.ColorFilter? colorFilter;

@override
ui.MaskFilter? maskFilter;
ui.ImageFilter? imageFilter;

@override
ui.Shader? get shader => _shader;
bool invertColors = false;

@override
set shader(ui.Shader? uiShader) {
final SkwasmShader? skwasmShader = uiShader as SkwasmShader?;
_shader = skwasmShader;
final ShaderHandle shaderHandle =
skwasmShader != null ? skwasmShader.handle : nullptr;
paintSetShader(_handle, shaderHandle);
}
ui.MaskFilter? maskFilter;
}
10 changes: 3 additions & 7 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/picture.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ class SkwasmPicture implements ui.Picture {
PictureHandle get handle => _handle;

@override
Future<ui.Image> toImage(int width, int height) {
throw UnimplementedError();
}
Future<ui.Image> toImage(int width, int height) async => toImageSync(width, height);

@override
void dispose() {
Expand All @@ -30,10 +28,8 @@ class SkwasmPicture implements ui.Picture {
bool debugDisposed = false;

@override
ui.Image toImageSync(int width, int height) {
// TODO(jacksongardner): implement toImageSync
throw UnimplementedError();
}
ui.Image toImageSync(int width, int height) =>
SkwasmImage(imageCreateFromPicture(handle, width, height));

ui.Rect get cullRect {
return withStackScope((StackScope s) {
Expand Down
55 changes: 53 additions & 2 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import 'dart:ffi';

import 'package:ui/src/engine/skwasm/skwasm_impl.dart';

final class CanvasWrapper extends Opaque {}
final class RawCanvas extends Opaque {}

typedef CanvasHandle = Pointer<CanvasWrapper>;
typedef CanvasHandle = Pointer<RawCanvas>;

@Native<Void Function(CanvasHandle)>(symbol: 'canvas_destroy', isLeaf: true)
external void canvasDestroy(CanvasHandle canvas);
Expand Down Expand Up @@ -126,6 +126,57 @@ external void canvasDrawPath(
symbol: 'canvas_drawPicture', isLeaf: true)
external void canvasDrawPicture(CanvasHandle canvas, PictureHandle picture);

@Native<Void Function(
CanvasHandle,
ImageHandle,
Float,
Float,
PaintHandle,
Int
)>(symbol: 'canvas_drawImage', isLeaf: true)
external void canvasDrawImage(
CanvasHandle handle,
ImageHandle image,
double offsetX,
double offsetY,
PaintHandle paint,
int filterQuality,
);

@Native<Void Function(
CanvasHandle,
ImageHandle,
Pointer<Float>,
Pointer<Float>,
PaintHandle,
Int,
)>(symbol: 'canvas_drawImageRect', isLeaf: true)
external void canvasDrawImageRect(
CanvasHandle handle,
ImageHandle image,
Pointer<Float> sourceRect,
Pointer<Float> destRect,
PaintHandle paint,
int filterQuality,
);

@Native<Void Function(
CanvasHandle,
ImageHandle,
Pointer<Int32>,
Pointer<Float>,
PaintHandle,
Int,
)>(symbol: 'canvas_drawImageNine', isLeaf: true)
external void canvasDrawImageNine(
CanvasHandle handle,
ImageHandle image,
Pointer<Int32> centerRect,
Pointer<Float> destRect,
PaintHandle paint,
int filterQuality,
);

@Native<Void Function(CanvasHandle, PathHandle, Float, Float, Int32, Bool)>(
symbol: 'canvas_drawShadow', isLeaf: true)
external void canvasDrawShadow(
Expand Down
Loading