Commit 680d581d authored by Hans Muller's avatar Hans Muller Committed by GitHub

Correct handling of assets when no main asset is present (#11564)

parent 5ee8390e
......@@ -150,7 +150,6 @@ class AssetImage extends AssetBundleImageProvider {
final SplayTreeMap<double, String> mapping = new SplayTreeMap<double, String>();
for (String candidate in candidates)
mapping[_parseScale(candidate)] = candidate;
mapping[_naturalResolution] = main;
// TODO(ianh): implement support for config.locale, config.size, config.platform
// (then document this over in the Image.asset docs)
return _findNearest(mapping, config.devicePixelRatio);
......
......@@ -34,9 +34,10 @@ class TestByteData implements ByteData {
dynamic noSuchMethod(Invocation invocation) => null;
}
String testManifest = '''
const String testManifest = '''
{
"assets/image.png" : [
"assets/image.png",
"assets/1.5x/image.png",
"assets/2.0x/image.png",
"assets/3.0x/image.png",
......@@ -46,6 +47,10 @@ String testManifest = '''
''';
class TestAssetBundle extends CachingAssetBundle {
TestAssetBundle({ this.manifest: testManifest });
final String manifest;
@override
Future<ByteData> load(String key) {
ByteData data;
......@@ -53,6 +58,9 @@ class TestAssetBundle extends CachingAssetBundle {
case 'assets/image.png':
data = new TestByteData(1.0);
break;
case 'assets/1.0x/image.png':
data = new TestByteData(10.0); // see "...with a main asset and a 1.0x asset"
break;
case 'assets/1.5x/image.png':
data = new TestByteData(1.5);
break;
......@@ -72,7 +80,7 @@ class TestAssetBundle extends CachingAssetBundle {
@override
Future<String> loadString(String key, { bool cache: true }) {
if (key == 'AssetManifest.json')
return new SynchronousFuture<String>(testManifest);
return new SynchronousFuture<String>(manifest);
return null;
}
......@@ -101,7 +109,7 @@ class TestAssetImage extends AssetImage {
}
}
Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize) {
Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize, [AssetBundle bundle]) {
const double windowSize = 500.0; // 500 logical pixels
const double imageSize = 200.0; // 200 logical pixels
......@@ -112,7 +120,7 @@ Widget buildImageAtRatio(String image, Key key, double ratio, bool inferSize) {
padding: const EdgeInsets.all(0.0)
),
child: new DefaultAssetBundle(
bundle: new TestAssetBundle(),
bundle: bundle ?? new TestAssetBundle(),
child: new Center(
child: inferSize ?
new Image(
......@@ -231,4 +239,57 @@ void main() {
expect(getTestImage(tester, key).scale, 4.0);
});
testWidgets('Image for device pixel ratio 1.0, with no main asset', (WidgetTester tester) async {
const String manifest = '''
{
"assets/image.png" : [
"assets/1.5x/image.png",
"assets/2.0x/image.png",
"assets/3.0x/image.png",
"assets/4.0x/image.png"
]
}
''';
final AssetBundle bundle = new TestAssetBundle(manifest: manifest);
const double ratio = 1.0;
Key key = new GlobalKey();
await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, bundle));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getTestImage(tester, key).scale, 1.5);
key = new GlobalKey();
await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, bundle));
expect(getRenderImage(tester, key).size, const Size(48.0, 48.0));
expect(getTestImage(tester, key).scale, 1.5);
});
testWidgets('Image for device pixel ratio 1.0, with a main asset and a 1.0x asset', (WidgetTester tester) async {
// If both a main asset and a 1.0x asset are specified, then prefer
// the 1.0x asset.
const String manifest = '''
{
"assets/image.png" : [
"assets/image.png",
"assets/1.0x/image.png",
"assets/1.5x/image.png",
"assets/2.0x/image.png",
"assets/3.0x/image.png",
"assets/4.0x/image.png"
]
}
''';
final AssetBundle bundle = new TestAssetBundle(manifest: manifest);
const double ratio = 1.0;
Key key = new GlobalKey();
await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, bundle));
expect(getRenderImage(tester, key).size, const Size(200.0, 200.0));
expect(getTestImage(tester, key).scale, 10.0);
key = new GlobalKey();
await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, true, bundle));
expect(getRenderImage(tester, key).size, const Size(480.0, 480.0));
expect(getTestImage(tester, key).scale, 10.0);
});
}
......@@ -98,6 +98,10 @@ class AssetBundle {
final PackageMap packageMap = new PackageMap(packagesPath);
// The _assetVariants map contains an entry for each asset listed
// in the pubspec.yaml file's assets and font and sections. The
// value of each image asset is a list of resolution-specific "variants",
// see _AssetDirectoryCache.
final Map<_Asset, List<_Asset>> assetVariants = _parseAssets(
packageMap,
manifestDescriptor,
......@@ -112,14 +116,24 @@ class AssetBundle {
manifestDescriptor.containsKey('uses-material-design') &&
manifestDescriptor['uses-material-design'];
// Save the contents of each image, image variant, and font
// asset in entries.
for (_Asset asset in assetVariants.keys) {
if (!asset.assetFileExists && assetVariants[asset].isEmpty) {
printStatus('Error detected in pubspec.yaml:', emphasis: true);
printError('No file or variants found for $asset.\n');
return 1;
}
if (asset.assetFileExists)
entries[asset.assetEntry] = new DevFSFileContent(asset.assetFile);
// The file name for an asset's "main" entry is whatever appears in
// the pubspec.yaml file. The main entry's file must always exist for
// font assets. It need not exist for an image if resolution-specific
// variant files exist. An image's main entry is treated the same as a
// "1x" resolution variant and if both exist then the explicit 1x
// variant is preferred.
if (asset.assetFileExists) {
assert(!assetVariants[asset].contains(asset));
assetVariants[asset].insert(0, asset);
}
for (_Asset variant in assetVariants[asset]) {
assert(variant.assetFileExists);
entries[variant.assetEntry] = new DevFSFileContent(variant.assetFile);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment