part of dart._engine; // 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. class HtmlRendererImageCodec extends HtmlImageElementCodec { HtmlRendererImageCodec(super.src, {super.chunkCallback}); @override ui.Image createImageFromHTMLImageElement( DomHTMLImageElement image, int naturalWidth, int naturalHeight, ) { return HtmlImage(image, naturalWidth, naturalHeight); } } class HtmlRendererBlobCodec extends HtmlBlobCodec { HtmlRendererBlobCodec(super.blob); @override ui.Image createImageFromHTMLImageElement( DomHTMLImageElement image, int naturalWidth, int naturalHeight, ) { return HtmlImage(image, naturalWidth, naturalHeight); } } class HtmlImage implements ui.Image { HtmlImage(this.imgElement, this.width, this.height) { ui.Image.onCreate?.call(this); } final DomHTMLImageElement imgElement; bool _didClone = false; bool _disposed = false; @override void dispose() { ui.Image.onDispose?.call(this); // Do nothing. The codec that owns this image should take care of // releasing the object url. assert(() { _disposed = true; return true; }()); } @override bool get debugDisposed { bool? result; assert(() { result = _disposed; return true; }()); if (result != null) { return result!; } throw StateError('Image.debugDisposed is only available when asserts are enabled.'); } @override ui.Image clone() => this; @override bool isCloneOf(ui.Image other) => other == this; @override List? debugGetOpenHandleStackTraces() => null; @override final int width; @override final int height; @override Future toByteData({ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) { switch (format) { // TODO(ColdPaleLight): https://github.com/flutter/flutter/issues/89128 // The format rawRgba always returns straight rather than premul currently. case ui.ImageByteFormat.rawRgba: case ui.ImageByteFormat.rawStraightRgba: final DomCanvasElement canvas = createDomCanvasElement() ..width = width.toDouble() ..height = height.toDouble(); final DomCanvasRenderingContext2D ctx = canvas.context2D; ctx.drawImage(imgElement, 0, 0); final DomImageData imageData = ctx.getImageData(0, 0, width, height); // Resize the canvas to 0x0 to cause the browser to reclaim its memory // eagerly. canvas.width = 0; canvas.height = 0; return Future.value(imageData.data.buffer.asByteData()); default: if (imgElement.src?.startsWith('data:') ?? false) { final UriData data = UriData.fromUri(Uri.parse(imgElement.src!)); return Future.value(data.contentAsBytes().buffer.asByteData()); } else { return Future.value(); } } } @override ui.ColorSpace get colorSpace => ui.ColorSpace.sRGB; DomHTMLImageElement cloneImageElement() { if (!_didClone) { _didClone = true; imgElement.style.position = 'absolute'; } return imgElement.cloneNode(true) as DomHTMLImageElement; } @override String toString() => '[$width\u00D7$height]'; }