merge m-c to fx-team

This commit is contained in:
Tim Taubert 2013-02-15 10:40:59 +01:00
commit 79504917e8
14 changed files with 241 additions and 14 deletions

View File

@ -6,6 +6,7 @@
const Cu = Components.utils; const Cu = Components.utils;
Cu.import("resource:///modules/devtools/gDevTools.jsm");
Cu.import("resource:///modules/devtools/ProfilerController.jsm"); Cu.import("resource:///modules/devtools/ProfilerController.jsm");
Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm"); Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm");
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
@ -14,10 +15,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
this.EXPORTED_SYMBOLS = ["ProfilerPanel"]; this.EXPORTED_SYMBOLS = ["ProfilerPanel"];
XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function () { XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
Cu.import("resource://gre/modules/devtools/dbg-server.jsm"); "resource://gre/modules/devtools/dbg-server.jsm");
return DebuggerServer;
}); XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
/** /**
* An instance of a profile UI. Profile UI consists of * An instance of a profile UI. Profile UI consists of
@ -105,6 +107,9 @@ function ProfileUI(uid, panel) {
break; break;
case "enabled": case "enabled":
this.emit("enabled"); this.emit("enabled");
break;
case "displaysource":
this.panel.displaySource(event.data.data);
} }
}.bind(this)); }.bind(this));
} }
@ -219,6 +224,7 @@ ProfilerPanel.prototype = {
_uid: null, _uid: null,
_activeUid: null, _activeUid: null,
_runningUid: null, _runningUid: null,
_browserWin: null,
get activeProfile() { get activeProfile() {
return this.profiles.get(this._activeUid); return this.profiles.get(this._activeUid);
@ -228,6 +234,21 @@ ProfilerPanel.prototype = {
this._activeUid = profile.uid; this._activeUid = profile.uid;
}, },
get browserWindow() {
if (this._browserWin) {
return this._browserWin;
}
let win = this.window.top;
let type = win.document.documentElement.getAttribute("windowtype");
if (type !== "navigator:browser") {
win = Services.wm.getMostRecentWindow("navigator:browser");
}
return this._browserWin = win;
},
/** /**
* Open a debug connection and, on success, switch to the newly created * Open a debug connection and, on success, switch to the newly created
* profile. * profile.
@ -416,6 +437,48 @@ ProfilerPanel.prototype = {
} }
}, },
/**
* Open file specified in data in either a debugger or view-source.
*
* @param object data
* An object describing the file. It must have three properties:
* - uri
* - line
* - isChrome (chrome files are opened via view-source)
*/
displaySource: function PP_displaySource(data, onOpen=function() {}) {
let win = this.window;
let panelWin, timeout;
function onSourceShown(event) {
if (event.detail.url !== data.uri) {
return;
}
panelWin.removeEventListener("Debugger:SourceShown", onSourceShown, false);
panelWin.editor.setCaretPosition(data.line - 1);
onOpen();
}
if (data.isChrome) {
return void this.browserWindow.gViewSourceUtils.
viewSource(data.uri, null, this.document, data.line);
}
gDevTools.showToolbox(this.target, "jsdebugger").then(function (toolbox) {
let dbg = toolbox.getCurrentPanel();
panelWin = dbg.panelWin;
let view = dbg.panelWin.DebuggerView;
if (view.Source && view.Sources.selectedValue === data.uri) {
return void view.editor.setCaretPosition(data.line - 1);
}
panelWin.addEventListener("Debugger:SourceShown", onSourceShown, false);
panelWin.DebuggerView.Sources.preferredSource = data.uri;
}.bind(this));
},
/** /**
* Cleanup. * Cleanup.
*/ */

View File

