Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
38f3dad
Roll Skia from e6eb56d9b074 to fde9fe141863 (1 revision) (#45260)
skia-flutter-autoroll Aug 30, 2023
69f04bd
[Impeller] transform text path offsets so color sources match expecte…
Aug 30, 2023
dad87d3
Roll Dart SDK from 0cea73a8d3c3 to 96d3a79547fc (1 revision) (#45262)
skia-flutter-autoroll Aug 30, 2023
f11ee48
Roll Fuchsia Mac SDK from QKekosWnIY_ObKstn... to Y2xfuZM0ec5GQfHV8..…
skia-flutter-autoroll Aug 30, 2023
3aee4c5
Roll Skia from fde9fe141863 to 03289b20b5d3 (1 revision) (#45268)
skia-flutter-autoroll Aug 30, 2023
249cd28
Roll Dart SDK from 96d3a79547fc to 4352efd8497d (1 revision) (#45267)
skia-flutter-autoroll Aug 30, 2023
f476a1e
Roll Skia from 03289b20b5d3 to 80f4d2f303d0 (1 revision) (#45270)
skia-flutter-autoroll Aug 30, 2023
5f36a83
Roll Skia from 80f4d2f303d0 to 7492e29ad235 (1 revision) (#45272)
skia-flutter-autoroll Aug 30, 2023
159fda6
Roll Skia from 7492e29ad235 to a2728a7ad2a3 (1 revision) (#45273)
skia-flutter-autoroll Aug 30, 2023
b5ae430
Roll Skia from a2728a7ad2a3 to 6f4fd97d2f7e (2 revisions) (#45278)
skia-flutter-autoroll Aug 30, 2023
684046b
Roll Skia from 6f4fd97d2f7e to a58ccf8ae398 (1 revision) (#45280)
skia-flutter-autoroll Aug 30, 2023
e3883ea
Roll Skia from a58ccf8ae398 to 3489b6d1d613 (2 revisions) (#45283)
skia-flutter-autoroll Aug 30, 2023
8762f0c
Roll Skia from 3489b6d1d613 to 7a246c9eb086 (4 revisions) (#45286)
skia-flutter-autoroll Aug 30, 2023
62cf36e
Revert "Roll Dart SDK from 0cea73a8d3c3 to 96d3a79547fc" (#45285)
gaaclarke Aug 30, 2023
7ffca75
Roll Skia from 7a246c9eb086 to 185fbe1a264d (3 revisions) (#45289)
skia-flutter-autoroll Aug 30, 2023
31d5662
Roll Fuchsia Mac SDK from Y2xfuZM0ec5GQfHV8... to gWpPuUyuR_hmz9Xmg..…
skia-flutter-autoroll Aug 30, 2023
b63eee2
[Impeller] Reorganize the glyph atlas to improve efficiency when look…
jason-simmons Aug 30, 2023
aeab1b0
Add an API in `ui_web` to create a `ui.Image` from an `ImageBitmap` (…
eyebrowsoffire Aug 30, 2023
6263387
Increase maximum length of function names from 30 to 60. (#45296)
matanlurey Aug 30, 2023
d37cef8
[web] Roll to most recent fallback font data (#45301)
eyebrowsoffire Aug 30, 2023
3878734
[fuchsia] Restructure Flatland vsync loop
uysalere Sep 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add an API in ui_web to create a ui.Image from an ImageBitmap (#…
…45256)

This API will help with situations in which the user has a browser
resource that they want to transform into a `ui.Image` and render
directly into the layer tree. Most browser resources can be converted to
an `ImageBitmap` via the `createImageBitmap` API.
  • Loading branch information
eyebrowsoffire authored Aug 30, 2023
commit aeab1b0c170567dc456b431b8381d83727ee51b2
23 changes: 20 additions & 3 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,31 @@ extension CanvasKitExtension on CanvasKit {
) => _MakeImage(info, pixels.toJS, bytesPerRow.toJS);

@JS('MakeLazyImageFromTextureSource')
external SkImage? _MakeLazyImageFromTextureSource(
external SkImage? _MakeLazyImageFromTextureSource2(
JSAny src,
SkPartialImageInfo info,
);
SkImage? MakeLazyImageFromTextureSource(

@JS('MakeLazyImageFromTextureSource')
external SkImage? _MakeLazyImageFromTextureSource3(
JSAny src,
JSNumber zeroSecondArgument,
JSBoolean srcIsPremultiplied,
);

SkImage? MakeLazyImageFromTextureSourceWithInfo(
Object src,
SkPartialImageInfo info,
) => _MakeLazyImageFromTextureSource(src.toJSAnyShallow, info);
) => _MakeLazyImageFromTextureSource2(src.toJSAnyShallow, info);

SkImage? MakeLazyImageFromImageBitmap(
DomImageBitmap imageBitmap,
bool hasPremultipliedAlpha,
) => _MakeLazyImageFromTextureSource3(
imageBitmap as JSAny,
0.toJS,
hasPremultipliedAlpha.toJS,
);
}

@JS('window.CanvasKitInit')
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class CkBrowserImageDecoder extends BrowserImageDecoder {

@override
ui.Image generateImageFromVideoFrame(VideoFrame frame) {
final SkImage? skImage = canvasKit.MakeLazyImageFromTextureSource(
final SkImage? skImage = canvasKit.MakeLazyImageFromTextureSourceWithInfo(
frame,
SkPartialImageInfo(
alphaType: canvasKit.AlphaType.Premul,
Expand Down
12 changes: 12 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,18 @@ class CanvasKitRenderer implements Renderer {
ui_web.ImageCodecChunkCallback? chunkCallback
}) => skiaInstantiateWebImageCodec(uri.toString(), chunkCallback);

@override
ui.Image createImageFromImageBitmap(DomImageBitmap imageBitmap) {
final SkImage? skImage = canvasKit.MakeLazyImageFromImageBitmap(
imageBitmap,
true
);
if (skImage == null) {
throw Exception('Failed to convert image bitmap to an SkImage.');
}
return CkImage(skImage);
}

@override
void decodeImageFromPixels(
Uint8List pixels,
Expand Down
41 changes: 39 additions & 2 deletions lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,33 @@ extension DomImageBitmapExtension on DomImageBitmap {
external void close();
}


@JS('createImageBitmap')
external JSPromise _createImageBitmap1(
JSAny source,
);
@JS('createImageBitmap')
external JSPromise _createImageBitmap2(
JSAny source,
JSNumber x,
JSNumber y,
JSNumber width,
JSNumber height,
);
JSPromise createImageBitmap(JSAny source, [({int x, int y, int width, int height})? bounds]) {
if (bounds != null) {
return _createImageBitmap2(
source,
bounds.x.toJS,
bounds.y.toJS,
bounds.width.toJS,
bounds.height.toJS
);
} else {
return _createImageBitmap1(source);
}
}

@JS()
@staticInterop
class DomCanvasPattern {}
Expand Down Expand Up @@ -2264,14 +2291,24 @@ extension DomURLExtension on DomURL {
@staticInterop
class DomBlob {
external factory DomBlob(JSArray parts);

external factory DomBlob.withOptions(JSArray parts, JSAny options);
}

extension DomBlobExtension on DomBlob {
external JSPromise arrayBuffer();
}

DomBlob createDomBlob(List<Object?> parts) =>
DomBlob(parts.toJSAnyShallow as JSArray);
DomBlob createDomBlob(List<Object?> parts, [Map<String, dynamic>? options]) {
if (options == null) {
return DomBlob(parts.toJSAnyShallow as JSArray);
} else {
return DomBlob.withOptions(
parts.toJSAnyShallow as JSArray,
options.toJSAnyDeep
);
}
}

typedef DomMutationCallback = void Function(
JSArray mutation, DomMutationObserver observer);
Expand Down
28 changes: 28 additions & 0 deletions lib/web_ui/lib/src/engine/html/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:js_interop';
import 'dart:math' as math;
import 'dart:typed_data';

Expand Down Expand Up @@ -361,4 +362,31 @@ class HtmlRenderer implements Renderer {
baseline: baseline,
lineNumber: lineNumber
);

@override
Future<ui.Image> createImageFromImageBitmap(DomImageBitmap imageSource) async {
final int width = imageSource.width.toDartInt;
final int height = imageSource.height.toDartInt;
final OffScreenCanvas canvas = OffScreenCanvas(width, height);
final DomCanvasRenderingContextBitmapRenderer context = canvas.getBitmapRendererContext()!;
context.transferFromImageBitmap(imageSource);
final DomHTMLImageElement imageElement = createDomHTMLImageElement();
late final DomEventListener loadListener;
late final DomEventListener errorListener;
final Completer<HtmlImage> completer = Completer<HtmlImage>();
loadListener = createDomEventListener((DomEvent event) {
completer.complete(HtmlImage(imageElement, width, height));
imageElement.removeEventListener('load', loadListener);
imageElement.removeEventListener('error', errorListener);
});
errorListener = createDomEventListener((DomEvent event) {
completer.completeError(Exception('Failed to create image from image bitmap.'));
imageElement.removeEventListener('load', loadListener);
imageElement.removeEventListener('error', errorListener);
});
imageElement.addEventListener('load', loadListener);
imageElement.addEventListener('error', errorListener);
imageElement.src = await canvas.toDataUrl();
return completer.future;
}
}
10 changes: 3 additions & 7 deletions lib/web_ui/lib/src/engine/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,11 @@ import 'dart:async';
import 'dart:math' as math;
import 'dart:typed_data';

import 'package:ui/src/engine.dart';
import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart';
import 'package:ui/ui.dart' as ui;
import 'package:ui/ui_web/src/ui_web.dart' as ui_web;

import 'browser_detection.dart';
import 'canvaskit/renderer.dart';
import 'configuration.dart';
import 'embedder.dart';
import 'fonts.dart';
import 'html/renderer.dart';

final Renderer _renderer = Renderer._internal();
Renderer get renderer => _renderer;

Expand Down Expand Up @@ -134,6 +128,8 @@ abstract class Renderer {
ui_web.ImageCodecChunkCallback? chunkCallback,
});

FutureOr<ui.Image> createImageFromImageBitmap(DomImageBitmap imageSource);

void decodeImageFromPixels(
Uint8List pixels,
int width,
Expand Down
6 changes: 6 additions & 0 deletions lib/web_ui/lib/src/engine/safe_browser_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,12 @@ class OffScreenCanvas {
: canvasElement!.getContext('2d');
}

DomCanvasRenderingContextBitmapRenderer? getBitmapRendererContext() {
return (offScreenCanvas != null
? offScreenCanvas!.getContext('bitmaprenderer')
: canvasElement!.getContext('bitmaprenderer')) as DomCanvasRenderingContextBitmapRenderer?;
}

/// Feature detection for transferToImageBitmap on OffscreenCanvas.
bool get transferToImageBitmapSupported =>
js_util.hasProperty(offScreenCanvas!, 'transferToImageBitmap');
Expand Down
6 changes: 4 additions & 2 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/codecs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:js_interop';

import 'package:ui/src/engine.dart';
import 'package:ui/src/engine/skwasm/skwasm_impl.dart';
import 'package:ui/ui.dart' as ui;
Expand All @@ -18,8 +20,8 @@ class SkwasmImageDecoder extends BrowserImageDecoder {
final int width = frame.codedWidth.toInt();
final int height = frame.codedHeight.toInt();
final SkwasmSurface surface = (renderer as SkwasmRenderer).surface;
return SkwasmImage(imageCreateFromVideoFrame(
frame,
return SkwasmImage(imageCreateFromTextureSource(
frame as JSAny,
width,
height,
surface.handle,
Expand Down
19 changes: 9 additions & 10 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/raw/raw_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ library skwasm_impl;
import 'dart:ffi';
import 'dart:js_interop';

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

final class RawImage extends Opaque {}
Expand Down Expand Up @@ -47,9 +46,9 @@ external ImageHandle imageCreateFromPixels(
// Int,
// Int,
// SurfaceHandle,
// )>(symbol: 'image_createFromVideoFrame', isLeaf: true)
// external ImageHandle imageCreateFromVideoFrame(
// JSAny videoFrame,
// )>(symbol: 'image_createFromTextureSource', isLeaf: true)
// external ImageHandle imageCreateFromTextureSource(
// JSAny textureSource,
// int width,
// int height,
// SurfaceHandle handle,
Expand All @@ -59,21 +58,21 @@ external ImageHandle imageCreateFromPixels(
// annotations currently. For now, we can use JS interop to expose this function
// instead.
extension SkwasmImageExtension on SkwasmInstance {
@JS('wasmExports.image_createFromVideoFrame')
external JSNumber imageCreateFromVideoFrame(
VideoFrame frame,
@JS('wasmExports.image_createFromTextureSource')
external JSNumber imageCreateFromTextureSource(
JSAny textureSource,
JSNumber width,
JSNumber height,
JSNumber surfaceHandle,
);
}
ImageHandle imageCreateFromVideoFrame(
VideoFrame frame,
ImageHandle imageCreateFromTextureSource(
JSAny frame,
int width,
int height,
SurfaceHandle handle
) => ImageHandle.fromAddress(
skwasmInstance.imageCreateFromVideoFrame(
skwasmInstance.imageCreateFromTextureSource(
frame,
width.toJS,
height.toJS,
Expand Down
10 changes: 10 additions & 0 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,16 @@ class SkwasmRenderer implements Renderer {
baseline: baseline,
lineNumber: lineNumber
);

@override
ui.Image createImageFromImageBitmap(DomImageBitmap imageSource) {
return SkwasmImage(imageCreateFromTextureSource(
imageSource as JSAny,
imageSource.width.toDartInt,
imageSource.height.toDartInt,
surface.handle,
));
}
}

class SkwasmPictureRenderer implements PictureRenderer {
Expand Down
5 changes: 5 additions & 0 deletions lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -189,4 +189,9 @@ class SkwasmRenderer implements Renderer {
required double baseline,
required int lineNumber
}) => throw UnimplementedError('Skwasm not implemented on this platform.');

@override
ui.Image createImageFromImageBitmap(DomImageBitmap imageSource) {
throw UnimplementedError('Skwasm not implemented on this platform.');
}
}
19 changes: 19 additions & 0 deletions lib/web_ui/lib/ui_web/src/ui_web/images.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:js_interop';

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

Expand All @@ -25,3 +28,19 @@ Future<ui.Codec> createImageCodecFromUrl(
chunkCallback: chunkCallback,
);
}

/// Creates a [ui.Image] from an ImageBitmap object.
///
/// The contents of the ImageBitmap must have a premultiplied alpha.
/// The engine will take ownership of the ImageBitmap object and consume its
/// contents.
///
/// See https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap
FutureOr<ui.Image> createImageFromImageBitmap(JSAny imageSource) {
if (!domInstanceOfString(imageSource, 'ImageBitmap')) {
throw ArgumentError('Image source $imageSource is not an ImageBitmap.', 'imageSource');
}
return renderer.createImageFromImageBitmap(
imageSource as DomImageBitmap,
);
}
32 changes: 17 additions & 15 deletions lib/web_ui/skwasm/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,22 @@ class ExternalWebGLTexture : public GrExternalTexture {
};
} // namespace

class VideoFrameImageGenerator : public GrExternalTextureGenerator {
class TextureSourceImageGenerator : public GrExternalTextureGenerator {
public:
VideoFrameImageGenerator(SkImageInfo ii,
SkwasmObject videoFrame,
Skwasm::Surface* surface)
TextureSourceImageGenerator(SkImageInfo ii,
SkwasmObject textureSource,
Skwasm::Surface* surface)
: GrExternalTextureGenerator(ii),
_videoFrameWrapper(surface->createVideoFrameWrapper(videoFrame)) {}
_textureSourceWrapper(
surface->createTextureSourceWrapper(textureSource)) {}

std::unique_ptr<GrExternalTexture> generateExternalTexture(
GrRecordingContext* context,
GrMipMapped mipmapped) override {
GrGLTextureInfo glInfo;
glInfo.fID = skwasm_createGlTextureFromVideoFrame(
_videoFrameWrapper->getVideoFrame(), fInfo.width(), fInfo.height());
glInfo.fID = skwasm_createGlTextureFromTextureSource(
_textureSourceWrapper->getTextureSource(), fInfo.width(),
fInfo.height());
glInfo.fFormat = GL_RGBA8_OES;
glInfo.fTarget = GL_TEXTURE_2D;

Expand All @@ -103,7 +105,7 @@ class VideoFrameImageGenerator : public GrExternalTextureGenerator {
}

private:
std::unique_ptr<Skwasm::VideoFrameWrapper> _videoFrameWrapper;
std::unique_ptr<Skwasm::TextureSourceWrapper> _textureSourceWrapper;
};

SKWASM_EXPORT SkImage* image_createFromPicture(SkPicture* picture,
Expand All @@ -129,17 +131,17 @@ SKWASM_EXPORT SkImage* image_createFromPixels(SkData* data,
.release();
}

SKWASM_EXPORT SkImage* image_createFromVideoFrame(SkwasmObject videoFrame,
int width,
int height,
Skwasm::Surface* surface) {
SKWASM_EXPORT SkImage* image_createFromTextureSource(SkwasmObject textureSource,
int width,
int height,
Skwasm::Surface* surface) {
return SkImages::DeferredFromTextureGenerator(
std::unique_ptr<VideoFrameImageGenerator>(
new VideoFrameImageGenerator(
std::unique_ptr<TextureSourceImageGenerator>(
new TextureSourceImageGenerator(
SkImageInfo::Make(width, height,
SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kPremul_SkAlphaType),
videoFrame, surface)))
textureSource, surface)))
.release();
}

Expand Down
Loading