Throttle HTML5 image loading
This commit is contained in:
@@ -2,21 +2,27 @@ package lime._backend.html5;
|
|||||||
|
|
||||||
|
|
||||||
import js.html.Event;
|
import js.html.Event;
|
||||||
|
import js.html.Image in JSImage;
|
||||||
import js.html.ProgressEvent;
|
import js.html.ProgressEvent;
|
||||||
import js.html.XMLHttpRequest;
|
import js.html.XMLHttpRequest;
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
import lime.app.Future;
|
import lime.app.Future;
|
||||||
import lime.app.Promise;
|
import lime.app.Promise;
|
||||||
|
import lime.graphics.Image;
|
||||||
|
import lime.graphics.ImageBuffer;
|
||||||
import lime.net.HTTPRequest;
|
import lime.net.HTTPRequest;
|
||||||
import lime.net.HTTPRequestHeader;
|
import lime.net.HTTPRequestHeader;
|
||||||
|
import lime.utils.AssetType;
|
||||||
|
|
||||||
|
@:access(lime.graphics.ImageBuffer)
|
||||||
|
|
||||||
|
|
||||||
class HTML5HTTPRequest {
|
class HTML5HTTPRequest {
|
||||||
|
|
||||||
|
|
||||||
private static var activeRequests:Int;
|
private static var activeRequests = 0;
|
||||||
private static var requestLimit:Int;
|
private static var requestLimit = 4;
|
||||||
private static var requestQueue:List<QueueItem>;
|
private static var requestQueue = new List<QueueItem> ();
|
||||||
|
|
||||||
private var binary:Bool;
|
private var binary:Bool;
|
||||||
private var parent:_IHTTPRequest;
|
private var parent:_IHTTPRequest;
|
||||||
@@ -45,14 +51,6 @@ class HTML5HTTPRequest {
|
|||||||
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
if (requestQueue == null) {
|
|
||||||
|
|
||||||
activeRequests = 0;
|
|
||||||
requestLimit = 6;
|
|
||||||
requestQueue = new List<QueueItem> ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -134,6 +132,124 @@ class HTML5HTTPRequest {
|
|||||||
|
|
||||||
var promise = new Promise<Bytes> ();
|
var promise = new Promise<Bytes> ();
|
||||||
|
|
||||||
|
if (activeRequests < requestLimit) {
|
||||||
|
|
||||||
|
activeRequests++;
|
||||||
|
__loadData (uri, promise);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
requestQueue.add ({ instance: this, uri: uri, promise: promise, type: AssetType.BINARY });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.future;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static function loadImage (uri:String):Future<Image> {
|
||||||
|
|
||||||
|
var promise = new Promise<Image> ();
|
||||||
|
|
||||||
|
if (activeRequests < requestLimit) {
|
||||||
|
|
||||||
|
activeRequests++;
|
||||||
|
__loadImage (uri, promise);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
requestQueue.add ({ instance: null, uri: uri, promise: promise, type: AssetType.IMAGE });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.future;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function loadText (uri:String):Future<String> {
|
||||||
|
|
||||||
|
var promise = new Promise<String> ();
|
||||||
|
|
||||||
|
if (activeRequests < requestLimit) {
|
||||||
|
|
||||||
|
activeRequests++;
|
||||||
|
__loadText (uri, promise);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
requestQueue.add ({ instance: this, uri: uri, promise: promise, type: AssetType.TEXT });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.future;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static function processQueue ():Void {
|
||||||
|
|
||||||
|
if (activeRequests < requestLimit && requestQueue.length > 0) {
|
||||||
|
|
||||||
|
activeRequests++;
|
||||||
|
|
||||||
|
var queueItem = requestQueue.pop ();
|
||||||
|
|
||||||
|
switch (queueItem.type) {
|
||||||
|
|
||||||
|
case IMAGE:
|
||||||
|
|
||||||
|
__loadImage (queueItem.uri, queueItem.promise);
|
||||||
|
|
||||||
|
case TEXT:
|
||||||
|
|
||||||
|
queueItem.instance.__loadText (queueItem.uri, queueItem.promise);
|
||||||
|
|
||||||
|
case BINARY:
|
||||||
|
|
||||||
|
queueItem.instance.__loadData (queueItem.uri, queueItem.promise);
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
activeRequests--;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function processResponse ():Void {
|
||||||
|
|
||||||
|
if (parent.enableResponseHeaders) {
|
||||||
|
|
||||||
|
parent.responseHeaders = [];
|
||||||
|
var name, value;
|
||||||
|
|
||||||
|
for (line in request.getAllResponseHeaders ().split ("\n")) {
|
||||||
|
|
||||||
|
name = StringTools.trim (line.substr (0, line.indexOf (":")));
|
||||||
|
value = StringTools.trim (line.substr (line.indexOf (":") + 1));
|
||||||
|
|
||||||
|
if (name != "") {
|
||||||
|
|
||||||
|
parent.responseHeaders.push (new HTTPRequestHeader (name, value));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.responseStatus = request.status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function __loadData (uri:String, promise:Promise<Bytes>):Void {
|
||||||
|
|
||||||
var progress = function (event) {
|
var progress = function (event) {
|
||||||
|
|
||||||
promise.progress (event.loaded, event.total);
|
promise.progress (event.loaded, event.total);
|
||||||
@@ -176,26 +292,49 @@ class HTML5HTTPRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binary = true;
|
binary = true;
|
||||||
|
|
||||||
if (activeRequests < requestLimit) {
|
|
||||||
|
|
||||||
activeRequests++;
|
|
||||||
load (uri, progress, readyStateChange);
|
load (uri, progress, readyStateChange);
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
requestQueue.add ({ instance: this, uri: uri, progress: progress, readyStateChange: readyStateChange });
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.future;
|
|
||||||
|
private static function __loadImage (uri:String, promise:Promise<Image>):Void {
|
||||||
|
|
||||||
|
var image = new JSImage ();
|
||||||
|
image.crossOrigin = "Anonymous";
|
||||||
|
|
||||||
|
image.addEventListener ("load", function (event) {
|
||||||
|
|
||||||
|
var buffer = new ImageBuffer (null, image.width, image.height);
|
||||||
|
buffer.__srcImage = cast image;
|
||||||
|
|
||||||
|
activeRequests--;
|
||||||
|
processQueue ();
|
||||||
|
|
||||||
|
promise.complete (new Image (buffer));
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
image.addEventListener ("progress", function (event) {
|
||||||
|
|
||||||
|
promise.progress (event.loaded, event.total);
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
image.addEventListener ("error", function (event) {
|
||||||
|
|
||||||
|
activeRequests--;
|
||||||
|
processQueue ();
|
||||||
|
|
||||||
|
promise.error (event.detail);
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
image.src = uri;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function loadText (uri:String):Future<String> {
|
private function __loadText (uri:String, promise:Promise<String>):Void {
|
||||||
|
|
||||||
var promise = new Promise<String> ();
|
|
||||||
|
|
||||||
var progress = function (event) {
|
var progress = function (event) {
|
||||||
|
|
||||||
@@ -227,72 +366,19 @@ class HTML5HTTPRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binary = false;
|
binary = false;
|
||||||
|
|
||||||
if (activeRequests < requestLimit) {
|
|
||||||
|
|
||||||
activeRequests++;
|
|
||||||
load (uri, progress, readyStateChange);
|
load (uri, progress, readyStateChange);
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
requestQueue.add ({ instance: this, uri: uri, progress: progress, readyStateChange: readyStateChange });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise.future;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function processQueue ():Void {
|
|
||||||
|
|
||||||
if (activeRequests < requestLimit && requestQueue.length > 0) {
|
|
||||||
|
|
||||||
activeRequests++;
|
|
||||||
|
|
||||||
var queueItem = requestQueue.pop ();
|
|
||||||
queueItem.instance.load (queueItem.uri, queueItem.progress, queueItem.readyStateChange);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function processResponse ():Void {
|
|
||||||
|
|
||||||
if (parent.enableResponseHeaders) {
|
|
||||||
|
|
||||||
parent.responseHeaders = [];
|
|
||||||
var name, value;
|
|
||||||
|
|
||||||
for (line in request.getAllResponseHeaders ().split ("\n")) {
|
|
||||||
|
|
||||||
name = StringTools.trim (line.substr (0, line.indexOf (":")));
|
|
||||||
value = StringTools.trim (line.substr (line.indexOf (":") + 1));
|
|
||||||
|
|
||||||
if (name != "") {
|
|
||||||
|
|
||||||
parent.responseHeaders.push (new HTTPRequestHeader (name, value));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.responseStatus = request.status;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@:dox(hide) private typedef QueueItem = {
|
@:dox(hide) typedef QueueItem = {
|
||||||
|
|
||||||
var instance:HTML5HTTPRequest;
|
var instance:HTML5HTTPRequest;
|
||||||
|
var type:AssetType;
|
||||||
|
var promise:Dynamic;
|
||||||
var uri:String;
|
var uri:String;
|
||||||
var progress:Dynamic;
|
|
||||||
var readyStateChange:Dynamic;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ import lime.utils.ArrayBuffer;
|
|||||||
import lime.utils.UInt8Array;
|
import lime.utils.UInt8Array;
|
||||||
|
|
||||||
#if (js && html5)
|
#if (js && html5)
|
||||||
|
import lime._backend.html5.HTML5HTTPRequest;
|
||||||
import js.html.CanvasElement;
|
import js.html.CanvasElement;
|
||||||
import js.html.ImageElement;
|
import js.html.ImageElement;
|
||||||
import js.html.Image in JSImage;
|
import js.html.Image in JSImage;
|
||||||
@@ -73,6 +74,10 @@ import lime.graphics.console.TextureData;
|
|||||||
@:access(lime.math.Rectangle)
|
@:access(lime.math.Rectangle)
|
||||||
@:access(lime.math.Vector2)
|
@:access(lime.math.Vector2)
|
||||||
|
|
||||||
|
#if (js && html5)
|
||||||
|
@:access(lime._backend.html5.HTML5HTTPRequest)
|
||||||
|
#end
|
||||||
|
|
||||||
|
|
||||||
class Image {
|
class Image {
|
||||||
|
|
||||||
@@ -744,42 +749,16 @@ class Image {
|
|||||||
|
|
||||||
if (base64 == null || type == null) return Future.withValue (null);
|
if (base64 == null || type == null) return Future.withValue (null);
|
||||||
|
|
||||||
var promise = new Promise<Image> ();
|
|
||||||
|
|
||||||
#if (js && html5)
|
#if (js && html5)
|
||||||
var image = new JSImage ();
|
|
||||||
|
|
||||||
image.addEventListener ("load", function (event) {
|
return HTML5HTTPRequest.loadImage ("data:" + type + ";base64," + base64);
|
||||||
|
|
||||||
var buffer = new ImageBuffer (null, image.width, image.height);
|
|
||||||
buffer.__srcImage = cast image;
|
|
||||||
|
|
||||||
promise.complete (new Image (buffer));
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.addEventListener ("progress", function (event) {
|
|
||||||
|
|
||||||
promise.progress (event.loaded, event.total);
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.addEventListener ("error", function (event) {
|
|
||||||
|
|
||||||
promise.error (event.detail);
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.src = "data:" + type + ";base64," + base64;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
promise.error ("");
|
return cast Future.withError ("");
|
||||||
|
|
||||||
#end
|
#end
|
||||||
|
|
||||||
return promise.future;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -854,35 +833,7 @@ class Image {
|
|||||||
|
|
||||||
#if (js && html5)
|
#if (js && html5)
|
||||||
|
|
||||||
var promise = new Promise<Image> ();
|
return HTML5HTTPRequest.loadImage (path);
|
||||||
|
|
||||||
var image = new JSImage ();
|
|
||||||
image.crossOrigin = "Anonymous";
|
|
||||||
|
|
||||||
image.addEventListener ("load", function (event) {
|
|
||||||
|
|
||||||
var buffer = new ImageBuffer (null, image.width, image.height);
|
|
||||||
buffer.__srcImage = cast image;
|
|
||||||
|
|
||||||
promise.complete (new Image (buffer));
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.addEventListener ("progress", function (event) {
|
|
||||||
|
|
||||||
promise.progress (event.loaded, event.total);
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.addEventListener ("error", function (event) {
|
|
||||||
|
|
||||||
promise.error (event.detail);
|
|
||||||
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
image.src = path;
|
|
||||||
|
|
||||||
return promise.future;
|
|
||||||
|
|
||||||
#elseif flash
|
#elseif flash
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user