michael@0: /* michael@0: * Helper structures to track callbacks from image and channel loads. michael@0: */ michael@0: michael@0: // START_REQUEST and STOP_REQUEST are used by ChannelListener, and michael@0: // stored in ChannelListener.requestStatus. michael@0: const START_REQUEST = 0x01; michael@0: const STOP_REQUEST = 0x02; michael@0: const DATA_AVAILABLE = 0x04; michael@0: michael@0: // One bit per callback that imageListener below implements. Stored in michael@0: // ImageListener.state. michael@0: const SIZE_AVAILABLE = 0x01; michael@0: const FRAME_UPDATE = 0x02; michael@0: const FRAME_COMPLETE = 0x04; michael@0: const LOAD_COMPLETE = 0x08; michael@0: const DECODE_COMPLETE = 0x10; michael@0: michael@0: // An implementation of imgIScriptedNotificationObserver with the ability to michael@0: // call specified functions on onStartRequest and onStopRequest. michael@0: function ImageListener(start_callback, stop_callback) michael@0: { michael@0: this.sizeAvailable = function onSizeAvailable(aRequest) michael@0: { michael@0: do_check_false(this.synchronous); michael@0: michael@0: this.state |= SIZE_AVAILABLE; michael@0: michael@0: if (this.start_callback) michael@0: this.start_callback(this, aRequest); michael@0: } michael@0: this.frameComplete = function onFrameComplete(aRequest) michael@0: { michael@0: do_check_false(this.synchronous); michael@0: michael@0: this.state |= FRAME_COMPLETE; michael@0: } michael@0: this.decodeComplete = function onDecodeComplete(aRequest) michael@0: { michael@0: do_check_false(this.synchronous); michael@0: michael@0: this.state |= DECODE_COMPLETE; michael@0: } michael@0: this.loadComplete = function onLoadcomplete(aRequest) michael@0: { michael@0: do_check_false(this.synchronous); michael@0: michael@0: try { michael@0: aRequest.requestDecode(); michael@0: } catch (e) { michael@0: do_print("requestDecode threw " + e); michael@0: } michael@0: michael@0: this.state |= LOAD_COMPLETE; michael@0: michael@0: if (this.stop_callback) michael@0: this.stop_callback(this, aRequest); michael@0: } michael@0: this.frameUpdate = function onFrameUpdate(aRequest) michael@0: { michael@0: } michael@0: this.isAnimated = function onIsAnimated() michael@0: { michael@0: } michael@0: michael@0: // Initialize the synchronous flag to true to start. This must be set to michael@0: // false before exiting to the event loop! michael@0: this.synchronous = true; michael@0: michael@0: // A function to call when onStartRequest is called. michael@0: this.start_callback = start_callback; michael@0: michael@0: // A function to call when onStopRequest is called. michael@0: this.stop_callback = stop_callback; michael@0: michael@0: // The image load/decode state. michael@0: // A bitfield that tracks which callbacks have been called. Takes the bits michael@0: // defined above. michael@0: this.state = 0; michael@0: } michael@0: michael@0: function NS_FAILED(val) michael@0: { michael@0: return !!(val & 0x80000000); michael@0: } michael@0: michael@0: function ChannelListener() michael@0: { michael@0: this.onStartRequest = function onStartRequest(aRequest, aContext) michael@0: { michael@0: if (this.outputListener) michael@0: this.outputListener.onStartRequest(aRequest, aContext); michael@0: michael@0: this.requestStatus |= START_REQUEST; michael@0: } michael@0: michael@0: this.onDataAvailable = function onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount) michael@0: { michael@0: if (this.outputListener) michael@0: this.outputListener.onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount); michael@0: michael@0: this.requestStatus |= DATA_AVAILABLE; michael@0: } michael@0: michael@0: this.onStopRequest = function onStopRequest(aRequest, aContext, aStatusCode) michael@0: { michael@0: if (this.outputListener) michael@0: this.outputListener.onStopRequest(aRequest, aContext, aStatusCode); michael@0: michael@0: // If we failed (or were canceled - failure is implied if canceled), michael@0: // there's no use tracking our state, since it's meaningless. michael@0: if (NS_FAILED(aStatusCode)) michael@0: this.requestStatus = 0; michael@0: else michael@0: this.requestStatus |= STOP_REQUEST; michael@0: } michael@0: michael@0: // A listener to pass the notifications we get to. michael@0: this.outputListener = null; michael@0: michael@0: // The request's status. A bitfield that holds one or both of START_REQUEST michael@0: // and STOP_REQUEST, according to which callbacks have been called on the michael@0: // associated request. michael@0: this.requestStatus = 0; michael@0: }