瀏覽代碼

Handle Data URIs passed in to THREE.XHRLoader manually since Safari can not load Data URIs through XMLHttpRequest (#9823)

Rich Tibbett 8 年之前
父節點
當前提交
18a33bdbac
共有 1 個文件被更改,包括 122 次插入30 次删除
  1. 122 30
      src/loaders/XHRLoader.js

+ 122 - 30
src/loaders/XHRLoader.js

@@ -15,6 +15,8 @@ Object.assign( XHRLoader.prototype, {
 
 
 	load: function ( url, onLoad, onProgress, onError ) {
 	load: function ( url, onLoad, onProgress, onError ) {
 
 
+		if ( url === undefined ) url = '';
+
 		if ( this.path !== undefined ) url = this.path + url;
 		if ( this.path !== undefined ) url = this.path + url;
 
 
 		var scope = this;
 		var scope = this;
@@ -37,66 +39,156 @@ Object.assign( XHRLoader.prototype, {
 
 
 		}
 		}
 
 
-		var request = new XMLHttpRequest();
-		request.open( 'GET', url, true );
+		// Check for data: URI
+		var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
+		var dataUriRegexResult = url.match( dataUriRegex );
 
 
-		request.addEventListener( 'load', function ( event ) {
+		// Safari can not handle Data URIs through XMLHttpRequest so process manually
+		if ( dataUriRegexResult ) {
 
 
-			var response = event.target.response;
+			var mimeType = dataUriRegexResult[1];
+			var isBase64 = !!dataUriRegexResult[2];
+			var data = dataUriRegexResult[3];
 
 
-			Cache.add( url, response );
+			data = window.decodeURIComponent(data);
 
 
-			if ( this.status === 200 ) {
+			if( isBase64 ) {
+				data = window.atob(data);
+			}
 
 
-				if ( onLoad ) onLoad( response );
+			try {
 
 
-				scope.manager.itemEnd( url );
+				var response;
+				var responseType = ( this.responseType || '' ).toLowerCase();
 
 
-			} else if ( this.status === 0 ) {
+				switch ( responseType ) {
 
 
-				// Some browsers return HTTP Status 0 when using non-http protocol
-				// e.g. 'file://' or 'data://'. Handle as success.
+					case 'arraybuffer':
+					case 'blob':
 
 
-				console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );
+					 	response = new ArrayBuffer( data.length );
+						var view = new Uint8Array( response );
+						for ( var i = 0; i < data.length; i ++ ) {
 
 
-				if ( onLoad ) onLoad( response );
+								view[ i ] = data.charCodeAt( i );
 
 
-				scope.manager.itemEnd( url );
+						}
 
 
-			} else {
+						if ( responseType === 'blob' ) {
 
 
-				if ( onError ) onError( event );
+							response = new Blob( [ response ], { "type" : mimeType } );
 
 
-				scope.manager.itemError( url );
+						}
+
+						break;
+
+					case 'document':
+
+						var parser = new DOMParser();
+						response = parser.parseFromString( data, mimeType );
+
+						break;
+
+					case 'json':
+
+						response = JSON.parse( data );
+
+						break;
+
+					default: // 'text' or other
+
+						response = data;
+
+						break;
+
+				}
+
+				// Wait for next browser tick
+				window.setTimeout( function() {
+
+					if ( onLoad ) onLoad( response );
+
+					scope.manager.itemEnd( url );
+
+				}, 0);
+
+			} catch ( error ) {
+
+				// Wait for next browser tick
+				window.setTimeout( function() {
+
+					if ( onError ) onError( error );
+
+					scope.manager.itemError( url );
+
+				}, 0);
 
 
 			}
 			}
 
 
-		}, false );
+		} else {
+
+			var request = new XMLHttpRequest();
+			request.open( 'GET', url, true );
+
+			request.addEventListener( 'load', function ( event ) {
+
+				var response = event.target.response;
+
+				Cache.add( url, response );
+
+				if ( this.status === 200 ) {
+
+					if ( onLoad ) onLoad( response );
+
+					scope.manager.itemEnd( url );
+
+				} else if ( this.status === 0 ) {
+
+					// Some browsers return HTTP Status 0 when using non-http protocol
+					// e.g. 'file://' or 'data://'. Handle as success.
+
+					console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );
+
+					if ( onLoad ) onLoad( response );
+
+					scope.manager.itemEnd( url );
 
 
-		if ( onProgress !== undefined ) {
+				} else {
 
 
-			request.addEventListener( 'progress', function ( event ) {
+					if ( onError ) onError( event );
 
 
-				onProgress( event );
+					scope.manager.itemError( url );
+
+				}
 
 
 			}, false );
 			}, false );
 
 
-		}
+			if ( onProgress !== undefined ) {
+
+				request.addEventListener( 'progress', function ( event ) {
+
+					onProgress( event );
+
+				}, false );
+
+			}
+
+			request.addEventListener( 'error', function ( event ) {
 
 
-		request.addEventListener( 'error', function ( event ) {
+				if ( onError ) onError( event );
 
 
-			if ( onError ) onError( event );
+				scope.manager.itemError( url );
 
 
-			scope.manager.itemError( url );
+			}, false );
 
 
-		}, false );
+			if ( this.responseType !== undefined ) request.responseType = this.responseType;
+			if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
 
 
-		if ( this.responseType !== undefined ) request.responseType = this.responseType;
-		if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
+			if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );
 
 
-		if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );
+			request.send( null );
 
 
-		request.send( null );
+		}
 
 
 		scope.manager.itemStart( url );
 		scope.manager.itemStart( url );