Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix crash in Safari at the start of the game

  • Loading branch information...
commit 18b6537eb4f71903453ce08d83752d4e337f3f52 1 parent d701895
@sork sork authored
Showing with 111 additions and 40 deletions.
  1. +10 −6 client/js/game.js
  2. +71 −33 client/js/renderer.js
  3. +30 −1 client/js/util.js
View
16 client/js/game.js
@@ -791,9 +791,11 @@ function(InfoManager, BubbleManager, Renderer, Map, Animation, Sprite, AnimatedT
if(!self.storage.hasAlreadyPlayed()) {
self.storage.initPlayer(self.player.name);
- self.storage.savePlayer(self.renderer.getPlayerImage(),
- self.player.getSpriteName(),
- self.player.getWeaponName());
+ self.renderer.getPlayerImage(function(playerImage) {
+ self.storage.savePlayer(playerImage,
+ self.player.getSpriteName(),
+ self.player.getWeaponName());
+ });
self.showNotification("Welcome to BrowserQuest!");
} else {
self.showNotification("Welcome back to BrowserQuest!");
@@ -1055,9 +1057,11 @@ function(InfoManager, BubbleManager, Renderer, Map, Animation, Sprite, AnimatedT
});
self.player.onSwitchItem(function() {
- self.storage.savePlayer(self.renderer.getPlayerImage(),
- self.player.getArmorName(),
- self.player.getWeaponName());
+ self.renderer.getPlayerImage(function(playerImage) {
+ self.storage.savePlayer(playerImage,
+ self.player.getArmorName(),
+ self.player.getWeaponName());
+ });
if(self.equipment_callback) {
self.equipment_callback();
}
View
104 client/js/renderer.js
@@ -664,42 +664,80 @@ function(Camera, Item, Character, Player, Timer) {
clearScreen: function(ctx) {
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
-
- getPlayerImage: function() {
+
+ getPlayerImage: function(callback) {
var canvas = document.createElement('canvas'),
- ctx = canvas.getContext('2d'),
- os = this.upscaledRendering ? 1 : this.scale,
- player = this.game.player,
- sprite = player.getArmorSprite(),
- spriteAnim = sprite.animationData["idle_down"],
- // character
- row = spriteAnim.row,
+ ctx = canvas.getContext('2d'),
+ os = this.upscaledRendering ? 1 : this.scale,
+ player = this.game.player,
+ sprite = player.getArmorSprite(),
+ spriteAnim = sprite.animationData["idle_down"],
+ // character
+ row = spriteAnim.row,
w = sprite.width * os,
h = sprite.height * os,
- y = row * h,
- // weapon
- weapon = this.game.sprites[this.game.player.getWeaponName()],
- ww = weapon.width * os,
- wh = weapon.height * os,
- wy = wh * row,
- offsetX = (weapon.offsetX - sprite.offsetX) * os,
- offsetY = (weapon.offsetY - sprite.offsetY) * os,
- // shadow
- shadow = this.game.shadows["small"],
- sw = shadow.width * os,
- sh = shadow.height * os,
- ox = -sprite.offsetX * os;
- oy = -sprite.offsetY * os;
-
- canvas.width = w;
- canvas.height = h;
-
- ctx.clearRect(0, 0, w, h);
- ctx.drawImage(shadow.image, 0, 0, sw, sh, ox, oy, sw, sh);
- ctx.drawImage(sprite.image, 0, y, w, h, 0, 0, w, h);
- ctx.drawImage(weapon.image, 0, wy, ww, wh, offsetX, offsetY, ww, wh);
-
- return canvas.toDataURL("image/png");
+ y = row * h,
+ // weapon
+ weapon = this.game.sprites[player.getWeaponName()],
+ ww = weapon.width * os,
+ wh = weapon.height * os,
+ wy = wh * row,
+ offsetX = (weapon.offsetX - sprite.offsetX) * os,
+ offsetY = (weapon.offsetY - sprite.offsetY) * os,
+ // shadow
+ shadow = this.game.shadows["small"],
+ sw = shadow.width * os,
+ sh = shadow.height * os,
+ ox = -sprite.offsetX * os,
+ oy = -sprite.offsetY * os,
+ drawPlayerImage = function(shadowImage, spriteImage, weaponImage) {
+ ctx.drawImage(shadowImage, 0, 0, sw, sh, ox, oy, sw, sh);
+ ctx.drawImage(spriteImage, 0, y, w, h, 0, 0, w, h);
+ ctx.drawImage(weaponImage, 0, wy, ww, wh, offsetX, offsetY, ww, wh);
+
+ if(callback) {
+ callback(canvas.toDataURL("image/png"));
+ }
+ };
+
+ canvas.width = w;
+ canvas.height = h;
+ ctx.clearRect(0, 0, w, h);
+
+ if(Detect.isSafari()) {
+ // In Safari, any image loaded from an external domain drawn onto a canvas makes it tainted even though the .crossOrigin property was set.
+ // This triggers a security exception when calling toDataURL() on this canvas.
+ //
+ // When using a CDN for images, we need to use a workaround in order to be able to render the player image.
+ // We retrieve via XHR three base64 images which compose the player image (current armor, current weapon, shadow).
+ // These three base64 images are then rendered onto a canvas, which can then be converted to a data URL because it's not tainted.
+
+ var imgCounter = 3, spriteImage, weaponImage, shadowImage, basePath = 'http://cdn.mozilla.net/browserquest/img/',
+ tryDrawing = function() {
+ imgCounter -= 1;
+ if(imgCounter == 0) {
+ drawPlayerImage(shadowImage, spriteImage, weaponImage);
+ }
+ };
+
+ getBase64Image(basePath+this.scale+'/'+player.getArmorName()+'.png', function(img) {
+ spriteImage = img;
+ tryDrawing();
+ });
+ getBase64Image(basePath+this.scale+'/shadow16.png', function(img) {
+ shadowImage = img;
+ tryDrawing();
+ });
+ getBase64Image(basePath+this.scale+'/'+player.getWeaponName()+'.png', function(img) {
+ weaponImage = img;
+ tryDrawing();
+ });
+ } else {
+ drawPlayerImage(shadow.image, sprite.image, weapon.image);
+ if(callback) {
+ callback(canvas.toDataURL("image/png"));
+ }
+ }
},
renderStaticCanvases: function() {
View
31 client/js/util.js
@@ -22,4 +22,33 @@ window.requestAnimFrame = (function(){
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
-})();
+})();
+
+// Adapted from: http://stackoverflow.com/a/8022521/38072
+var getBase64Image = function(url, callback) {
+ var xhr = new XMLHttpRequest(),
+ img = new Image();
+
+ xhr.open('GET', url, true);
+ xhr.responseType = 'arraybuffer';
+
+ xhr.onload = function(e) {
+ if (this.status == 200) {
+ var uInt8Array = new Uint8Array(this.response);
+ var i = uInt8Array.length;
+ var binaryString = new Array(i);
+ while (i--) {
+ binaryString[i] = String.fromCharCode(uInt8Array[i]);
+ }
+ var data = binaryString.join('');
+
+ var base64 = window.btoa(data);
+
+ img.onload = function() {
+ callback(img);
+ };
+ img.src = "data:image/png;base64,"+base64;
+ }
+ };
+ xhr.send();
+};
Please sign in to comment.
Something went wrong with that request. Please try again.