[web] Cleanup everything HTML from the framework (#162837)

Things being removed:

- Custom image filter logic in `cupertino/dialog.dart`.
- Network image support for the HTML renderer.
- Shader warm up guard for the HTML renderer.
- Custom caret metrics logic in `text_painter.dart`.
This commit is contained in:
Mouad Debbar 2025-02-13 15:53:36 -05:00 committed by GitHub
parent c2229a884b
commit 4e6e24f729
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 22 additions and 75 deletions

View File

@ -684,7 +684,7 @@ class CupertinoPopupSurface extends StatelessWidget {
isVibrancePainted = debugIsVibrancePainted; isVibrancePainted = debugIsVibrancePainted;
return true; return true;
}()); }());
if ((kIsWeb && !isSkiaWeb) || !isVibrancePainted) { if (!isVibrancePainted) {
if (blurSigma == 0) { if (blurSigma == 0) {
return null; return null;
} }

View File

@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:js_interop'; import 'dart:js_interop';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:ui_web' as ui_web;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -134,9 +133,6 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
return collector; return collector;
} }
// HTML renderer does not support decoding network images to a specified size. The decode parameter
// here is ignored and `ui_web.createImageCodecFromUrl` will be used directly
// in place of the typical `instantiateImageCodec` method.
Future<ImageStreamCompleter> _loadAsync( Future<ImageStreamCompleter> _loadAsync(
NetworkImage key, NetworkImage key,
_SimpleDecoderCallback decode, _SimpleDecoderCallback decode,
@ -176,9 +172,6 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
final bool containsNetworkImageHeaders = key.headers?.isNotEmpty ?? false; final bool containsNetworkImageHeaders = key.headers?.isNotEmpty ?? false;
// When headers are set, the image can only be loaded by decoding. // When headers are set, the image can only be loaded by decoding.
// //
// For the HTML renderer, `ui_web.createImageCodecFromUrl` method is not
// capable of handling headers.
//
// For CanvasKit and Skwasm, it is not possible to load an <img> element and // For CanvasKit and Skwasm, it is not possible to load an <img> element and
// pass the headers with the request to fetch the image. Since the user has // pass the headers with the request to fetch the image. Since the user has
// provided headers, this function should assume the headers are required to // provided headers, this function should assume the headers are required to
@ -188,32 +181,6 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkIm
return loadViaDecode(); return loadViaDecode();
} }
if (!isSkiaWeb) {
// This branch is only hit by the HTML renderer, which is deprecated. The
// HTML renderer supports loading images with CORS restrictions, so we
// don't need to catch errors and try loading the image in an <img> tag
// in this case.
// Resolve the Codec before passing it to
// [MultiFrameImageStreamCompleter] so any errors aren't reported
// twice (once from the MultiFrameImageStreamCompleter) and again
// from the wrapping [ForwardingImageStreamCompleter].
final Uri resolved = Uri.base.resolve(key.url);
final ui.Codec codec = await ui_web.createImageCodecFromUrl(
resolved,
chunkCallback: (int bytes, int total) {
chunkEvents.add(ImageChunkEvent(cumulativeBytesLoaded: bytes, expectedTotalBytes: total));
},
);
return MultiFrameImageStreamCompleter(
chunkEvents: chunkEvents.stream,
codec: Future<ui.Codec>.value(codec),
scale: key.scale,
debugLabel: key.url,
informationCollector: _imageStreamInformationCollector(key),
);
}
switch (webHtmlElementStrategy) { switch (webHtmlElementStrategy) {
case image_provider.WebHtmlElementStrategy.never: case image_provider.WebHtmlElementStrategy.never:
return loadViaDecode(); return loadViaDecode();

View File

@ -90,20 +90,17 @@ abstract class ShaderWarmUp {
await warmUpOnCanvas(canvas); await warmUpOnCanvas(canvas);
final ui.Picture picture = recorder.endRecording(); final ui.Picture picture = recorder.endRecording();
assert(debugCaptureShaderWarmUpPicture(picture)); assert(debugCaptureShaderWarmUpPicture(picture));
if (!kIsWeb || isSkiaWeb) { TimelineTask? debugShaderWarmUpTask;
// Picture.toImage is not implemented on the html renderer. if (!kReleaseMode) {
TimelineTask? debugShaderWarmUpTask; debugShaderWarmUpTask = TimelineTask()..start('Warm-up shader');
}
try {
final ui.Image image = await picture.toImage(size.width.ceil(), size.height.ceil());
assert(debugCaptureShaderWarmUpImage(image));
image.dispose();
} finally {
if (!kReleaseMode) { if (!kReleaseMode) {
debugShaderWarmUpTask = TimelineTask()..start('Warm-up shader'); debugShaderWarmUpTask!.finish();
}
try {
final ui.Image image = await picture.toImage(size.width.ceil(), size.height.ceil());
assert(debugCaptureShaderWarmUpImage(image));
image.dispose();
} finally {
if (!kReleaseMode) {
debugShaderWarmUpTask!.finish();
}
} }
} }
picture.dispose(); picture.dispose();

View File

@ -1528,9 +1528,7 @@ class TextPainter {
final _TextPainterLayoutCacheWithOffset cachedLayout = _layoutCache!; final _TextPainterLayoutCacheWithOffset cachedLayout = _layoutCache!;
// If nothing is laid out, top start is the only reasonable place to place // If nothing is laid out, top start is the only reasonable place to place
// the cursor. // the cursor.
// The HTML renderer reports numberOfLines == 1 when the text is empty: if (cachedLayout.paragraph.numberOfLines < 1) {
// https://github.com/flutter/flutter/issues/143331
if (cachedLayout.paragraph.numberOfLines < 1 || plainText.isEmpty) {
// TODO(LongCatIsLooong): assert when an invalid position is given. // TODO(LongCatIsLooong): assert when an invalid position is given.
return null; return null;
} }
@ -1588,31 +1586,16 @@ class TextPainter {
boxHeightStyle: ui.BoxHeightStyle.strut, boxHeightStyle: ui.BoxHeightStyle.strut,
); );
if (boxes.isNotEmpty) { final bool anchorToLeft = switch (glyphInfo.writingDirection) {
final bool anchorToLeft = switch (glyphInfo.writingDirection) { TextDirection.ltr => anchorToLeadingEdge,
TextDirection.ltr => anchorToLeadingEdge, TextDirection.rtl => !anchorToLeadingEdge,
TextDirection.rtl => !anchorToLeadingEdge, };
}; final TextBox box = anchorToLeft ? boxes.first : boxes.last;
final TextBox box = anchorToLeft ? boxes.first : boxes.last; metrics = _LineCaretMetrics(
metrics = _LineCaretMetrics( offset: Offset(anchorToLeft ? box.left : box.right, box.top),
offset: Offset(anchorToLeft ? box.left : box.right, box.top), writingDirection: box.direction,
writingDirection: box.direction, height: box.bottom - box.top,
height: box.bottom - box.top, );
);
} else {
// Fall back to glyphInfo. This should only happen when using the HTML renderer.
assert(kIsWeb && !isSkiaWeb);
final Rect graphemeBounds = glyphInfo.graphemeClusterLayoutBounds;
final double dx = switch (glyphInfo.writingDirection) {
TextDirection.ltr => anchorToLeadingEdge ? graphemeBounds.left : graphemeBounds.right,
TextDirection.rtl => anchorToLeadingEdge ? graphemeBounds.right : graphemeBounds.left,
};
metrics = _LineCaretMetrics(
offset: Offset(dx, graphemeBounds.top),
writingDirection: glyphInfo.writingDirection,
height: graphemeBounds.height,
);
}
cachedLayout._previousCaretPositionKey = caretPositionCacheKey; cachedLayout._previousCaretPositionKey = caretPositionCacheKey;
return _caretMetrics = metrics; return _caretMetrics = metrics;