Merge pull request from fsih/fixQuirksOnLoadCostume

Run quirks mode fixes on costumes loaded from sb2s
This commit is contained in:
DD Liu 2018-05-10 13:42:48 -04:00 committed by GitHub
commit 5c003641f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 5 deletions

View file

@ -917,6 +917,14 @@ class Runtime extends EventEmitter {
this.renderer = renderer; this.renderer = renderer;
} }
/**
* Set the svg adapter, which converts scratch 2 svgs to scratch 3 svgs
* @param {!SvgRenderer} svgAdapter The adapter to attach
*/
attachV2SVGAdapter (svgAdapter) {
this.v2SvgAdapter = svgAdapter;
}
/** /**
* Attach the storage module * Attach the storage module
* @param {!ScratchStorage} storage The storage module to attach * @param {!ScratchStorage} storage The storage module to attach

View file

@ -11,9 +11,11 @@ const log = require('../util/log');
* @property {number} [bitmapResolution] - the resolution scale for a bitmap costume. * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
* @param {!Asset} costumeAsset - the asset of the costume loaded from storage. * @param {!Asset} costumeAsset - the asset of the costume loaded from storage.
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
* @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
* to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
* @returns {?Promise} - a promise which will resolve after skinId is set, or null on error. * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
*/ */
const loadCostumeFromAsset = function (costume, costumeAsset, runtime) { const loadCostumeFromAsset = function (costume, costumeAsset, runtime, optVersion) {
costume.assetId = costumeAsset.assetId; costume.assetId = costumeAsset.assetId;
const renderer = runtime.renderer; const renderer = runtime.renderer;
if (!renderer) { if (!renderer) {
@ -29,9 +31,24 @@ const loadCostumeFromAsset = function (costume, costumeAsset, runtime) {
]; ];
} }
if (costumeAsset.assetType === AssetType.ImageVector) { if (costumeAsset.assetType === AssetType.ImageVector) {
let svgString = costumeAsset.decodeText();
// SVG Renderer load fixes "quirks" associated with Scratch 2 projects
if (optVersion && optVersion === 2 && runtime.v2SvgAdapter) {
runtime.v2SvgAdapter.loadString(svgString);
svgString = runtime.v2SvgAdapter.toString();
// Put back into storage
const storage = runtime.storage;
costumeAsset.encodeTextData(svgString, storage.DataFormat.SVG);
costume.assetId = storage.builtinHelper.cache(
storage.AssetType.ImageVector,
storage.DataFormat.SVG,
costumeAsset.data
);
costume.md5 = `${costume.assetId}.${costume.dataFormat}`;
}
// createSVGSkin does the right thing if rotationCenter isn't provided, so it's okay if it's // createSVGSkin does the right thing if rotationCenter isn't provided, so it's okay if it's
// undefined here // undefined here
costume.skinId = renderer.createSVGSkin(costumeAsset.decodeText(), rotationCenter); costume.skinId = renderer.createSVGSkin(svgString, rotationCenter);
costume.size = renderer.getSkinSize(costume.skinId); costume.size = renderer.getSkinSize(costume.skinId);
// Now we should have a rotationCenter even if we didn't before // Now we should have a rotationCenter even if we didn't before
if (!rotationCenter) { if (!rotationCenter) {
@ -86,9 +103,11 @@ const loadCostumeFromAsset = function (costume, costumeAsset, runtime) {
* @property {number} rotationCenterY - the Y component of the costume's origin. * @property {number} rotationCenterY - the Y component of the costume's origin.
* @property {number} [bitmapResolution] - the resolution scale for a bitmap costume. * @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
* @param {!Runtime} runtime - Scratch runtime, used to access the storage module. * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
* @param {?int} optVersion - Version of Scratch that the costume comes from. If this is set
* to 2, scratch 3 will perform an upgrade step to handle quirks in SVGs from Scratch 2.0.
* @returns {?Promise} - a promise which will resolve after skinId is set, or null on error. * @returns {?Promise} - a promise which will resolve after skinId is set, or null on error.
*/ */
const loadCostume = function (md5ext, costume, runtime) { const loadCostume = function (md5ext, costume, runtime, optVersion) {
if (!runtime.storage) { if (!runtime.storage) {
log.error('No storage module present; cannot load costume asset: ', md5ext); log.error('No storage module present; cannot load costume asset: ', md5ext);
return Promise.resolve(costume); return Promise.resolve(costume);
@ -102,7 +121,7 @@ const loadCostume = function (md5ext, costume, runtime) {
return runtime.storage.load(assetType, md5, ext).then(costumeAsset => { return runtime.storage.load(assetType, md5, ext).then(costumeAsset => {
costume.dataFormat = ext; costume.dataFormat = ext;
return loadCostumeFromAsset(costume, costumeAsset, runtime); return loadCostumeFromAsset(costume, costumeAsset, runtime, optVersion);
}); });
}; };

View file

@ -360,7 +360,7 @@ const parseScratchObject = function (object, runtime, extensions, topLevel, zip)
// the file name of the costume should be the baseLayerID followed by the file ext // the file name of the costume should be the baseLayerID followed by the file ext
const assetFileName = `${costumeSource.baseLayerID}.${ext}`; const assetFileName = `${costumeSource.baseLayerID}.${ext}`;
costumePromises.push(deserializeCostume(costume, runtime, zip, assetFileName) costumePromises.push(deserializeCostume(costume, runtime, zip, assetFileName)
.then(() => loadCostume(costume.md5, costume, runtime))); .then(() => loadCostume(costume.md5, costume, runtime, 2 /* optVersion */)));
} }
} }
// Sounds from JSON // Sounds from JSON

View file

@ -826,6 +826,14 @@ class VirtualMachine extends EventEmitter {
this.runtime.attachRenderer(renderer); this.runtime.attachRenderer(renderer);
} }
/**
* Set the svg adapter for the VM/runtime, which converts scratch 2 svgs to scratch 3 svgs
* @param {!SvgRenderer} svgAdapter The adapter to attach
*/
attachV2SVGAdapter (svgAdapter) {
this.runtime.attachV2SVGAdapter(svgAdapter);
}
/** /**
* Set the storage module for the VM/runtime * Set the storage module for the VM/runtime
* @param {!ScratchStorage} storage The storage module to attach * @param {!ScratchStorage} storage The storage module to attach