michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: var gBrowser; michael@0: var gProgressListener; michael@0: var gDebugger; michael@0: var gRTestIndexList; michael@0: var gRTestURLList = null; michael@0: michael@0: const nsILayoutDebuggingTools = Components.interfaces.nsILayoutDebuggingTools; michael@0: const nsIDocShell = Components.interfaces.nsIDocShell; michael@0: const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; michael@0: michael@0: const NS_LAYOUT_DEBUGGINGTOOLS_CONTRACTID = "@mozilla.org/layout-debug/layout-debuggingtools;1"; michael@0: michael@0: michael@0: function nsLDBBrowserContentListener() michael@0: { michael@0: this.init(); michael@0: } michael@0: michael@0: nsLDBBrowserContentListener.prototype = { michael@0: michael@0: init : function() michael@0: { michael@0: this.mStatusText = document.getElementById("status-text"); michael@0: this.mURLBar = document.getElementById("urlbar"); michael@0: this.mForwardButton = document.getElementById("forward-button"); michael@0: this.mBackButton = document.getElementById("back-button"); michael@0: this.mStopButton = document.getElementById("stop-button"); michael@0: }, michael@0: michael@0: QueryInterface : function(aIID) michael@0: { michael@0: if (aIID.equals(Components.interfaces.nsIWebProgressListener) || michael@0: aIID.equals(Components.interfaces.nsISupportsWeakReference) || michael@0: aIID.equals(Components.interfaces.nsISupports)) michael@0: return this; michael@0: throw Components.results.NS_NOINTERFACE; michael@0: }, michael@0: michael@0: // nsIWebProgressListener implementation michael@0: onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) michael@0: { michael@0: if (!(aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) || michael@0: aWebProgress != gBrowser.webProgress) michael@0: return; michael@0: michael@0: if (aStateFlags & nsIWebProgressListener.STATE_START) { michael@0: this.setButtonEnabled(this.mStopButton, true); michael@0: this.setButtonEnabled(this.mForwardButton, gBrowser.canGoForward); michael@0: this.setButtonEnabled(this.mBackButton, gBrowser.canGoBack); michael@0: this.mStatusText.value = "loading..."; michael@0: this.mLoading = true; michael@0: michael@0: } else if (aStateFlags & nsIWebProgressListener.STATE_STOP) { michael@0: this.setButtonEnabled(this.mStopButton, false); michael@0: this.mStatusText.value = this.mURLBar.value + " loaded"; michael@0: michael@0: if (gRTestURLList && this.mLoading) { michael@0: // Let other things happen in the first 20ms, since this michael@0: // doesn't really seem to be when the page is done loading. michael@0: setTimeout("gRTestURLList.doneURL()", 20); michael@0: } michael@0: this.mLoading = false; michael@0: } michael@0: }, michael@0: michael@0: onProgressChange : function(aWebProgress, aRequest, michael@0: aCurSelfProgress, aMaxSelfProgress, michael@0: aCurTotalProgress, aMaxTotalProgress) michael@0: { michael@0: }, michael@0: michael@0: onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) michael@0: { michael@0: this.mURLBar.value = aLocation.spec; michael@0: this.setButtonEnabled(this.mForwardButton, gBrowser.canGoForward); michael@0: this.setButtonEnabled(this.mBackButton, gBrowser.canGoBack); michael@0: }, michael@0: michael@0: onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) michael@0: { michael@0: this.mStatusText.value = aMessage; michael@0: }, michael@0: michael@0: onSecurityChange : function(aWebProgress, aRequest, aState) michael@0: { michael@0: }, michael@0: michael@0: // non-interface methods michael@0: setButtonEnabled : function(aButtonElement, aEnabled) michael@0: { michael@0: if (aEnabled) michael@0: aButtonElement.removeAttribute("disabled"); michael@0: else michael@0: aButtonElement.setAttribute("disabled", "true"); michael@0: }, michael@0: michael@0: mStatusText : null, michael@0: mURLBar : null, michael@0: mForwardButton : null, michael@0: mBackButton : null, michael@0: mStopButton : null, michael@0: michael@0: mLoading : false michael@0: michael@0: } michael@0: michael@0: function OnLDBLoad() michael@0: { michael@0: gBrowser = document.getElementById("browser"); michael@0: michael@0: gProgressListener = new nsLDBBrowserContentListener(); michael@0: gBrowser.addProgressListener(gProgressListener); michael@0: michael@0: gDebugger = Components.classes[NS_LAYOUT_DEBUGGINGTOOLS_CONTRACTID]. michael@0: createInstance(nsILayoutDebuggingTools); michael@0: michael@0: if (window.arguments && window.arguments[0]) michael@0: gBrowser.loadURI(window.arguments[0]); michael@0: else michael@0: gBrowser.goHome(); michael@0: michael@0: gDebugger.init(gBrowser.contentWindow); michael@0: michael@0: checkPersistentMenus(); michael@0: gRTestIndexList = new RTestIndexList(); michael@0: } michael@0: michael@0: function checkPersistentMenu(item) michael@0: { michael@0: var menuitem = document.getElementById("menu_" + item); michael@0: menuitem.setAttribute("checked", gDebugger[item]); michael@0: } michael@0: michael@0: function checkPersistentMenus() michael@0: { michael@0: // Restore the toggles that are stored in prefs. michael@0: checkPersistentMenu("paintFlashing"); michael@0: checkPersistentMenu("paintDumping"); michael@0: checkPersistentMenu("invalidateDumping"); michael@0: checkPersistentMenu("eventDumping"); michael@0: checkPersistentMenu("motionEventDumping"); michael@0: checkPersistentMenu("crossingEventDumping"); michael@0: checkPersistentMenu("reflowCounts"); michael@0: } michael@0: michael@0: michael@0: function OnLDBUnload() michael@0: { michael@0: gBrowser.removeProgressListener(gProgressListener); michael@0: } michael@0: michael@0: function toggle(menuitem) michael@0: { michael@0: // trim the initial "menu_" michael@0: var feature = menuitem.id.substring(5); michael@0: gDebugger[feature] = menuitem.getAttribute("checked") == "true"; michael@0: } michael@0: michael@0: function openFile() michael@0: { michael@0: var nsIFilePicker = Components.interfaces.nsIFilePicker; michael@0: var fp = Components.classes["@mozilla.org/filepicker;1"] michael@0: .createInstance(nsIFilePicker); michael@0: fp.init(window, "Select a File", nsIFilePicker.modeOpen); michael@0: fp.appendFilters(nsIFilePicker.filterHTML | nsIFilePicker.filterAll); michael@0: if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec && michael@0: fp.fileURL.spec.length > 0) { michael@0: gBrowser.loadURI(fp.fileURL.spec); michael@0: } michael@0: } michael@0: const LDB_RDFNS = "http://mozilla.org/newlayout/LDB-rdf#"; michael@0: const NC_RDFNS = "http://home.netscape.com/NC-rdf#"; michael@0: michael@0: function RTestIndexList() { michael@0: this.init(); michael@0: } michael@0: michael@0: RTestIndexList.prototype = { michael@0: michael@0: init : function() michael@0: { michael@0: const nsIPrefService = Components.interfaces.nsIPrefService; michael@0: const PREF_SERVICE_CONTRACTID = "@mozilla.org/preferences-service;1"; michael@0: const PREF_BRANCH_NAME = "layout_debugger.rtest_url."; michael@0: const nsIRDFService = Components.interfaces.nsIRDFService; michael@0: const RDF_SERVICE_CONTRACTID = "@mozilla.org/rdf/rdf-service;1"; michael@0: const nsIRDFDataSource = Components.interfaces.nsIRDFDataSource; michael@0: const RDF_DATASOURCE_CONTRACTID = michael@0: "@mozilla.org/rdf/datasource;1?name=in-memory-datasource"; michael@0: michael@0: this.mPrefService = Components.classes[PREF_SERVICE_CONTRACTID]. michael@0: getService(nsIPrefService); michael@0: this.mPrefBranch = this.mPrefService.getBranch(PREF_BRANCH_NAME); michael@0: michael@0: this.mRDFService = Components.classes[RDF_SERVICE_CONTRACTID]. michael@0: getService(nsIRDFService); michael@0: this.mDataSource = Components.classes[RDF_DATASOURCE_CONTRACTID]. michael@0: createInstance(nsIRDFDataSource); michael@0: michael@0: this.mLDB_Root = this.mRDFService.GetResource(LDB_RDFNS + "Root"); michael@0: this.mNC_Name = this.mRDFService.GetResource(NC_RDFNS + "name"); michael@0: this.mNC_Child = this.mRDFService.GetResource(NC_RDFNS + "child"); michael@0: michael@0: this.load(); michael@0: michael@0: document.getElementById("menu_RTest_baseline").database. michael@0: AddDataSource(this.mDataSource); michael@0: document.getElementById("menu_RTest_verify").database. michael@0: AddDataSource(this.mDataSource); michael@0: document.getElementById("menu_RTest_remove").database. michael@0: AddDataSource(this.mDataSource); michael@0: }, michael@0: michael@0: save : function() michael@0: { michael@0: this.mPrefBranch.deleteBranch(""); michael@0: michael@0: const nsIRDFLiteral = Components.interfaces.nsIRDFLiteral; michael@0: const nsIRDFResource = Components.interfaces.nsIRDFResource; michael@0: var etor = this.mDataSource.GetTargets(this.mLDB_Root, michael@0: this.mNC_Child, true); michael@0: var i = 0; michael@0: while (etor.hasMoreElements()) { michael@0: var resource = etor.getNext().QueryInterface(nsIRDFResource); michael@0: var literal = this.mDataSource.GetTarget(resource, this.mNC_Name, true); michael@0: literal = literal.QueryInterface(nsIRDFLiteral); michael@0: this.mPrefBranch.setCharPref(i.toString(), literal.Value); michael@0: ++i; michael@0: } michael@0: michael@0: this.mPrefService.savePrefFile(null); michael@0: }, michael@0: michael@0: load : function() michael@0: { michael@0: var prefList = this.mPrefBranch.getChildList(""); michael@0: michael@0: var i = 0; michael@0: for (var pref in prefList) { michael@0: var file = this.mPrefBranch.getCharPref(pref); michael@0: var resource = this.mRDFService.GetResource(file); michael@0: var literal = this.mRDFService.GetLiteral(file); michael@0: this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true); michael@0: this.mDataSource.Assert(resource, this.mNC_Name, literal, true); michael@0: ++i; michael@0: } michael@0: michael@0: }, michael@0: michael@0: /* Add a new list of regression tests to the menus. */ michael@0: add : function() michael@0: { michael@0: const nsIFilePicker = Components.interfaces.nsIFilePicker; michael@0: const NS_FILEPICKER_CONTRACTID = "@mozilla.org/filepicker;1"; michael@0: michael@0: var fp = Components.classes[NS_FILEPICKER_CONTRACTID]. michael@0: createInstance(nsIFilePicker); michael@0: michael@0: // XXX l10n (but this is just for 5 developers, so no problem) michael@0: fp.init(window, "New Regression Test List", nsIFilePicker.modeOpen); michael@0: fp.appendFilters(nsIFilePicker.filterAll); michael@0: fp.defaultString = "rtest.lst"; michael@0: if (fp.show() != nsIFilePicker.returnOK) michael@0: return; michael@0: michael@0: var file = fp.file.persistentDescriptor; michael@0: var resource = this.mRDFService.GetResource(file); michael@0: var literal = this.mRDFService.GetLiteral(file); michael@0: this.mDataSource.Assert(this.mLDB_Root, this.mNC_Child, resource, true); michael@0: this.mDataSource.Assert(resource, this.mNC_Name, literal, true); michael@0: michael@0: this.save(); michael@0: michael@0: }, michael@0: michael@0: remove : function(file) michael@0: { michael@0: var resource = this.mRDFService.GetResource(file); michael@0: var literal = this.mRDFService.GetLiteral(file); michael@0: this.mDataSource.Unassert(this.mLDB_Root, this.mNC_Child, resource); michael@0: this.mDataSource.Unassert(resource, this.mNC_Name, literal); michael@0: michael@0: this.save(); michael@0: }, michael@0: michael@0: mPrefBranch : null, michael@0: mPrefService : null, michael@0: mRDFService : null, michael@0: mDataSource : null, michael@0: mLDB_Root : null, michael@0: mNC_Child : null, michael@0: mNC_Name : null michael@0: } michael@0: michael@0: const nsIFileInputStream = Components.interfaces.nsIFileInputStream; michael@0: const nsILineInputStream = Components.interfaces.nsILineInputStream; michael@0: const nsIFile = Components.interfaces.nsIFile; michael@0: const nsILocalFile = Components.interfaces.nsILocalFile; michael@0: const nsIFileURL = Components.interfaces.nsIFileURL; michael@0: const nsIIOService = Components.interfaces.nsIIOService; michael@0: const nsILayoutRegressionTester = Components.interfaces.nsILayoutRegressionTester; michael@0: michael@0: const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1"; michael@0: const IO_SERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; michael@0: const NS_LOCALFILEINPUTSTREAM_CONTRACTID = michael@0: "@mozilla.org/network/file-input-stream;1"; michael@0: michael@0: michael@0: function RunRTest(aFilename, aIsBaseline, aIsPrinting) michael@0: { michael@0: if (gRTestURLList) { michael@0: // XXX Does alert work? michael@0: alert("Already running regression test.\n"); michael@0: return; michael@0: } michael@0: dump("Running " + (aIsBaseline?"baseline":"verify") + michael@0: (aIsPrinting?" PrintMode":"") + " test for " + aFilename + ".\n"); michael@0: michael@0: var listFile = Components.classes[NS_LOCAL_FILE_CONTRACTID]. michael@0: createInstance(nsILocalFile); michael@0: listFile.persistentDescriptor = aFilename; michael@0: gRTestURLList = new RTestURLList(listFile, aIsBaseline, aIsPrinting); michael@0: gRTestURLList.startURL(); michael@0: } michael@0: michael@0: function RTestURLList(aLocalFile, aIsBaseline, aIsPrinting) { michael@0: this.init(aLocalFile, aIsBaseline, aIsPrinting); michael@0: } michael@0: michael@0: RTestURLList.prototype = { michael@0: init : function(aLocalFile, aIsBaseline, aIsPrinting) michael@0: { michael@0: this.mIsBaseline = aIsBaseline; michael@0: this.mIsPrinting = aIsPrinting; michael@0: this.mURLs = new Array(); michael@0: this.readFileList(aLocalFile); michael@0: this.mRegressionTester = michael@0: Components.classes["@mozilla.org/layout-debug/regressiontester;1"]. michael@0: createInstance(nsILayoutRegressionTester) michael@0: }, michael@0: michael@0: readFileList : function(aLocalFile) michael@0: { michael@0: var ios = Components.classes[IO_SERVICE_CONTRACTID] michael@0: .getService(nsIIOService); michael@0: var dirURL = ios.newFileURI(aLocalFile.parent); michael@0: michael@0: var fis = Components.classes[NS_LOCALFILEINPUTSTREAM_CONTRACTID]. michael@0: createInstance(nsIFileInputStream); michael@0: fis.init(aLocalFile, -1, -1, false); michael@0: var lis = fis.QueryInterface(nsILineInputStream); michael@0: michael@0: var line = {value:null}; michael@0: do { michael@0: var more = lis.readLine(line); michael@0: var str = line.value; michael@0: str = /^[^#]*/.exec(str); // strip everything after "#" michael@0: str = /\S*/.exec(str); // take the first chunk of non-whitespace michael@0: if (!str || str == "") michael@0: continue; michael@0: michael@0: var item = dirURL.resolve(str); michael@0: if (item.match(/\/rtest.lst$/)) { michael@0: var itemurl = ios.newURI(item, null, null); michael@0: itemurl = itemurl.QueryInterface(nsIFileURL); michael@0: this.readFileList(itemurl.file); michael@0: } else { michael@0: this.mURLs.push( {url:item, dir:aLocalFile.parent, relurl:str} ); michael@0: } michael@0: } while (more); michael@0: }, michael@0: michael@0: doneURL : function() michael@0: { michael@0: var basename = michael@0: String(this.mCurrentURL.relurl).replace(/[:=&.\/?]/g, "_") + ".rgd"; michael@0: michael@0: var data = this.mCurrentURL.dir.clone(); michael@0: data.append( this.mIsBaseline ? "baseline" : "verify"); michael@0: if (!data.exists()) michael@0: data.create(nsIFile.DIRECTORY_TYPE, 0777) michael@0: data.append(basename); michael@0: michael@0: dump("Writing regression data to " + michael@0: data.QueryInterface(nsILocalFile).persistentDescriptor + "\n"); michael@0: if (this.mIsPrinting) { michael@0: this.mRegressionTester.dumpFrameModel(gBrowser.contentWindow, data, michael@0: nsILayoutRegressionTester.DUMP_FLAGS_MASK_PRINT_MODE); michael@0: } michael@0: else { michael@0: this.mRegressionTester.dumpFrameModel(gBrowser.contentWindow, data, 0); michael@0: } michael@0: michael@0: michael@0: michael@0: if (!this.mIsBaseline) { michael@0: var base_data = this.mCurrentURL.dir.clone(); michael@0: base_data.append("baseline"); michael@0: base_data.append(basename); michael@0: dump("Comparing to regression data from " + michael@0: base_data.QueryInterface(nsILocalFile).persistentDescriptor + "\n"); michael@0: var filesDiffer = michael@0: this.mRegressionTester.compareFrameModels(base_data, data, michael@0: nsILayoutRegressionTester.COMPARE_FLAGS_BRIEF) michael@0: dump("Comparison for " + this.mCurrentURL.url + " " + michael@0: (filesDiffer ? "failed" : "passed") + ".\n"); michael@0: } michael@0: michael@0: this.mCurrentURL = null; michael@0: michael@0: this.startURL(); michael@0: }, michael@0: michael@0: startURL : function() michael@0: { michael@0: this.mCurrentURL = this.mURLs.shift(); michael@0: if (!this.mCurrentURL) { michael@0: gRTestURLList = null; michael@0: return; michael@0: } michael@0: michael@0: gBrowser.loadURI(this.mCurrentURL.url); michael@0: }, michael@0: michael@0: mURLs : null, michael@0: mCurrentURL : null, // url (string), dir (nsIFileURL), relurl (string) michael@0: mIsBaseline : null, michael@0: mRegressionTester : null, michael@0: mIsPrinting : null michael@0: }