Fix support for MHTML. This uses feature detection to determine if DataURLs, and then if MHTML is supported, and falls back on the original unsprited images.

Closes #376.
This commit is contained in:
Ross Boucher committed 2010-02-19 16:48:57 -08:00
1 parent b2179f14ab
commit b7df6c1480
3 files changed
+96 -67

No files matched your search

+41 -23
View File
@@ -283,7 +283,7 @@ function loadExecutableForBundle(/*Bundle*/ aBundle, success, failure)
{
try
{
decompileStaticFile(aBundle, anEvent.request.responseText());
decompileStaticFile(aBundle, anEvent.request.responseText(), aBundle.executablePath());
aBundle._loadStatus &= ~CFBundleLoadingExecutable;
success();
}
@@ -319,7 +319,7 @@ function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure)
{
try
{
decompileStaticFile(aBundle, anEvent.request.responseText());
decompileStaticFile(aBundle, anEvent.request.responseText(), spritedImagesPath);
aBundle._loadStatus &= ~CFBundleLoadingSpritedImages;
success();
}
@@ -356,9 +356,10 @@ function CFBundleTestSpriteSupport(/*String*/ MHTMLPath, /*Function*/ aCallback)
CFBundleDataURLSpriteType,
"data:image/gif;base64,R0lGODlhAQABAIAAAMc9BQAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==",
CFBundleMHTMLSpriteType,
MHTMLPath,
MHTMLPath+"!test",
CFBundleMHTMLUncachedSpriteType,
MHTMLPath+"?"+CFCacheBuster]);
MHTMLPath+"?"+CFCacheBuster+"!test"
]);
}
function CFBundleNotifySpriteSupportListeners()
@@ -371,6 +372,13 @@ function CFBundleNotifySpriteSupportListeners()
function CFBundleTestSpriteTypes(/*Array*/ spriteTypes)
{
if (spriteTypes.length < 2)
{
CFBundleSupportedSpriteType = CFBundleNoSpriteType;
CFBundleNotifySpriteSupportListeners();
return;
}
var image = new Image();
image.onload = function()
@@ -386,21 +394,25 @@ function CFBundleTestSpriteTypes(/*Array*/ spriteTypes)
image.onerror = function()
{
if (spriteTypes.length === 2)
{
CFBundleSupportedSpriteType = CFBundleNoSpriteType;
CFBundleNotifySpriteSupportListeners();
}
else
CFBundleTestSpriteTypes(spriteTypes.slice(2));
CFBundleTestSpriteTypes(spriteTypes.slice(2));
}
image.src = spriteTypes[1];
}
function mhtmlBasePath()
{
#ifdef BROWSER
//FIXME: URL stuff is kind of broken
return window.location.protocol + "//" + window.location.hostname + (window.location.port ? (":" + window.location.port) : "");
#else
return "";
#endif
}
function spritedImagesTestPathForBundle(/*Bundle*/ aBundle)
{
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLTest.txt");
return "mhtml:" + mhtmlBasePath() + FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLTest.txt");
}
function spritedImagesPathForBundle(/*Bundle*/ aBundle)
@@ -408,12 +420,9 @@ function spritedImagesPathForBundle(/*Bundle*/ aBundle)
if (CFBundleSupportedSpriteType === CFBundleDataURLSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "dataURLs.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTML.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLSpriteType || CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
return mhtmlBasePath() + FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTMLPaths.txt");
if (CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
return FILE.join(aBundle.path(), aBundle.mostEligibleEnvironment() + ".environment", "MHTML.txt?" + CFCacheBuster);
return NULL;
}
@@ -464,8 +473,7 @@ function executeBundle(/*Bundle*/ aBundle, /*Function*/ aCallback)
var children = staticResource.children();
for (var name in children)
if (hasOwnProperty.call(children, name))
staticResources.push(children[name]);
staticResources.push(children[name]);
}
}
@@ -483,15 +491,15 @@ var STATIC_MAGIC_NUMBER = "@STATIC",
MARKER_IMPORT_STD = 'I',
MARKER_IMPORT_LOCAL = 'i';
function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString)
function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString, /*String*/ aPath)
{
var stream = new MarkedStream(aString);
if (stream.magicNumber() !== STATIC_MAGIC_NUMBER)
throw new Error("Could not read static file.");
throw new Error("Could not read static file: "+aPath);
if (stream.version() !== "1.0")
throw new Error("Could not read static file.");
throw new Error("Could not read static file: "+aPath);
var marker,
bundlePath = aBundle.path(),
@@ -514,8 +522,18 @@ function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString)
var URI = stream.getString();
if (URI.toLowerCase().indexOf("mhtml:") === 0)
URI = "mhtml:" + FILE.join(bundlePath, URI.substr("mhtml:".length));
{
URI = "mhtml:" + mhtmlBasePath() + FILE.join(bundlePath, URI.substr("mhtml:".length));
if (CFBundleSupportedSpriteType === CFBundleMHTMLUncachedSpriteType)
{
var exclamationIndex = URI.indexOf("!"),
firstPart = URI.substring(0, exclamationIndex),
lastPart = URI.substring(exclamationIndex);
URI = firstPart + "?" + CFCacheBuster + lastPart;
}
}
aBundle._URIMap[text] = URI;
// The unresolved directories must not be bundles.
@@ -0,0 +1,9 @@
/*
Content-Type: multipart/related; boundary="_SEPARATOR_"
--_SEPARATOR_
Content-Location:test
Content-Transfer-Encoding:base64
R0lGODlhAQABAIAAAMc9BQAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==
*/
@@ -317,7 +317,17 @@ BundleTask.prototype.buildProductStaticPathForEnvironment = function(anEnvironme
BundleTask.prototype.buildProductMHTMLPathForEnvironment = function(anEnvironment)
{
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "MHTML.txt");
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "MHTMLPaths.txt");
}
BundleTask.prototype.buildProductMHTMLDataPathForEnvironment = function(anEnvironment)
{
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "MHTMLData.txt");
}
BundleTask.prototype.buildProductMHTMLTestPathForEnvironment = function(anEnvironment)
{
return FILE.join(this.buildProductPath(), anEnvironment.name() + ".environment", "MHTMLTest.txt");
}
BundleTask.prototype.buildProductDataURLPathForEnvironment = function(anEnvironment)
@@ -460,8 +470,7 @@ BundleTask.prototype.defineResourceTask = function(aResourcePath, aDestinationPa
FILE.write(spritedDestinationPath, base64.encode(FILE.read(aResourcePath, "b")), { charset:"UTF-8" });
});
filedir (this.buildProductDataURLPathForEnvironment(anEnvironment), [spritedDestinationPath]);
filedir (this.buildProductMHTMLPathForEnvironment(anEnvironment), [spritedDestinationPath]);
task (anEnvironment.name() + "-sprites", [spritedDestinationPath]);
}, this);
}
@@ -571,6 +580,10 @@ BundleTask.prototype.defineResourceTasks = function()
}, this);
}
var RESOURCES_PATH = FILE.join(FILE.absolute(FILE.dirname(module.path)), "RESOURCES"),
MHTMLTestPath = FILE.join(RESOURCES_PATH, "MHTMLTest.txt");
BundleTask.prototype.defineSpritedImagesTask = function()
{
this.environments().forEach(function(/*Environment*/ anEnvironment)
@@ -580,16 +593,23 @@ BundleTask.prototype.defineSpritedImagesTask = function()
var folder = anEnvironment.name() + ".environment",
resourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, "Resources", ""),
productName = this.productName(),
dataURLPath = this.buildProductDataURLPathForEnvironment(anEnvironment);
dataURLPath = this.buildProductDataURLPathForEnvironment(anEnvironment),
MHTMLPath = this.buildProductMHTMLPathForEnvironment(anEnvironment),
MHTMLDataPath = this.buildProductMHTMLDataPathForEnvironment(anEnvironment),
MHTMLTestDestinationPath = this.buildProductMHTMLTestPathForEnvironment(anEnvironment),
productName = this.productName();
filedir (dataURLPath, function(aTask)
task(anEnvironment.name() + "-sprites", function(aTask)
{
TERM.stream.print("Creating data URLs file... \0green(" + dataURLPath + "\0)");
TERM.stream.print("Creating sprited images file... \0green(" + dataURLPath +"\0)");
var dataURLStream = FILE.open(dataURLPath, "w+", { charset:"UTF-8" });
var dataURLStream = FILE.open(dataURLPath, "w+", { charset:"UTF-8" }),
MHTMLStream = FILE.open(MHTMLPath, "w+", { charset:"UTF-8" }),
MHTMLDataStream = FILE.open(MHTMLDataPath, "w+", { charset:"UTF-8" });
dataURLStream.write("@STATIC;1.0;");
MHTMLStream.write("@STATIC;1.0;");
MHTMLDataStream.write("/*\r\nContent-Type: multipart/related; boundary=\"_ANY_STRING_WILL_DO_AS_A_SEPARATOR\"\r\n\r\n");
aTask.prerequisites().forEach(function(aFilename)
{
@@ -599,56 +619,39 @@ BundleTask.prototype.defineSpritedImagesTask = function()
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
dataURLStream.write("u;" + resourcePath.length + ";" + resourcePath);
MHTMLStream.write("u;" + resourcePath.length + ";" + resourcePath);
// As data URL...
var contents = "data:" + mimeType(aFilename) +
";base64," + FILE.read(aFilename, "b").decodeToString("UTF-8");
dataURLStream.write(contents.length + ";" + contents);
});
dataURLStream.write("e;");
dataURLStream.close();
});
this.enhance([dataURLPath]);
var MHTMLPath = this.buildProductMHTMLPathForEnvironment(anEnvironment);
filedir (MHTMLPath, function(aTask)
{
TERM.stream.print("Creating MHTML images file... \0green(" + MHTMLPath +"\0)");
var MHTMLStream = FILE.open(MHTMLPath, "w+", { charset:"UTF-8" }),
MHTMLContents = "/*\r\nContent-Type: multipart/related; boundary=\"_ANY_STRING_WILL_DO_AS_A_SEPARATOR\"\r\n\r\n";
MHTMLStream.write("@STATIC;1.0;");
aTask.prerequisites().forEach(function(aFilename)
{
if (!FILE.isFile(aFilename) || aFilename.indexOf(resourcesPath) !== 0 || !isImage(aFilename))
return;
var resourcePath = "Resources/" + FILE.relative(resourcesPath, aFilename);
MHTMLStream.write("u;" + resourcePath.length + ";" + resourcePath);
// As MHTML...
contents = "mhtml:" + FILE.join(folder, productName + ".sj!") + resourcePath;
contents = "mhtml:" + FILE.join(folder, "MHTMLData.txt!") + resourcePath;
MHTMLContents += "--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n";
MHTMLContents += "Content-Location:" + resourcePath + "\r\nContent-Transfer-Encoding:base64\r\n\r\n";
MHTMLContents += FILE.read(aFilename, "b").decodeToString("UTF-8");
MHTMLContents += "\r\n";
MHTMLDataStream.write("--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n");
MHTMLDataStream.write("Content-Location:" + resourcePath + "\r\nContent-Transfer-Encoding:base64\r\n\r\n");
MHTMLDataStream.write(FILE.read(aFilename, "b").decodeToString("UTF-8"));
MHTMLDataStream.write("\r\n");
MHTMLStream.write(contents.length + ";" + contents);
});
dataURLStream.write("e;");
dataURLStream.close();
MHTMLStream.write("e;");
MHTMLStream.write(MHTMLContents + "*/");
MHTMLStream.close();
MHTMLDataStream.write("*/");
MHTMLDataStream.close();
// copy the MHTML test file into this environment
FILE.copy(MHTMLTestPath, MHTMLTestDestinationPath);
});
this.enhance([MHTMLPath]);
this.enhance([anEnvironment.name() + "-sprites"]);
}, this);
}
@@ -668,8 +671,7 @@ BundleTask.prototype.defineStaticTask = function()
{
TERM.stream.print("Creating static file... \0green(" + staticPath +"\0)");
var fileStream = FILE.open(staticPath, "w+", { charset:"UTF-8" }),
MHTMLContents = "";
var fileStream = FILE.open(staticPath, "w+", { charset:"UTF-8" });
fileStream.write("@STATIC;1.0;");