@ -15,15 +15,19 @@ var gInstanceUID;
* - stop, when user wants to stop profiling. * - stop, when user wants to stop profiling.
* - disabled, when the profiler was disabled * - disabled, when the profiler was disabled
* - enabled, when the profiler was enabled * - enabled, when the profiler was enabled
* - displaysource, when user wants to display source
* @param object data (optional)
* Additional data to send to the parent page.
*/ */
function notifyParent(status) { function notifyParent(status, data={}) {
if (!gInstanceUID) { if (!gInstanceUID) {
gInstanceUID = window.location.search.substr(1); gInstanceUID = window.location.search.substr(1);
} }
window.parent.postMessage({ window.parent.postMessage({
uid: gInstanceUID, uid: gInstanceUID,
status: status status: status,
data: data
}, "*"); }, "*");
} }
@ -197,7 +201,7 @@ function enterFinishedProfileUI() {
var currentBreadcrumb = gSampleFilters; var currentBreadcrumb = gSampleFilters;
gBreadcrumbTrail.add({ gBreadcrumbTrail.add({
title: "Complete Profile", title: gStrings["Complete Profile"],
enterCallback: function () { enterCallback: function () {
gSampleFilters = []; gSampleFilters = [];
filtersChanged(); filtersChanged();

View File

@ -466,7 +466,8 @@ TreeView.prototype = {
'<span class="resourceIcon" data-resource="' + node.library + '"></span> ' + '<span class="resourceIcon" data-resource="' + node.library + '"></span> ' +
'<span class="functionName">' + nodeName + '</span>' + '<span class="functionName">' + nodeName + '</span>' +
'<span class="libraryName">' + libName + '</span>' + '<span class="libraryName">' + libName + '</span>' +
'<input type="button" value="Focus Callstack" title="Focus Callstack" class="focusCallstackButton" tabindex="-1">'; (nodeName === '(total)' ? '' :
'<input type="button" value="Focus Callstack" title="Focus Callstack" class="focusCallstackButton" tabindex="-1">');
}, },
_resolveChildren: function TreeView__resolveChildren(div, childrenCollapsedValue) { _resolveChildren: function TreeView__resolveChildren(div, childrenCollapsedValue) {
while (div.pendingExpand != null && div.pendingExpand.length > 0) { while (div.pendingExpand != null && div.pendingExpand.length > 0) {

View File

@ -169,8 +169,12 @@ function ProfileTreeManager() {
self._onContextMenuClick(e); self._onContextMenuClick(e);
}); });
this.treeView.addEventListener("focusCallstackButtonClicked", function (frameData) { this.treeView.addEventListener("focusCallstackButtonClicked", function (frameData) {
var focusedCallstack = self._getCallstackUpTo(frameData); // NOTE: Not in the original Cleopatra source code.
focusOnCallstack(focusedCallstack, frameData.name); notifyParent("displaysource", {
line: frameData.scriptLocation.lineInformation,
uri: frameData.scriptLocation.scriptURI,
isChrome: /^otherhost_*/.test(frameData.library)
});
}); });
this._container = document.createElement("div"); this._container = document.createElement("div");
this._container.className = "tree"; this._container.className = "tree";
@ -1566,7 +1570,8 @@ function focusOnSymbol(focusSymbol, name) {
} }
function focusOnCallstack(focusedCallstack, name, overwriteCallstack) { function focusOnCallstack(focusedCallstack, name, overwriteCallstack) {
var invertCallback = gInvertCallstack; var invertCallstack = gInvertCallstack;
if (overwriteCallstack != null) { if (overwriteCallstack != null) {
invertCallstack = overwriteCallstack; invertCallstack = overwriteCallstack;
} }

View File

@ -10,12 +10,21 @@ relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk include $(DEPTH)/config/autoconf.mk
MOCHITEST_BROWSER_FILES = \ MOCHITEST_BROWSER_TESTS = \
browser_profiler_run.js \ browser_profiler_run.js \
browser_profiler_controller.js \ browser_profiler_controller.js \
browser_profiler_profiles.js \ browser_profiler_profiles.js \
browser_profiler_remote.js \ browser_profiler_remote.js \
browser_profiler_bug_830664_multiple_profiles.js \ browser_profiler_bug_830664_multiple_profiles.js \
browser_profiler_bug_834878_source_buttons.js \
head.js \ head.js \
$(NULL)
MOCHITEST_BROWSER_PAGES = \
mock_profiler_bug_834878_page.html \
mock_profiler_bug_834878_script.js \
$(NULL)
MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const BASE = "http://example.com/browser/browser/devtools/profiler/test/";
const URL = BASE + "mock_profiler_bug_834878_page.html";
const SCRIPT = BASE + "mock_profiler_bug_834878_script.js";
function test() {
waitForExplicitFinish();
setUp(URL, function onSetUp(tab, browser, panel) {
panel.once("profileCreated", function () {
let data = { uri: SCRIPT, line: 5, isChrome: false };
panel.displaySource(data, function onOpen() {
let target = TargetFactory.forTab(tab);
let dbg = gDevTools.getToolbox(target).getPanel("jsdebugger");
let view = dbg.panelWin.DebuggerView;
is(view.Sources.selectedValue, data.uri, "URI is different");
is(view.editor.getCaretPosition().line, data.line - 1, "Line is different");
tearDown(tab);
});
});
panel.createProfile();
});
}

View File

@ -0,0 +1,14 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'/>
<title>Profiler Script Linking Test</title>
<script type="text/javascript" src="mock_profiler_bug_834878_script.js">
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function main() {
console.log("Hello, World!");
return 0;
}

View File

@ -18,7 +18,7 @@ profiler.label=Profiler
# LOCALIZATION NOTE (profiler.commandkey, profiler.accesskey) # LOCALIZATION NOTE (profiler.commandkey, profiler.accesskey)
# Used for the menuitem in the tool menu # Used for the menuitem in the tool menu
profiler.commandkey=Y profiler.commandkey=Y
profiler.accesskey=Y profiler.accesskey=P
# LOCALIZATION NOTE (profiler.tooltip): # LOCALIZATION NOTE (profiler.tooltip):
# This string is displayed in the tooltip of the tab when the profiler is # This string is displayed in the tooltip of the tab when the profiler is

View File

@ -1439,6 +1439,37 @@ nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aSc
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollbarWidth(bool aFlushLayout, int32_t* aResult)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
*aResult = 0;
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
NS_ENSURE_STATE(doc);
if (aFlushLayout) {
doc->FlushPendingNotifications(Flush_Layout);
}
nsIPresShell* presShell = doc->GetShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE);
nsIScrollableFrame* scrollFrame = presShell->GetRootScrollFrameAsScrollable();
NS_ENSURE_TRUE(scrollFrame, NS_OK);
nsMargin sizes = scrollFrame->GetActualScrollbarSizes();
*aResult = nsPresContext::AppUnitsToIntCSSPixels(sizes.LeftRight());
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult) nsDOMWindowUtils::GetRootBounds(nsIDOMClientRect** aResult)
{ {

View File

@ -41,7 +41,7 @@ interface nsIDOMClientRect;
interface nsIURI; interface nsIURI;
interface nsIDOMEventTarget; interface nsIDOMEventTarget;
[scriptable, uuid(020deb5a-cba6-41dd-8551-72a880d01970)] [scriptable, uuid(16b3bdcc-75d4-11e2-8a20-aaff78957a39)]
interface nsIDOMWindowUtils : nsISupports { interface nsIDOMWindowUtils : nsISupports {
/** /**
@ -647,6 +647,13 @@ interface nsIDOMWindowUtils : nsISupports {
*/ */
void getScrollXY(in boolean aFlushLayout, out long aScrollX, out long aScrollY); void getScrollXY(in boolean aFlushLayout, out long aScrollX, out long aScrollY);
/**
* Returns the scrollbar width of the window's scroll frame.
*
* @param aFlushLayout flushes layout if true. Otherwise, no flush occurs.
*/
long getScrollbarWidth(in boolean aFlushLayout);
/** /**
* Returns the bounds of the window's currently loaded document. This will * Returns the bounds of the window's currently loaded document. This will
* generally be (0, 0, pageWidth, pageHeight) but in some cases (e.g. RTL * generally be (0, 0, pageWidth, pageHeight) but in some cases (e.g. RTL

View File

@ -29,6 +29,8 @@ MOCHITEST_FILES = \
test_consoleAPI.html \ test_consoleAPI.html \
test_domWindowUtils.html \ test_domWindowUtils.html \
test_domWindowUtils_scrollXY.html \ test_domWindowUtils_scrollXY.html \
test_domWindowUtils_scrollbarWidth.html \
file_domWindowUtils_scrollbarWidth.html \
test_offsets.html \ test_offsets.html \
test_offsets.js \ test_offsets.js \
test_windowProperties.html \ test_windowProperties.html \

View File

@ -0,0 +1,7 @@
<!DOCTYPE HTML>
<html>
<body style='width: 100000px; overflow: hidden;'></body>
<div id="float" style="float: left; overflow: scroll;">
<div style="width: 200px;"></div>
</div>
</html>

View File

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<title>nsIDOMWindowUtils::getScrollbarWidth test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body id="body">
<script type="application/javascript;version=1.8">
function doTests() {
let iframe = document.getElementById("iframe");
let cwindow = iframe.contentWindow;
let utils = SpecialPowers.getDOMWindowUtils(cwindow);
let doc = cwindow.document;
function haveNonFloatingScrollbars() {
return doc.getElementById("float").offsetWidth > 200;
}
is(utils.getScrollbarWidth(true), 0,
"getScrollbarWidth returns zero without a scrollbar");
// Some platforms (esp. mobile) may have floating scrollbars that don't
// affect layout. Thus getScrollbarWidth() would always return 0.
if (haveNonFloatingScrollbars()) {
let body = doc.querySelector("body");
body.style.overflowY = "scroll";
is(utils.getScrollbarWidth(false), 0,
"getScrollbarWidth returns zero with a vertical scrollbar w/o flushing");
ok(utils.getScrollbarWidth(true) > 0,
"getScrollbarWidth returns non-zero with a vertical scrollbar with flushing");
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
<iframe src="http://mochi.test:8888/tests/dom/tests/mochitest/general/file_domWindowUtils_scrollbarWidth.html"
id="iframe" onload="doTests();">
</iframe>
</body>
</html>