blob: 4e9629b082408c1193bcd7d21225fdcd96fb6a2b [file] [log] [blame]
/*
* weinre is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2011 IBM Corporation
*/
requireClass ../common/Ex
requireClass ../common/Weinre
requireClass ../common/IDGenerator
requireClass ../common/StackTrace
requireClass ../common/Native
//-----------------------------------------------------------------------------
class Timeline
//-----------------------------------------------------------------------------
static method start
Running = true
//-----------------------------------------------------------------------------
static method stop
Running = false
//-----------------------------------------------------------------------------
static method isRunning
return Running
//-----------------------------------------------------------------------------
static method addRecord_Mark(message)
if (!Timeline.isRunning()) return
var record = {}
record.type = TimelineRecordType.Mark
record.category = { name: "scripting" }
record.startTime = Date.now()
record.data = { message: message }
addStackTrace(record, 3)
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method addRecord_EventDispatch(event, name, category)
if (!Timeline.isRunning()) return
if (!category) category = "scripting"
var record = {}
record.type = TimelineRecordType.EventDispatch
record.category = { name: category }
record.startTime = Date.now()
record.data = { type: event.type }
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method addRecord_TimerInstall(id, timeout, singleShot)
if (!Timeline.isRunning()) return
var record = {}
record.type = TimelineRecordType.TimerInstall
record.category = { name: "scripting" }
record.startTime = Date.now()
record.data = { timerId: id, timeout: timeout, singleShot: singleShot }
addStackTrace(record, 4)
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method addRecord_TimerRemove(id, timeout, singleShot)
if (!Timeline.isRunning()) return
var record = {}
record.type = TimelineRecordType.TimerRemove
record.category = { name: "scripting" }
record.startTime = Date.now()
record.data = { timerId: id, timeout: timeout, singleShot: singleShot }
addStackTrace(record, 4)
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method addRecord_TimerFire(id, timeout, singleShot)
if (!Timeline.isRunning()) return
var record = {}
record.type = TimelineRecordType.TimerFire
record.category = { name: "scripting" }
record.startTime = Date.now()
record.data = { timerId: id, timeout: timeout, singleShot: singleShot }
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method addRecord_XHRReadyStateChange(method, url, id, xhr)
if (!Timeline.isRunning()) return
var record
if (xhr.readyState == XMLHttpRequest.OPENED) {
record = {
type: TimelineRecordType.ResourceSendRequest,
category: { name: "loading" },
startTime: Date.now(),
data: {
identifier: id,
url: url,
requestMethod: method
}
}
}
else if (xhr.readyState == XMLHttpRequest.DONE) {
record = {
type: TimelineRecordType.ResourceReceiveResponse,
category: { name: "loading" },
startTime: Date.now(),
data: {
identifier: id,
statusCode: xhr.status,
mimeType: xhr.getResponseHeader("Content-Type"),
expectedContentLength: xhr.getResponseHeader("Content-Length"),
url: url
}
}
}
else
return
Weinre.wi.TimelineNotify.addRecordToTimeline(record)
//-----------------------------------------------------------------------------
static method installGlobalListeners
if (applicationCache) {
applicationCache.addEventListener("checking", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.checking", "loading")}, false)
applicationCache.addEventListener("error", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.error", "loading")}, false)
applicationCache.addEventListener("noupdate", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.noupdate", "loading")}, false)
applicationCache.addEventListener("downloading", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.downloading", "loading")}, false)
applicationCache.addEventListener("progress", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.progress", "loading")}, false)
applicationCache.addEventListener("updateready", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.updateready", "loading")}, false)
applicationCache.addEventListener("cached", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.cached", "loading")}, false)
applicationCache.addEventListener("obsolete", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.obsolete", "loading")}, false)
}
// window.addEventListener("deviceorientation", function(e) {Timeline.addRecord_EventDispatch("window.deviceorientation")}, false)
window.addEventListener("error", function(e) {Timeline.addRecord_EventDispatch(e, "window.error")}, false)
window.addEventListener("hashchange", function(e) {Timeline.addRecord_EventDispatch(e, "window.hashchange")}, false)
window.addEventListener("message", function(e) {Timeline.addRecord_EventDispatch(e, "window.message")}, false)
window.addEventListener("offline", function(e) {Timeline.addRecord_EventDispatch(e, "window.offline")}, false)
window.addEventListener("online", function(e) {Timeline.addRecord_EventDispatch(e, "window.online")}, false)
window.addEventListener("scroll", function(e) {Timeline.addRecord_EventDispatch(e, "window.scroll")}, false)
//-----------------------------------------------------------------------------
static method installFunctionWrappers
window.clearInterval = wrapped_clearInterval
window.clearTimeout = wrapped_clearTimeout
window.setTimeout = wrapped_setTimeout
window.setInterval = wrapped_setInterval
window.XMLHttpRequest.prototype.open = wrapped_XMLHttpRequest_open
window.XMLHttpRequest = wrapped_XMLHttpRequest
//-----------------------------------------------------------------------------
function addStackTrace(record, skip)
if (!skip) skip = 1
var trace = new StackTrace(arguments).trace
record.stackTrace = []
for (var i=skip; i<trace.length; i++) {
record.stackTrace.push({
functionName: trace[i],
scriptName: "",
lineNumber: ""
})
}
//-----------------------------------------------------------------------------
function wrapped_setInterval(code, interval)
var code = instrumentedTimerCode(code, interval, false)
var id = Native.setInterval(code, interval)
code.__timerId = id
addTimer(id, interval, false)
return id
//-----------------------------------------------------------------------------
function wrapped_setTimeout(code, delay)
var code = instrumentedTimerCode(code, delay, true)
var id = Native.setTimeout(code, delay)
code.__timerId = id
addTimer(id, delay, true)
return id
//-----------------------------------------------------------------------------
function wrapped_clearInterval(id)
var result = Native.clearInterval(id)
removeTimer(id, false)
return result
//-----------------------------------------------------------------------------
function wrapped_clearTimeout(id)
var result = Native.clearTimeout(id)
removeTimer(id, true)
return result
//-----------------------------------------------------------------------------
function addTimer(id, timeout, singleShot)
var timerSet = singleShot ? TimerTimeouts : TimerIntervals
timerSet[id] = {
id: id,
timeout: timeout,
singleShot: singleShot
}
Timeline.addRecord_TimerInstall(id, timeout, singleShot)
//-----------------------------------------------------------------------------
function removeTimer(id, singleShot)
var timerSet = singleShot ? TimerTimeouts : TimerIntervals
var timer = timerSet[id]
if (!timer) return
Timeline.addRecord_TimerRemove(id, timer.timeout, singleShot)
delete timerSet[id]
//-----------------------------------------------------------------------------
function instrumentedTimerCode(code, timeout, singleShot)
if (typeof(code) != "function") return code
var instrumentedCode = function() {
var result = code()
var id = arguments.callee.__timerId
Timeline.addRecord_TimerFire(id, timeout, singleShot)
return result
}
return instrumentedCode
//-----------------------------------------------------------------------------
function wrapped_XMLHttpRequest
var xhr = new Native.XMLHttpRequest()
IDGenerator.getId(xhr)
xhr.addEventListener("readystatechange", getXhrEventHandler(xhr), false)
return xhr
init
wrapped_XMLHttpRequest.UNSENT = 0
wrapped_XMLHttpRequest.OPENED = 1
wrapped_XMLHttpRequest.HEADERS_RECEIVED = 2
wrapped_XMLHttpRequest.LOADING = 3
wrapped_XMLHttpRequest.DONE = 4
//-----------------------------------------------------------------------------
function wrapped_XMLHttpRequest_open()
var xhr = this
xhr.__weinre_method = arguments[0]
xhr.__weinre_url = arguments[1]
var result = Native.XMLHttpRequest_open.apply(xhr, [].slice.call(arguments))
return result
//-----------------------------------------------------------------------------
function getXhrEventHandler(xhr)
return function(event) {
Timeline.addRecord_XHRReadyStateChange(xhr.__weinre_method, xhr.__weinre_url, IDGenerator.getId(xhr), xhr)
}
//-----------------------------------------------------------------------------
init
var Running = false
var TimerTimeouts = {}
var TimerIntervals = {}
var TimelineRecordType = {
EventDispatch: 0,
Layout: 1,
RecalculateStyles: 2,
Paint: 3,
ParseHTML: 4,
TimerInstall: 5,
TimerRemove: 6,
TimerFire: 7,
XHRReadyStateChange: 8,
XHRLoad: 9,
EvaluateScript: 10,
Mark: 11,
ResourceSendRequest: 12,
ResourceReceiveResponse: 13,
ResourceFinish: 14,
FunctionCall: 15,
ReceiveResourceData: 16,
GCEvent: 17,
MarkDOMContent: 18,
MarkLoad: 19,
ScheduleResourceRequest: 20
}
Timeline.installGlobalListeners()
Timeline.installFunctionWrappers()