Skip to content

Commit

Permalink
Merge pull request #1126 from fsih/fixQuirksOnLoadCostume
Browse files Browse the repository at this point in the history
Run quirks mode fixes on costumes loaded from sb2s
  • Loading branch information
fsih committed May 10, 2018
2 parents 6ffc206 + 589dd7d commit 5c00364
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
8 changes: 8 additions & 0 deletions src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,14 @@ class Runtime extends EventEmitter {
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
* @param {!ScratchStorage} storage The storage module to attach
Expand Down
27 changes: 23 additions & 4 deletions src/import/load-costume.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ const log = require('../util/log');
* @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
* @param {!Asset} costumeAsset - the asset of the costume loaded from storage.
* @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.
*/
const loadCostumeFromAsset = function (costume, costumeAsset, runtime) {
const loadCostumeFromAsset = function (costume, costumeAsset, runtime, optVersion) {
costume.assetId = costumeAsset.assetId;
const renderer = runtime.renderer;
if (!renderer) {
Expand All @@ -29,9 +31,24 @@ const loadCostumeFromAsset = function (costume, costumeAsset, runtime) {
];
}
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
// undefined here
costume.skinId = renderer.createSVGSkin(costumeAsset.decodeText(), rotationCenter);
costume.skinId = renderer.createSVGSkin(svgString, rotationCenter);
costume.size = renderer.getSkinSize(costume.skinId);
// Now we should have a rotationCenter even if we didn't before
if (!rotationCenter) {
Expand Down Expand Up @@ -86,9 +103,11 @@ const loadCostumeFromAsset = function (costume, costumeAsset, runtime) {
* @property {number} rotationCenterY - the Y component of the costume's origin.
* @property {number} [bitmapResolution] - the resolution scale for a bitmap costume.
* @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.
*/
const loadCostume = function (md5ext, costume, runtime) {
const loadCostume = function (md5ext, costume, runtime, optVersion) {
if (!runtime.storage) {
log.error('No storage module present; cannot load costume asset: ', md5ext);
return Promise.resolve(costume);
Expand All @@ -102,7 +121,7 @@ const loadCostume = function (md5ext, costume, runtime) {

return runtime.storage.load(assetType, md5, ext).then(costumeAsset => {
costume.dataFormat = ext;
return loadCostumeFromAsset(costume, costumeAsset, runtime);
return loadCostumeFromAsset(costume, costumeAsset, runtime, optVersion);
});
};

Expand Down
2 changes: 1 addition & 1 deletion src/serialization/sb2.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
const assetFileName = `${costumeSource.baseLayerID}.${ext}`;
costumePromises.push(deserializeCostume(costume, runtime, zip, assetFileName)
.then(() => loadCostume(costume.md5, costume, runtime)));
.then(() => loadCostume(costume.md5, costume, runtime, 2 /* optVersion */)));
}
}
// Sounds from JSON
Expand Down
8 changes: 8 additions & 0 deletions src/virtual-machine.js
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,14 @@ class VirtualMachine extends EventEmitter {
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
* @param {!ScratchStorage} storage The storage module to attach
Expand Down

0 comments on commit 5c00364

Please sign in to comment.