Skip to content

Commit 18a33bd

Browse files
richtrmrdoob
authored andcommitted
Handle Data URIs passed in to THREE.XHRLoader manually since Safari can not load Data URIs through XMLHttpRequest (mrdoob#9823)
1 parent 6ab1bdd commit 18a33bd

File tree

1 file changed

+122
-30
lines changed

1 file changed

+122
-30
lines changed

src/loaders/XHRLoader.js

Lines changed: 122 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Object.assign( XHRLoader.prototype, {
1515

1616
load: function ( url, onLoad, onProgress, onError ) {
1717

18+
if ( url === undefined ) url = '';
19+
1820
if ( this.path !== undefined ) url = this.path + url;
1921

2022
var scope = this;
@@ -37,66 +39,156 @@ Object.assign( XHRLoader.prototype, {
3739

3840
}
3941

40-
var request = new XMLHttpRequest();
41-
request.open( 'GET', url, true );
42+
// Check for data: URI
43+
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
44+
var dataUriRegexResult = url.match( dataUriRegex );
4245

43-
request.addEventListener( 'load', function ( event ) {
46+
// Safari can not handle Data URIs through XMLHttpRequest so process manually
47+
if ( dataUriRegexResult ) {
4448

45-
var response = event.target.response;
49+
var mimeType = dataUriRegexResult[1];
50+
var isBase64 = !!dataUriRegexResult[2];
51+
var data = dataUriRegexResult[3];
4652

47-
Cache.add( url, response );
53+
data = window.decodeURIComponent(data);
4854

49-
if ( this.status === 200 ) {
55+
if( isBase64 ) {
56+
data = window.atob(data);
57+
}
5058

51-
if ( onLoad ) onLoad( response );
59+
try {
5260

53-
scope.manager.itemEnd( url );
61+
var response;
62+
var responseType = ( this.responseType || '' ).toLowerCase();
5463

55-
} else if ( this.status === 0 ) {
64+
switch ( responseType ) {
5665

57-
// Some browsers return HTTP Status 0 when using non-http protocol
58-
// e.g. 'file://' or 'data://'. Handle as success.
66+
case 'arraybuffer':
67+
case 'blob':
5968

60-
console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );
69+
response = new ArrayBuffer( data.length );
70+
var view = new Uint8Array( response );
71+
for ( var i = 0; i < data.length; i ++ ) {
6172

62-
if ( onLoad ) onLoad( response );
73+
view[ i ] = data.charCodeAt( i );
6374

64-
scope.manager.itemEnd( url );
75+
}
6576

66-
} else {
77+
if ( responseType === 'blob' ) {
6778

68-
if ( onError ) onError( event );
79+
response = new Blob( [ response ], { "type" : mimeType } );
6980

70-
scope.manager.itemError( url );
81+
}
82+
83+
break;
84+
85+
case 'document':
86+
87+
var parser = new DOMParser();
88+
response = parser.parseFromString( data, mimeType );
89+
90+
break;
91+
92+
case 'json':
93+
94+
response = JSON.parse( data );
95+
96+
break;
97+
98+
default: // 'text' or other
99+
100+
response = data;
101+
102+
break;
103+
104+
}
105+
106+
// Wait for next browser tick
107+
window.setTimeout( function() {
108+
109+
if ( onLoad ) onLoad( response );
110+
111+
scope.manager.itemEnd( url );
112+
113+
}, 0);
114+
115+
} catch ( error ) {
116+
117+
// Wait for next browser tick
118+
window.setTimeout( function() {
119+
120+
if ( onError ) onError( error );
121+
122+
scope.manager.itemError( url );
123+
124+
}, 0);
71125

72126
}
73127

74-
}, false );
128+
} else {
129+
130+
var request = new XMLHttpRequest();
131+
request.open( 'GET', url, true );
132+
133+
request.addEventListener( 'load', function ( event ) {
134+
135+
var response = event.target.response;
136+
137+
Cache.add( url, response );
138+
139+
if ( this.status === 200 ) {
140+
141+
if ( onLoad ) onLoad( response );
142+
143+
scope.manager.itemEnd( url );
144+
145+
} else if ( this.status === 0 ) {
146+
147+
// Some browsers return HTTP Status 0 when using non-http protocol
148+
// e.g. 'file://' or 'data://'. Handle as success.
149+
150+
console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );
151+
152+
if ( onLoad ) onLoad( response );
153+
154+
scope.manager.itemEnd( url );
75155

76-
if ( onProgress !== undefined ) {
156+
} else {
77157

78-
request.addEventListener( 'progress', function ( event ) {
158+
if ( onError ) onError( event );
79159

80-
onProgress( event );
160+
scope.manager.itemError( url );
161+
162+
}
81163

82164
}, false );
83165

84-
}
166+
if ( onProgress !== undefined ) {
167+
168+
request.addEventListener( 'progress', function ( event ) {
169+
170+
onProgress( event );
171+
172+
}, false );
173+
174+
}
175+
176+
request.addEventListener( 'error', function ( event ) {
85177

86-
request.addEventListener( 'error', function ( event ) {
178+
if ( onError ) onError( event );
87179

88-
if ( onError ) onError( event );
180+
scope.manager.itemError( url );
89181

90-
scope.manager.itemError( url );
182+
}, false );
91183

92-
}, false );
184+
if ( this.responseType !== undefined ) request.responseType = this.responseType;
185+
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
93186

94-
if ( this.responseType !== undefined ) request.responseType = this.responseType;
95-
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
187+
if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );
96188

97-
if ( request.overrideMimeType ) request.overrideMimeType( 'text/plain' );
189+
request.send( null );
98190

99-
request.send( null );
191+
}
100192

101193
scope.manager.itemStart( url );
102194

0 commit comments

Comments
 (0)