Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: MyWidget(),
),
);
}
}

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
child: Stack(
fit: StackFit.expand,
children: [
Image.asset(
'assets/images/wallpaper2.jpg',
fit: BoxFit.cover,
),
ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.8),
BlendMode.srcOut,
),
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: const BoxDecoration(
color: Colors.black,
backgroundBlendMode: BlendMode.dstOut,
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: const EdgeInsets.only(top: 80),
height: 200,
width: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(100),
),
),
),
const Center(
child: Text(
'Hello World',
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.w600,
),
),
)
],
),
),
],
),
);
}
}
2 changes: 1 addition & 1 deletion e2etests/web/regular_integration_tests/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dev_dependencies:
sdk: flutter
flutter_test:
sdk: flutter
integration_test: ^0.9.2+2
integration_test: ^1.0.2+2
http: 0.12.0+2
web_test_utils:
path: ../../../web_sdk/web_test_utils
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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:async';
import 'dart:html' as html;
import 'dart:js' as js;
import 'dart:js_util' as js_util;
import 'package:flutter_test/flutter_test.dart';
import 'package:regular_integration_tests/image_load_failure_main.dart' as app;

import 'package:integration_test/integration_test.dart';

/// Tests
void main() {
final IntegrationTestWidgetsFlutterBinding binding =
IntegrationTestWidgetsFlutterBinding.ensureInitialized()
as IntegrationTestWidgetsFlutterBinding;
testWidgets('Image load fails on incorrect asset',
(WidgetTester tester) async {
final StringBuffer buffer = StringBuffer();
await runZoned(() async {
app.main();
await tester.pumpAndSettle();
}, zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
buffer.writeln(line);
}));
final dynamic exception1 = tester.takeException();
expect(exception1, isNotNull);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// 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 'package:integration_test/integration_test_driver.dart' as test;

Future<void> main() async => test.integrationDriver();
24 changes: 22 additions & 2 deletions lib/web_ui/lib/src/engine/assets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,34 @@ class AssetManager {
return Uri.encodeFull((_baseUrl ?? '') + '$assetsDir/$asset');
}

/// Returns true if buffer contains html document.
static bool _responseIsHtmlPage(ByteData data) {
const String htmlDocTypeResponse = '<!DOCTYPE html>';
final int testLength = htmlDocTypeResponse.length;
if (data.lengthInBytes < testLength) {
return false;
}
for (int i = 0; i < testLength; i++) {
if (data.getInt8(i) != htmlDocTypeResponse.codeUnitAt(i))
return false;
}
return true;
}

Future<ByteData> load(String asset) async {
final String url = getAssetUrl(asset);
try {
final html.HttpRequest request =
await html.HttpRequest.request(url, responseType: 'arraybuffer');

// Development server will return index.html for invalid urls.
// The check below makes sure when it is returned for non html assets
// we report an error instead of silent failure.
final ByteBuffer response = request.response;
return response.asByteData();
final ByteData data = response.asByteData();
if (!url.endsWith('html') && _responseIsHtmlPage(data)) {
throw AssetManagerException(url, 404);
}
return data;
} on html.ProgressEvent catch (e) {
final html.EventTarget? target = e.target;
if (target is html.HttpRequest) {
Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/engine/html_image_codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class HtmlCodec implements ui.Codec {
loadSubscription?.cancel();
errorSubscription.cancel();
completer.completeError(event);
throw ArgumentError('Unable to load image asset: $src');
});
loadSubscription = imgElement.onLoad.listen((html.Event event) {
if (chunkCallback != null) {
Expand Down
30 changes: 23 additions & 7 deletions lib/web_ui/lib/src/engine/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,20 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
};
}

void _reportAssetLoadError(String url,
ui.PlatformMessageResponseCallback? callback, String error) {
const MethodCodec codec = JSONMethodCodec();
final String message = 'Error while trying to load an asset $url';
if (!assertionsEnabled) {
/// For web/release mode log the load failure on console.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Shouldn't the _replyToPlatformMessage(...) call below be enough to log the failure?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Shouldn't the _replyToPlatformMessage(...) call below be enough to log the failure?

Otherwise for release builds user gets no indication of failure at all. The error reported by replyToPlatformMessage is silent in release mode.

printWarning(message);
}
_replyToPlatformMessage(
callback, codec.encodeErrorEnvelope(code: 'errorCode',
message: message,
details: error));
}

void _sendPlatformMessage(
String name,
ByteData? data,
Expand All @@ -336,7 +350,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
}

switch (name) {

/// This should be in sync with shell/common/shell.cc
case 'flutter/skia':
const MethodCodec codec = JSONMethodCodec();
Expand Down Expand Up @@ -364,12 +377,15 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {

case 'flutter/assets':
final String url = utf8.decode(data!.buffer.asUint8List());
ui.webOnlyAssetManager.load(url).then((ByteData assetData) {
_replyToPlatformMessage(callback, assetData);
}, onError: (dynamic error) {
printWarning('Error while trying to load an asset: $error');
_replyToPlatformMessage(callback, null);
});
ui.webOnlyAssetManager.load(url)
.then((ByteData assetData) {
_replyToPlatformMessage(callback, assetData);
}, onError: (dynamic error) {
_reportAssetLoadError(url, callback, error);
}
).catchError((dynamic e) {
_reportAssetLoadError(url, callback, e);
});
return;

case 'flutter/platform':
Expand Down