Merge m-c to b-i.

This commit is contained in:
Ryan VanderMeulen 2013-12-06 16:12:01 -05:00
commit db4dc38b67
596 changed files with 104922 additions and 10704 deletions

1
aclocal.m4 vendored
View File

@ -30,6 +30,7 @@ builtin(include, build/autoconf/zlib.m4)dnl
builtin(include, build/autoconf/linux.m4)dnl
builtin(include, build/autoconf/python-virtualenv.m4)dnl
builtin(include, build/autoconf/winsdk.m4)dnl
builtin(include, build/autoconf/icu.m4)dnl
MOZ_PROG_CHECKMSYS()

View File

@ -605,12 +605,13 @@ int main(int argc, char* argv[])
#ifdef HAS_DLL_BLOCKLIST
DllBlocklist_Initialize();
#ifdef DEBUG
// In order to be effective against AppInit DLLs, the blocklist must be
// initialized before user32.dll is loaded into the process. If this assert
// ever fires, then the fix for bug 932100 has been defeated and the
// blocklist will miss AppInit DLLs. You should use a delayload or reorder
// the code to prevent user32.dll from loading during early startup.
MOZ_ASSERT(!GetModuleHandleA("user32.dll"));
// initialized before user32.dll is loaded into the process (bug 932100).
if (GetModuleHandleA("user32.dll")) {
fprintf(stderr, "DLL blocklist was unable to intercept AppInit DLLs.\n");
}
#endif
#endif
nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory);

View File

@ -574,11 +574,7 @@ pref("browser.gesture.twist.left", "cmd_gestureRotateLeft");
pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
pref("browser.gesture.tap", "cmd_fullZoomReset");
#ifndef RELEASE_BUILD
pref("browser.snapshots.limit", 5);
#else
pref("browser.snapshots.limit", 0);
#endif
// 0: Nothing happens
// 1: Scrolling contents

View File

@ -869,7 +869,7 @@ let PlacesToolbarHelper = {
return document.getElementById("PlacesToolbar");
},
init: function PTH_init() {
init: function PTH_init(forceToolbarOverflowCheck) {
let viewElt = this._viewElt;
if (!viewElt || viewElt._placesView)
return;
@ -886,6 +886,9 @@ let PlacesToolbarHelper = {
return;
new PlacesToolbar(this._place);
if (forceToolbarOverflowCheck) {
viewElt._placesView.updateOverflowStatus();
}
},
customizeStart: function PTH_customizeStart() {
@ -900,7 +903,7 @@ let PlacesToolbarHelper = {
customizeDone: function PTH_customizeDone() {
this._isCustomizing = false;
this.init();
this.init(true);
},
onPlaceholderCommand: function () {

View File

@ -1037,32 +1037,14 @@ PlacesToolbar.prototype = {
this.updateChevron();
break;
case "overflow":
if (aEvent.target != aEvent.currentTarget)
if (!this._isOverflowStateEventRelevant(aEvent))
return;
// Ignore purely vertical overflows.
if (aEvent.detail == 0)
return;
// Attach the popup binding to the chevron popup if it has not yet
// been initialized.
if (!this._chevronPopup.hasAttribute("type")) {
this._chevronPopup.setAttribute("place", this.place);
this._chevronPopup.setAttribute("type", "places");
}
this._chevron.collapsed = false;
this.updateChevron();
this._onOverflow();
break;
case "underflow":
if (aEvent.target != aEvent.currentTarget)
if (!this._isOverflowStateEventRelevant(aEvent))
return;
// Ignore purely vertical underflows.
if (aEvent.detail == 0)
return;
this.updateChevron();
this._chevron.collapsed = true;
this._onUnderflow();
break;
case "TabOpen":
case "TabClose":
@ -1103,6 +1085,35 @@ PlacesToolbar.prototype = {
}
},
updateOverflowStatus: function() {
if (this._rootElt.scrollLeftMax > 0) {
this._onOverflow();
} else {
this._onUnderflow();
}
},
_isOverflowStateEventRelevant: function PT_isOverflowStateEventRelevant(aEvent) {
// Ignore events not aimed at ourselves, as well as purely vertical ones:
return aEvent.target == aEvent.currentTarget && aEvent.detail > 0;
},
_onOverflow: function PT_onOverflow() {
// Attach the popup binding to the chevron popup if it has not yet
// been initialized.
if (!this._chevronPopup.hasAttribute("type")) {
this._chevronPopup.setAttribute("place", this.place);
this._chevronPopup.setAttribute("type", "places");
}
this._chevron.collapsed = false;
this.updateChevron();
},
_onUnderflow: function PT_onUnderflow() {
this.updateChevron();
this._chevron.collapsed = true;
},
updateChevron: function PT_updateChevron() {
// If the chevron is collapsed there's nothing to update.
if (this._chevron.collapsed)

View File

@ -1508,12 +1508,34 @@ let SessionStoreInternal = {
throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
},
/**
* Restores the given state |aState| for a given window |aWindow|.
*
* @param aWindow (xul window)
* The window that the given state will be restored to.
* @param aState (string)
* The state that will be applied to the given window.
* @param aOverwrite (bool)
* When true, existing tabs in the given window will be re-used or
* removed. When false, only new tabs will be added, no existing ones
8 will be removed or overwritten.
*/
setWindowState: function ssi_setWindowState(aWindow, aState, aOverwrite) {
if (!aWindow.__SSi) {
throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
}
this.restoreWindow(aWindow, aState, {overwriteTabs: aOverwrite});
let winState = JSON.parse(aState);
if (!winState) {
throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG);
}
if (!winState.windows || !winState.windows[0]) {
throw Components.Exception("Invalid window state passed", Cr.NS_ERROR_INVALID_ARG);
}
let state = {windows: [winState.windows[0]]};
this.restoreWindow(aWindow, state, {overwriteTabs: aOverwrite});
},
getTabState: function ssi_getTabState(aTab) {
@ -2280,7 +2302,7 @@ let SessionStoreInternal = {
* @param aWindow
* Window reference
* @param aState
* JS object or its eval'able source
* JS object
* @param aOptions
* {overwriteTabs: true} to overwrite existing tabs w/ new ones
* {isFollowUp: true} if this is not the restoration of the 1st window
@ -2300,17 +2322,10 @@ let SessionStoreInternal = {
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
this.onLoad(aWindow);
try {
var root = typeof aState == "string" ? JSON.parse(aState) : aState;
if (!root.windows[0]) {
this._sendRestoreCompletedNotifications();
return; // nothing to restore
}
}
catch (ex) { // invalid state object - don't restore anything
debug(ex);
var root = aState;
if (!root.windows[0]) {
this._sendRestoreCompletedNotifications();
return;
return; // nothing to restore
}
TelemetryStopwatch.start("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");

View File

@ -78,44 +78,38 @@ function test() {
}
}
// open a window and add the above closed window list
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) {
this.removeEventListener("load", arguments.callee, false);
gPrefService.setIntPref("browser.sessionstore.max_windows_undo",
test_state._closedWindows.length);
ss.setWindowState(newWin, JSON.stringify(test_state), true);
gPrefService.setIntPref("browser.sessionstore.max_windows_undo",
test_state._closedWindows.length);
ss.setBrowserState(JSON.stringify(test_state), true);
let closedWindows = JSON.parse(ss.getClosedWindowData());
is(closedWindows.length, test_state._closedWindows.length,
"Closed window list has the expected length");
is(countByTitle(closedWindows, FORGET),
test_state._closedWindows.length - remember_count,
"The correct amount of windows are to be forgotten");
is(countByTitle(closedWindows, REMEMBER), remember_count,
"Everything is set up.");
let closedWindows = JSON.parse(ss.getClosedWindowData());
is(closedWindows.length, test_state._closedWindows.length,
"Closed window list has the expected length");
is(countByTitle(closedWindows, FORGET),
test_state._closedWindows.length - remember_count,
"The correct amount of windows are to be forgotten");
is(countByTitle(closedWindows, REMEMBER), remember_count,
"Everything is set up.");
// all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
ok(testForError(function() ss.forgetClosedWindow(-1)),
"Invalid window for forgetClosedWindow throws");
ok(testForError(function() ss.forgetClosedWindow(test_state._closedWindows.length + 1)),
"Invalid window for forgetClosedWindow throws");
// all of the following calls with illegal arguments should throw NS_ERROR_ILLEGAL_VALUE
ok(testForError(function() ss.forgetClosedWindow(-1)),
"Invalid window for forgetClosedWindow throws");
ok(testForError(function() ss.forgetClosedWindow(test_state._closedWindows.length + 1)),
"Invalid window for forgetClosedWindow throws");
// Remove third window, then first window
ss.forgetClosedWindow(2);
ss.forgetClosedWindow(null);
// Remove third window, then first window
ss.forgetClosedWindow(2);
ss.forgetClosedWindow(null);
closedWindows = JSON.parse(ss.getClosedWindowData());
is(closedWindows.length, remember_count,
"The correct amount of windows were removed");
is(countByTitle(closedWindows, FORGET), 0,
"All windows specifically forgotten were indeed removed");
is(countByTitle(closedWindows, REMEMBER), remember_count,
"... and windows not specifically forgetten weren't.");
closedWindows = JSON.parse(ss.getClosedWindowData());
is(closedWindows.length, remember_count,
"The correct amount of windows were removed");
is(countByTitle(closedWindows, FORGET), 0,
"All windows specifically forgotten were indeed removed");
is(countByTitle(closedWindows, REMEMBER), remember_count,
"... and windows not specifically forgetten weren't.");
// clean up
newWin.close();
gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
finish();
}, false);
// clean up
gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
finish();
}

View File

@ -686,9 +686,9 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
// The container is not empty and an actual item was selected.
DebuggerView.setEditorLocation(sourceItem.value);
// Set window title.
let script = sourceItem.value.split(" -> ").pop();
document.title = L10N.getFormatStr("DebuggerWindowScriptTitle", script);
// Set window title. No need to split the url by " -> " here, because it was
// already sanitized when the source was added.
document.title = L10N.getFormatStr("DebuggerWindowScriptTitle", sourceItem.value);
DebuggerView.maybeShowBlackBoxMessage();
this.updateToolbarButtonsState();
@ -1085,38 +1085,14 @@ let SourceUtils = {
try {
// Use an nsIURL to parse all the url path parts.
var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
let url = aUrl.split(" -> ").pop();
var uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL);
} catch (e) {
// This doesn't look like a url, or nsIURL can't handle it.
return "";
}
let { scheme, directory, fileName } = uri;
let hostPort;
// Add-on SDK jar: URLs will cause accessing hostPort to throw.
if (scheme != "jar") {
hostPort = uri.hostPort;
}
let lastDir = directory.split("/").reverse()[1];
let group = [];
// Only show interesting schemes, http is implicit.
if (scheme != "http") {
group.push(scheme);
}
// Hostnames don't always exist for files or some resource urls.
// e.g. file://foo/bar.js or resource:///foo/bar.js don't have a host.
if (hostPort) {
// If the hostname is a dot-separated identifier, show the first 2 parts.
group.push(hostPort.split(".").slice(0, 2).join("."));
}
// Append the last directory if the path leads to an actual file.
// e.g. http://foo.org/bar/ should only show "foo.org", not "foo.org bar"
if (fileName) {
group.push(lastDir);
}
let groupLabel = group.join(" ");
let groupLabel = uri.prePath;
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
this._groupsCache.set(aUrl, unicodeLabel)
return unicodeLabel;

View File

@ -399,14 +399,6 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
initialize: function() {
dumpn("Initializing the StackFramesView");
let commandset = this._commandset = document.createElement("commandset");
let menupopup = this._menupopup = document.createElement("menupopup");
commandset.id = "stackframesCommandset";
menupopup.id = "stackframesMenupopup";
document.getElementById("debuggerPopupset").appendChild(menupopup);
document.getElementById("debuggerCommands").appendChild(commandset);
this.widget = new BreadcrumbsWidget(document.getElementById("stackframes"));
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("scroll", this._onScroll, true);
@ -414,6 +406,9 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
this.autoFocusOnFirstItem = false;
this.autoFocusOnSelection = false;
// This view's contents are also mirrored in a different container.
this._mirror = DebuggerView.StackFramesClassicList;
},
/**
@ -453,24 +448,22 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
this._prevBlackBoxedUrl = null;
}
// Create the element node and menu entry for the stack frame item.
// Create the element node for the stack frame item.
let frameView = this._createFrameView.apply(this, arguments);
let menuEntry = this._createMenuEntry.apply(this, arguments);
// Append a stack frame item to this container.
this.push([frameView, aTitle, aUrl], {
index: 0, /* specifies on which position should the item be appended */
attachment: {
popup: menuEntry,
depth: aDepth
},
attributes: [
["contextmenu", "stackframesMenupopup"]
],
// Make sure that when the stack frame item is removed, the corresponding
// menuitem and command are also destroyed.
// mirrored item in the classic list is also removed.
finalize: this._onStackframeRemoved
});
// Mirror this newly inserted item inside the "Call Stack" tab.
this._mirror.addFrame(aTitle, aUrl, aLine, aDepth);
},
/**
@ -542,65 +535,6 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
return container;
},
/**
* Customization function for populating an item's context menu.
*
* @param string aTitle
* The frame title to be displayed in the list.
* @param string aUrl
* The frame source url.
* @param string aLine
* The frame line number.
* @param number aDepth
* The frame depth in the stack.
* @param boolean aIsBlackBoxed
* Whether or not the frame is black boxed.
* @return object
* An object containing the stack frame command and menu item.
*/
_createMenuEntry: function(aTitle, aUrl, aLine, aDepth, aIsBlackBoxed) {
let frameDescription = SourceUtils.trimUrlLength(
SourceUtils.getSourceLabel(aUrl),
STACK_FRAMES_POPUP_SOURCE_URL_MAX_LENGTH,
STACK_FRAMES_POPUP_SOURCE_URL_TRIM_SECTION) +
SEARCH_LINE_FLAG + aLine;
let prefix = "sf-cMenu-"; // "stackframes context menu"
let commandId = prefix + aDepth + "-" + "-command";
let menuitemId = prefix + aDepth + "-" + "-menuitem";
let command = document.createElement("command");
command.id = commandId;
command.addEventListener("command", () => this.selectedDepth = aDepth, false);
let menuitem = document.createElement("menuitem");
menuitem.id = menuitemId;
menuitem.className = "dbg-stackframe-menuitem";
menuitem.setAttribute("type", "checkbox");
menuitem.setAttribute("command", commandId);
menuitem.setAttribute("tooltiptext", aUrl);
let labelNode = document.createElement("label");
labelNode.className = "plain dbg-stackframe-menuitem-title";
labelNode.setAttribute("value", aTitle);
labelNode.setAttribute("flex", "1");
let descriptionNode = document.createElement("label");
descriptionNode.className = "plain dbg-stackframe-menuitem-details";
descriptionNode.setAttribute("value", frameDescription);
menuitem.appendChild(labelNode);
menuitem.appendChild(descriptionNode);
this._commandset.appendChild(command);
this._menupopup.appendChild(menuitem);
return {
command: command,
menuitem: menuitem
};
},
/**
* Function called each time a stack frame item is removed.
*
@ -610,10 +544,9 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
_onStackframeRemoved: function(aItem) {
dumpn("Finalizing stackframe item: " + aItem);
// Destroy the context menu item for the stack frame.
let contextItem = aItem.attachment.popup;
contextItem.command.remove();
contextItem.menuitem.remove();
// Remove the mirrored item in the classic list.
let depth = aItem.attachment.depth;
this._mirror.remove(this._mirror.getItemForAttachment(e => e.depth == depth));
// Forget the previously blackboxed stack frame url.
this._prevBlackBoxedUrl = null;
@ -626,17 +559,13 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
let stackframeItem = this.selectedItem;
if (stackframeItem) {
// The container is not empty and an actual item was selected.
DebuggerController.StackFrames.selectFrame(stackframeItem.attachment.depth);
let depth = stackframeItem.attachment.depth;
DebuggerController.StackFrames.selectFrame(depth);
// Update the context menu to show the currently selected stackframe item
// as a checked entry.
for (let otherItem of this) {
if (otherItem != stackframeItem) {
otherItem.attachment.popup.menuitem.removeAttribute("checked");
} else {
otherItem.attachment.popup.menuitem.setAttribute("checked", "");
}
}
// Mirror the selected item in the classic list.
this.suppressSelectionEvents = true;
this._mirror.selectedItem = e => e.attachment.depth == depth;
this.suppressSelectionEvents = false;
}
},
@ -673,11 +602,142 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
}
},
_commandset: null,
_menupopup: null,
_mirror: null,
_prevBlackBoxedUrl: null
});
/*
* Functions handling the stackframes classic list UI.
* Controlled by the DebuggerView.StackFrames isntance.
*/
function StackFramesClassicListView() {
dumpn("StackFramesClassicListView was instantiated");
this._onSelect = this._onSelect.bind(this);
}
StackFramesClassicListView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the StackFramesClassicListView");
this.widget = new SideMenuWidget(document.getElementById("callstack-list"), {
theme: "light"
});
this.widget.addEventListener("select", this._onSelect, false);
this.emptyText = L10N.getStr("noStackFramesText");
this.autoFocusOnFirstItem = false;
this.autoFocusOnSelection = false;
// This view's contents are also mirrored in a different container.
this._mirror = DebuggerView.StackFrames;
// Show an empty label by default.
this.empty();
},
/**
* Destruction function, called when the debugger is closed.
*/
destroy: function() {
dumpn("Destroying the StackFramesClassicListView");
this.widget.removeEventListener("select", this._onSelect, false);
},
/**
* Adds a frame in this stackframes container.
*
* @param string aTitle
* The frame title (function name).
* @param string aUrl
* The frame source url.
* @param string aLine
* The frame line number.
* @param number aDepth
* The frame depth in the stack.
*/
addFrame: function(aTitle, aUrl, aLine, aDepth) {
// Create the element node for the stack frame item.
let frameView = this._createFrameView.apply(this, arguments);
// Append a stack frame item to this container.
this.push([frameView, aUrl], {
attachment: {
depth: aDepth
}
});
},
/**
* Customization function for creating an item's UI.
*
* @param string aTitle
* The frame title to be displayed in the list.
* @param string aUrl
* The frame source url.
* @param string aLine
* The frame line number.
* @param number aDepth
* The frame depth in the stack.
* @return nsIDOMNode
* The stack frame view.
*/
_createFrameView: function(aTitle, aUrl, aLine, aDepth) {
let container = document.createElement("hbox");
container.id = "classic-stackframe-" + aDepth;
container.className = "dbg-classic-stackframe";
container.setAttribute("flex", "1");
let frameTitleNode = document.createElement("label");
frameTitleNode.className = "plain dbg-classic-stackframe-title";
frameTitleNode.setAttribute("value", aTitle);
frameTitleNode.setAttribute("crop", "center");
let frameDetailsNode = document.createElement("hbox");
frameDetailsNode.className = "plain dbg-classic-stackframe-details";
let frameUrlNode = document.createElement("label");
frameUrlNode.className = "plain dbg-classic-stackframe-details-url";
frameUrlNode.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
frameUrlNode.setAttribute("crop", "center");
frameDetailsNode.appendChild(frameUrlNode);
let frameDetailsSeparator = document.createElement("label");
frameDetailsSeparator.className = "plain dbg-classic-stackframe-details-sep";
frameDetailsSeparator.setAttribute("value", SEARCH_LINE_FLAG);
frameDetailsNode.appendChild(frameDetailsSeparator);
let frameLineNode = document.createElement("label");
frameLineNode.className = "plain dbg-classic-stackframe-details-line";
frameLineNode.setAttribute("value", aLine);
frameDetailsNode.appendChild(frameLineNode);
container.appendChild(frameTitleNode);
container.appendChild(frameDetailsNode);
return container;
},
/**
* The select listener for the stackframes container.
*/
_onSelect: function(e) {
let stackframeItem = this.selectedItem;
if (stackframeItem) {
// The container is not empty and an actual item was selected.
// Mirror the selected item in the breadcrumbs list.
let depth = stackframeItem.attachment.depth;
this._mirror.selectedItem = e => e.attachment.depth == depth;
}
},
_mirror: null
});
/**
* Functions handling the filtering UI.
*/
@ -1533,3 +1593,4 @@ DebuggerView.FilteredSources = new FilteredSourcesView();
DebuggerView.FilteredFunctions = new FilteredFunctionsView();
DebuggerView.ChromeGlobals = new ChromeGlobalsView();
DebuggerView.StackFrames = new StackFramesView();
DebuggerView.StackFramesClassicList = new StackFramesClassicListView();

View File

@ -9,8 +9,6 @@ const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE = 1048576; // 1 MB in bytes
const SOURCE_URL_DEFAULT_MAX_LENGTH = 64; // chars
const STACK_FRAMES_SOURCE_URL_MAX_LENGTH = 15; // chars
const STACK_FRAMES_SOURCE_URL_TRIM_SECTION = "center";
const STACK_FRAMES_POPUP_SOURCE_URL_MAX_LENGTH = 32; // chars
const STACK_FRAMES_POPUP_SOURCE_URL_TRIM_SECTION = "center";
const STACK_FRAMES_SCROLL_DELAY = 100; // ms
const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars
const BREAKPOINT_CONDITIONAL_POPUP_POSITION = "before_start";
@ -59,6 +57,7 @@ let DebuggerView = {
this.FilteredFunctions.initialize();
this.ChromeGlobals.initialize();
this.StackFrames.initialize();
this.StackFramesClassicList.initialize();
this.Sources.initialize();
this.VariableBubble.initialize();
this.WatchExpressions.initialize();
@ -93,6 +92,7 @@ let DebuggerView = {
this.FilteredFunctions.destroy();
this.ChromeGlobals.destroy();
this.StackFrames.destroy();
this.StackFramesClassicList.destroy();
this.Sources.destroy();
this.VariableBubble.destroy();
this.WatchExpressions.destroy();
@ -531,7 +531,7 @@ let DebuggerView = {
animated: true,
delayed: true,
callback: aCallback
}, 0);
});
},
/**

View File

@ -4,14 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Sources search view */
#globalsearch {
overflow: auto;
}
/* Instruments pane view (watch expressions, variables, events...) */
/* Side pane views */
#sources-pane > tabpanels > tabpanel,
#instruments-pane > tabpanels > tabpanel {
-moz-box-orient: vertical;
}
@ -21,6 +16,10 @@
overflow-y: auto;
}
#globalsearch {
overflow: auto;
}
/* Toolbar controls */
.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {

View File

@ -321,23 +321,35 @@
<scrollbox id="globalsearch" orient="vertical" hidden="true"/>
<splitter class="devtools-horizontal-splitter" hidden="true"/>
<hbox id="debugger-widgets" flex="1">
<vbox id="sources-pane">
<vbox id="sources" flex="1"/>
<toolbar id="sources-toolbar" class="devtools-toolbar">
<hbox id="sources-controls">
<toolbarbutton id="black-box"
tooltiptext="&debuggerUI.sources.blackBoxTooltip;"
command="blackBoxCommand"
class="devtools-toolbarbutton"/>
<toolbarbutton id="pretty-print"
label="{}"
tooltiptext="&debuggerUI.sources.prettyPrint;"
class="devtools-toolbarbutton devtools-monospace"
command="prettyPrintCommand"
hidden="true"/>
</hbox>
</toolbar>
</vbox>
<tabbox id="sources-pane"
class="devtools-sidebar-tabs">
<tabs>
<tab id="sources-tab" label="&debuggerUI.tabs.sources;"/>
<tab id="callstack-tab" label="&debuggerUI.tabs.callstack;"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="sources-tabpanel">
<vbox id="sources" flex="1"/>
<toolbar id="sources-toolbar" class="devtools-toolbar">
<hbox id="sources-controls">
<toolbarbutton id="black-box"
tooltiptext="&debuggerUI.sources.blackBoxTooltip;"
command="blackBoxCommand"
class="devtools-toolbarbutton"/>
<toolbarbutton id="pretty-print"
label="{}"
tooltiptext="&debuggerUI.sources.prettyPrint;"
class="devtools-toolbarbutton devtools-monospace"
command="prettyPrintCommand"
hidden="true"/>
</hbox>
</toolbar>
</tabpanel>
<tabpanel id="callstack-tabpanel">
<vbox id="callstack-list" flex="1"/>
</tabpanel>
</tabpanels>
</tabbox>
<splitter id="sources-and-editor-splitter"
class="devtools-side-splitter"/>
<deck id="editor-deck" flex="4">
@ -367,12 +379,12 @@
<tab id="events-tab" label="&debuggerUI.tabs.events;"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="variables-tabpanel">
<tabpanel id="variables-tabpanel" class="theme-body">
<vbox id="expressions"/>
<splitter class="devtools-horizontal-splitter"/>
<vbox id="variables" flex="1"/>
</tabpanel>
<tabpanel id="events-tabpanel">
<tabpanel id="events-tabpanel" class="theme-body">
<vbox id="event-listeners" flex="1"/>
</tabpanel>
</tabpanels>

View File

@ -48,34 +48,40 @@ function test() {
}
function checkNavigationWhileFocused() {
let deferred = promise.defer();
return Task.spawn(function() {
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 2, source: 1, line: 6 });
EventUtils.sendKey("UP", gDebugger);
checkState({ frame: 2, source: 1, line: 6 });
waitForSourceAndCaret(gPanel, "-01.js", 5).then(() => {
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 5),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 1, source: 0, line: 5 });
EventUtils.sendKey("UP", gDebugger);
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
EventUtils.sendKey("UP", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
waitForSourceAndCaret(gPanel, "-02.js", 6).then(() => {
checkState({ frame: 3, source: 1, line: 6 });
waitForSourceAndCaret(gPanel, "-01.js", 5).then(() => {
checkState({ frame: 0, source: 0, line: 5 });
deferred.resolve();
});
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-02.js", 6),
EventUtils.sendKey("END", gDebugger)
]);
checkState({ frame: 3, source: 1, line: 6 });
yield promise.all([
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES),
waitForSourceAndCaret(gPanel, "-01.js", 5),
EventUtils.sendKey("HOME", gDebugger)
});
EventUtils.sendKey("END", gDebugger)
]);
checkState({ frame: 0, source: 0, line: 5 });
});
EventUtils.sendKey("UP", gDebugger)
return deferred.promise;
}
function checkState({ frame, source, line }) {

View File

@ -46,7 +46,7 @@ function performTest() {
is(gSources.widget.getAttribute("label"), "doc_recursion-stack.html",
"The sources widget should have a correct label attribute.");
is(gSources.widget.getAttribute("tooltiptext"), "example.com test",
is(gSources.widget.getAttribute("tooltiptext"), "http://example.com",
"The sources widget should have a correct tooltip text attribute.");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice-container").length, 0,

View File

@ -48,7 +48,7 @@ function testLocationChange() {
is(gSources.widget.getAttribute("label"), "doc_inline-debugger-statement.html",
"The sources widget should have a correct label attribute.");
is(gSources.widget.getAttribute("tooltiptext"), "example.com test",
is(gSources.widget.getAttribute("tooltiptext"), "http://example.com",
"The sources widget should have a correct tooltip text attribute.");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice-container").length, 0,

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gFrames;
let gFrames, gClassicFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -17,6 +17,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(performTest);
gDebuggee.simpleCall();
@ -28,6 +29,8 @@ function performTest() {
"Should only be getting stack frames while paused.");
is(gFrames.itemCount, 1,
"Should have only one frame.");
is(gClassicFrames.itemCount, 1,
"Should also have only one frame in the mirrored view.");
resumeDebuggerThenCloseAndFinish(gPanel);
}
@ -38,4 +41,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gFrames;
let gFrames, gClassicFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -17,6 +17,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, ".html", 18).then(performTest);
gDebuggee.evalCall();
@ -28,21 +29,32 @@ function performTest() {
"Should only be getting stack frames while paused.");
is(gFrames.itemCount, 2,
"Should have two frames.");
is(gClassicFrames.itemCount, 2,
"Should also have only two in the mirrored view.");
is(gFrames.getItemAtIndex(0).value,
"evalCall", "Oldest frame name should be correct.");
is(gFrames.getItemAtIndex(0).description,
TAB_URL, "Oldest frame url should be correct.");
is(gClassicFrames.getItemAtIndex(0).value,
TAB_URL, "Oldest frame name is mirrored correctly.");
is(gFrames.getItemAtIndex(1).value,
"(eval)", "Newest frame name should be correct.");
is(gFrames.getItemAtIndex(1).description,
TAB_URL, "Newest frame url should be correct.");
is(gClassicFrames.getItemAtIndex(1).value,
TAB_URL, "Newest frame name is mirrored correctly.");
is(gFrames.selectedIndex, 1,
"Newest frame should be selected by default.");
is(gClassicFrames.selectedIndex, 0,
"Newest frame should be selected by default in the mirrored view.");
isnot(gFrames.selectedIndex, 0,
"Oldest frame should not be selected.");
isnot(gClassicFrames.selectedIndex, 1,
"Oldest frame should not be selected in the mirrored view.");
EventUtils.sendMouseEvent({ type: "mousedown" },
gFrames.getItemAtIndex(0).target,
@ -50,8 +62,13 @@ function performTest() {
isnot(gFrames.selectedIndex, 1,
"Newest frame should not be selected after click.");
isnot(gClassicFrames.selectedIndex, 0,
"Newest frame in the mirrored view should not be selected.");
is(gFrames.selectedIndex, 0,
"Oldest frame should be selected after click.");
is(gClassicFrames.selectedIndex, 1,
"Oldest frame in the mirrored view should be selected.");
EventUtils.sendMouseEvent({ type: "mousedown" },
gFrames.getItemAtIndex(1).target.querySelector(".dbg-stackframe-title"),
@ -59,8 +76,13 @@ function performTest() {
is(gFrames.selectedIndex, 1,
"Newest frame should be selected after click inside the newest frame.");
is(gClassicFrames.selectedIndex, 0,
"Newest frame in the mirrored view should be selected.");
isnot(gFrames.selectedIndex, 0,
"Oldest frame should not be selected after click inside the newest frame.");
isnot(gClassicFrames.selectedIndex, 1,
"Oldest frame in the mirrored view should not be selected.");
EventUtils.sendMouseEvent({ type: "mousedown" },
gFrames.getItemAtIndex(0).target.querySelector(".dbg-stackframe-details"),
@ -68,8 +90,13 @@ function performTest() {
isnot(gFrames.selectedIndex, 1,
"Newest frame should not be selected after click inside the oldest frame.");
isnot(gClassicFrames.selectedIndex, 0,
"Newest frame in the mirrored view should not be selected.");
is(gFrames.selectedIndex, 0,
"Oldest frame should be selected after click inside the oldest frame.");
is(gClassicFrames.selectedIndex, 1,
"Oldest frame in the mirrored view should be selected.");
resumeDebuggerThenCloseAndFinish(gPanel);
}
@ -80,4 +107,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gFrames, gFramesScrollingInterval;
let gFrames, gClassicFrames, gFramesScrollingInterval;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -17,6 +17,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, ".html", 26).then(performTest);
@ -30,14 +31,20 @@ function performTest() {
"Should only be getting stack frames while paused.");
is(gFrames.itemCount, gDebugger.gCallStackPageSize,
"Should have only the max limit of frames.");
is(gClassicFrames.itemCount, gDebugger.gCallStackPageSize,
"Should have only the max limit of frames in the mirrored view as well.")
gDebugger.gThreadClient.addOneTimeListener("framesadded", () => {
is(gFrames.itemCount, gDebugger.gCallStackPageSize * 2,
"Should now have twice the max limit of frames.");
is(gClassicFrames.itemCount, gDebugger.gCallStackPageSize * 2,
"Should now have twice the max limit of frames in the mirrored view as well.");
gDebugger.gThreadClient.addOneTimeListener("framesadded", () => {
is(gFrames.itemCount, gDebuggee.gRecurseLimit,
"Should have reached the recurse limit.");
is(gClassicFrames.itemCount, gDebuggee.gRecurseLimit,
"Should have reached the recurse limit in the mirrored view as well.");
gDebugger.gThreadClient.resume(() => {
window.clearInterval(gFramesScrollingInterval);
@ -60,4 +67,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -8,7 +8,7 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gFrames;
let gFrames, gClassicFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -17,6 +17,7 @@ function test() {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, ".html", 18).then(performTest);
gDebuggee.evalCall();
@ -28,10 +29,14 @@ function performTest() {
"Should only be getting stack frames while paused.");
is(gFrames.itemCount, 2,
"Should have two frames.");
is(gClassicFrames.itemCount, 2,
"Should also have two frames in the mirrored view.");
gDebugger.once(gDebugger.EVENTS.AFTER_FRAMES_CLEARED, () => {
is(gFrames.itemCount, 0,
"Should have no frames after resume.");
is(gClassicFrames.itemCount, 0,
"Should also have no frames in the mirrored view after resume.");
closeDebuggerAndFinish(gPanel);
}, true);
@ -45,4 +50,5 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -9,7 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames;
let gEditor, gSources, gFrames, gClassicFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -20,6 +20,7 @@ function test() {
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6)
.then(initialChecks)
@ -40,6 +41,8 @@ function initialChecks() {
"Should only be getting stack frames while paused.");
is(gFrames.itemCount, 4,
"Should have four frames.");
is(gClassicFrames.itemCount, 4,
"Should also have four frames in the mirrored view.");
}
function testNewestTwoFrames() {
@ -47,6 +50,8 @@ function testNewestTwoFrames() {
is(gFrames.selectedIndex, 3,
"Newest frame should be selected by default.");
is(gClassicFrames.selectedIndex, 0,
"Newest frame should be selected in the mirrored view as well.");
is(gSources.selectedIndex, 1,
"The second source is selected in the widget.");
ok(isCaretPos(gPanel, 6),
@ -63,6 +68,8 @@ function testNewestTwoFrames() {
is(gFrames.selectedIndex, 2,
"Third frame should be selected after click.");
is(gClassicFrames.selectedIndex, 1,
"Third frame should be selected in the mirrored view as well.");
is(gSources.selectedIndex, 1,
"The second source is still selected in the widget.");
ok(isCaretPos(gPanel, 6),
@ -83,9 +90,11 @@ function testNewestTwoFrames() {
function testOldestTwoFrames() {
let deferred = promise.defer();
waitForSourceAndCaret(gPanel, "-01.js", 5).then(() => {
waitForSourceAndCaret(gPanel, "-01.js", 5).then(waitForTick).then(() => {
is(gFrames.selectedIndex, 1,
"Second frame should be selected after click.");
is(gClassicFrames.selectedIndex, 2,
"Second frame should be selected in the mirrored view as well.");
is(gSources.selectedIndex, 0,
"The first source is now selected in the widget.");
ok(isCaretPos(gPanel, 5),
@ -102,6 +111,8 @@ function testOldestTwoFrames() {
is(gFrames.selectedIndex, 0,
"Oldest frame should be selected after click.");
is(gClassicFrames.selectedIndex, 3,
"Oldest frame should be selected in the mirrored view as well.");
is(gSources.selectedIndex, 0,
"The first source is still selected in the widget.");
ok(isCaretPos(gPanel, 5),
@ -118,7 +129,7 @@ function testOldestTwoFrames() {
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gFrames.getItemAtIndex(1).target,
gDebugger.document.querySelector("#stackframe-2"),
gDebugger);
return deferred.promise;
@ -130,6 +141,8 @@ function testAfterResume() {
gDebugger.once(gDebugger.EVENTS.AFTER_FRAMES_CLEARED, () => {
is(gFrames.itemCount, 0,
"Should have no frames after resume.");
is(gClassicFrames.itemCount, 0,
"Should have no frames in the mirrored view as well.");
ok(isCaretPos(gPanel, 5),
"Editor caret location is correct after resume.");
is(gEditor.getDebugLocation(), null,
@ -150,5 +163,6 @@ registerCleanupFunction(function() {
gDebugger = null;
gEditor = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -9,7 +9,7 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames;
let gEditor, gSources, gFrames, gClassicFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -20,6 +20,7 @@ function test() {
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6).then(performTest);
gDebuggee.firstCall();
@ -29,16 +30,20 @@ function test() {
function performTest() {
is(gFrames.selectedIndex, 3,
"Newest frame should be selected by default.");
is(gClassicFrames.selectedIndex, 0,
"Newest frame should also be selected in the mirrored view.");
is(gSources.selectedIndex, 1,
"The second source is selected in the widget.");
is(gEditor.getText().search(/firstCall/), -1,
"The first source is not displayed.");
is(gEditor.getText().search(/debugger/), 172,
"The second source is displayed.")
"The second source is displayed.");
waitForSourceAndCaret(gPanel, "-01.js", 6).then(() => {
waitForSourceAndCaret(gPanel, "-01.js", 6).then(waitForTick).then(() => {
is(gFrames.selectedIndex, 0,
"Oldest frame should be selected after click.");
is(gClassicFrames.selectedIndex, 3,
"Oldest frame should also be selected in the mirrored view.");
is(gSources.selectedIndex, 0,
"The first source is now selected in the widget.");
is(gEditor.getText().search(/firstCall/), 118,
@ -46,7 +51,24 @@ function performTest() {
is(gEditor.getText().search(/debugger/), -1,
"The second source is not displayed.");
resumeDebuggerThenCloseAndFinish(gPanel);
waitForSourceAndCaret(gPanel, "-02.js", 6).then(waitForTick).then(() => {
is(gFrames.selectedIndex, 3,
"Newest frame should be selected again after click.");
is(gClassicFrames.selectedIndex, 0,
"Newest frame should also be selected again in the mirrored view.");
is(gSources.selectedIndex, 1,
"The second source is selected in the widget.");
is(gEditor.getText().search(/firstCall/), -1,
"The first source is not displayed.");
is(gEditor.getText().search(/debugger/), 172,
"The second source is displayed.");
resumeDebuggerThenCloseAndFinish(gPanel);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.querySelector("#classic-stackframe-0"),
gDebugger);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
@ -62,4 +84,5 @@ registerCleanupFunction(function() {
gEditor = null;
gSources = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -10,7 +10,7 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames, gToolbar;
let gEditor, gSources, gFrames, gClassicFrames, gToolbar;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
@ -21,6 +21,7 @@ function test() {
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gFrames = gDebugger.DebuggerView.StackFrames;
gClassicFrames = gDebugger.DebuggerView.StackFramesClassicList;
gToolbar = gDebugger.DebuggerView.Toolbar;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 6).then(performTest);
@ -53,13 +54,15 @@ function performTest() {
function selectBottomFrame() {
let updated = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
gFrames.selectedIndex = 0;
gClassicFrames.selectedIndex = gClassicFrames.itemCount - 1;
return updated.then(waitForTick);
}
function testBottomFrame(debugLocation) {
is(gFrames.selectedIndex, 0,
"Oldest frame should be selected after click.");
is(gClassicFrames.selectedIndex, gFrames.itemCount - 1,
"Oldest frame should also be selected in the mirrored view.");
is(gSources.selectedIndex, 0,
"The first source is now selected in the widget.");
is(gEditor.getText().search(/firstCall/), 118,
@ -82,6 +85,8 @@ function performTest() {
function testTopFrame(frameIndex) {
is(gFrames.selectedIndex, frameIndex,
"Topmost frame should be selected after click.");
is(gClassicFrames.selectedIndex, gFrames.itemCount - frameIndex - 1,
"Topmost frame should also be selected in the mirrored view.");
is(gSources.selectedIndex, 1,
"The second source is now selected in the widget.");
is(gEditor.getText().search(/firstCall/), -1,
@ -99,5 +104,6 @@ registerCleanupFunction(function() {
gEditor = null;
gSources = null;
gFrames = null;
gClassicFrames = null;
gToolbar = null;
});

View File

@ -6,7 +6,7 @@
"use strict";
const { Cc, Ci, Cu, Cr } = require("chrome");
const promise = require("sdk/core/promise");
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
const EventEmitter = require("devtools/shared/event-emitter");
const { WebGLFront } = require("devtools/server/actors/webgl");

View File

@ -13,7 +13,7 @@ Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
const promise = require("sdk/core/promise");
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
const EventEmitter = require("devtools/shared/event-emitter");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
const Editor = require("devtools/sourceeditor/editor");
@ -28,7 +28,13 @@ const EVENTS = {
SOURCES_SHOWN: "ShaderEditor:SourcesShown",
// When a shader's source was edited and compiled via the editor.
SHADER_COMPILED: "ShaderEditor:ShaderCompiled"
SHADER_COMPILED: "ShaderEditor:ShaderCompiled",
// When the UI is reset from tab navigation
UI_RESET: "ShaderEditor:UIReset",
// When the editor's error markers are all removed
EDITOR_ERROR_MARKERS_REMOVED: "ShaderEditor:EditorCleaned"
};
const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties"
@ -114,15 +120,17 @@ let EventsHandler = {
_onTabNavigated: function(event) {
switch (event) {
case "will-navigate": {
// Make sure the backend is prepared to handle WebGL contexts.
gFront.setup({ reload: false });
Task.spawn(function() {
// Make sure the backend is prepared to handle WebGL contexts.
gFront.setup({ reload: false });
// Reset UI.
ShadersListView.empty();
ShadersEditorsView.setText({ vs: "", fs: "" });
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
// Reset UI.
ShadersListView.empty();
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
yield ShadersEditorsView.setText({ vs: "", fs: "" });
$("#content").hidden = true;
}).then(() => window.emit(EVENTS.UI_RESET));
break;
}
case "navigate": {
@ -272,13 +280,16 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
]);
}
function showSources([vertexShaderText, fragmentShaderText]) {
ShadersEditorsView.setText({
return ShadersEditorsView.setText({
vs: vertexShaderText,
fs: fragmentShaderText
});
}
getShaders().then(getSources).then(showSources).then(null, Cu.reportError);
getShaders()
.then(getSources)
.then(showSources)
.then(null, Cu.reportError);
},
/**
@ -351,19 +362,24 @@ let ShadersEditorsView = {
* An object containing the following properties
* - vs: the vertex shader source code
* - fs: the fragment shader source code
* @return object
* A promise resolving upon completion of text setting.
*/
setText: function(sources) {
let view = this;
function setTextAndClearHistory(editor, text) {
editor.setText(text);
editor.clearHistory();
}
this._toggleListeners("off");
this._getEditor("vs").then(e => setTextAndClearHistory(e, sources.vs));
this._getEditor("fs").then(e => setTextAndClearHistory(e, sources.fs));
this._toggleListeners("on");
window.emit(EVENTS.SOURCES_SHOWN, sources);
return Task.spawn(function() {
yield view._toggleListeners("off");
yield promise.all([
view._getEditor("vs").then(e => setTextAndClearHistory(e, sources.vs)),
view._getEditor("fs").then(e => setTextAndClearHistory(e, sources.fs))
]);
yield view._toggleListeners("on");
}).then(() => window.emit(EVENTS.SOURCES_SHOWN, sources));
},
/**
@ -372,10 +388,12 @@ let ShadersEditorsView = {
* @param string type
* Specifies for which shader type should an editor be retrieved,
* either are "vs" for a vertex, or "fs" for a fragment shader.
* @return object
* Returns a promise that resolves to an editor instance
*/
_getEditor: function(type) {
if ($("#content").hidden) {
return promise.reject(null);
return promise.reject(new Error("Shader Editor is still waiting for a WebGL context to be created."));
}
if (this._editorPromises.has(type)) {
return this._editorPromises.get(type);
@ -399,14 +417,16 @@ let ShadersEditorsView = {
*
* @param string flag
* Either "on" to enable the event listeners, "off" to disable them.
* @return object
* A promise resolving upon completion of toggling the listeners.
*/
_toggleListeners: function(flag) {
["vs", "fs"].forEach(type => {
this._getEditor(type).then(editor => {
return promise.all(["vs", "fs"].map(type => {
return this._getEditor(type).then(editor => {
editor[flag]("focus", this["_" + type + "Focused"]);
editor[flag]("change", this["_" + type + "Changed"]);
});
});
}));
},
/**
@ -486,7 +506,7 @@ let ShadersEditorsView = {
}
function sanitizeValidMatches(e) {
return {
// Drivers might yield retarded line numbers under some obscure
// Drivers might yield confusing line numbers under some obscure
// circumstances. Don't throw the errors away in those cases,
// just display them on the currently edited line.
line: e.lineMatch[0] > lineCount ? currentLine : e.lineMatch[0] - 1,
@ -554,6 +574,7 @@ let ShadersEditorsView = {
editor.removeAllMarkers("errors");
this._errors[type].forEach(e => editor.removeLineClass(e.line));
this._errors[type].length = 0;
window.emit(EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
});
},

View File

@ -14,8 +14,7 @@ function ifWebGLSupported() {
yield reloaded;
let navigated = navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(gFront, "program-linked");
let thirdProgram = yield once(gFront, "program-linked");
let [secondProgram, thirdProgram] = yield getPrograms(gFront, 2);
yield navigated;
let vsEditor = yield ShadersEditorsView._getEditor("vs");
@ -56,9 +55,3 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -8,14 +8,18 @@
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
let { gFront, ShadersEditorsView } = panel.panelWin;
let { gFront, ShadersEditorsView, EVENTS } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
is(vsEditor.getText().indexOf("gl_Position"), 170,
"The vertex shader editor contains the correct text.");
is(fsEditor.getText().indexOf("gl_FragColor"), 97,

View File

@ -11,55 +11,61 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks added in the vertex shader editor.");
vsEditor.insertText(" ", { line: 1, ch: 0 });
yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
is(vsEditor.getText(1), " precision lowp float;", "Typed space.");
checkHasVertFirstError(false, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks removed while typing in the vertex shader editor.");
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
[, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks were re-added after recompiling the vertex shader.");
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks added in the fragment shader editor.");
fsEditor.insertText(" ", { line: 1, ch: 0 });
yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
is(fsEditor.getText(1), " precision lowp float;", "Typed space.");
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(false, fragError);
info("Error marks removed while typing in the fragment shader editor.");
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
[, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks were re-added after recompiling the fragment shader.");
vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 });
yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED);
checkHasVertFirstError(false, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks removed while typing in the vertex shader editor again.");
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
[, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(true, vertError);
checkHasFragError(true, fragError);
@ -148,9 +154,3 @@ function ifWebGLSupported() {
}
}
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
return deferred.promise;
}

View File

@ -11,7 +11,10 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -51,9 +54,3 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
return deferred.promise;
}

View File

@ -7,10 +7,13 @@
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
let { gFront, $, ShadersListView, ShadersEditorsView } = panel.panelWin;
let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden after linking.");
@ -39,6 +42,7 @@ function ifWebGLSupported() {
navigate(target, "about:blank");
yield navigating;
yield once(panel.panelWin, EVENTS.UI_RESET);
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden while navigating.");
@ -54,19 +58,17 @@ function ifWebGLSupported() {
is(ShadersListView.selectedIndex, -1,
"The shaders list has a negative index.");
try {
yield ShadersEditorsView._getEditor("vs");
yield ShadersEditorsView._getEditor("vs").then(() => {
ok(false, "The promise for a vertex shader editor should be rejected.");
} catch (e) {
}, () => {
ok(true, "The vertex shader editors wasn't initialized.");
}
});
try {
yield ShadersEditorsView._getEditor("fs");
yield ShadersEditorsView._getEditor("fs").then(() => {
ok(false, "The promise for a fragment shader editor should be rejected.");
} catch (e) {
}, () => {
ok(true, "The fragment shader editors wasn't initialized.");
}
});
yield navigated;

View File

@ -14,8 +14,10 @@ function ifWebGLSupported() {
});
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
let secondProgramActor = yield once(gFront, "program-linked");
let [firstProgramActor, secondProgramActor] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");

View File

@ -11,8 +11,10 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
let secondProgramActor = yield once(gFront, "program-linked");
let [firstProgramActor, secondProgramActor] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
@ -59,9 +61,3 @@ function getBlackBoxCheckbox(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-checkbox")[aIndex];
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -7,10 +7,14 @@
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(MULTIPLE_CONTEXTS_URL);
let { gFront, ShadersListView, ShadersEditorsView } = panel.panelWin;
let { EVENTS, gFront, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let programActor = yield once(gFront, "program-linked");
let [programActor] = yield promise.all([
getPrograms(gFront, 1),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
let programItem = ShadersListView.selectedItem;
is(programItem.attachment.programActor, programActor,

View File

@ -14,8 +14,10 @@ function ifWebGLSupported() {
});
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
let secondProgramActor = yield once(gFront, "program-linked");
let [firstProgramActor, secondProgramActor] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -89,9 +91,3 @@ function getBlackBoxCheckbox(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-checkbox")[aIndex];
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -11,8 +11,10 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
let secondProgramActor = yield once(gFront, "program-linked");
let [firstProgramActor, secondProgramActor] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
@ -45,9 +47,3 @@ function getItemLabel(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-label")[aIndex];
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -19,23 +19,17 @@ function ifWebGLSupported() {
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
is(ShadersListView.itemCount, 1,
"The shaders list contains one entry.");
is(ShadersListView.selectedItem, ShadersListView.items[0],
"The shaders list has a correct item selected.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct index selected.");
let secondProgramActor = yield once(gFront, "program-linked");
is(ShadersListView.itemCount, 2,
"The shaders list contains two entries.");
is(ShadersListView.selectedItem, ShadersListView.items[0],
"The shaders list has a correct item selected.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct index selected.");
let [firstProgramActor, secondProgramActor] = yield promise.all([
getPrograms(gFront, 2, (actors) => {
// Fired upon each actor addition, we want to check only
// after the first actor has been added so we can test state
if (actors.length === 1)
checkFirstProgram();
if (actors.length === 2)
checkSecondProgram();
}),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs, ]) => programs);
is(ShadersListView.labels[0], L10N.getFormatStr("shadersList.programLabel", 0),
"The correct first label is shown in the shaders list.");
@ -73,10 +67,21 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
function checkFirstProgram () {
is(ShadersListView.itemCount, 1,
"The shaders list contains one entry.");
is(ShadersListView.selectedItem, ShadersListView.items[0],
"The shaders list has a correct item selected.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct index selected.");
}
function checkSecondProgram () {
is(ShadersListView.itemCount, 2,
"The shaders list contains two entries.");
is(ShadersListView.selectedItem, ShadersListView.items[0],
"The shaders list has a correct item selected.");
is(ShadersListView.selectedIndex, 0,
"The shaders list has a correct index selected.");
}
}

View File

@ -10,7 +10,10 @@ function ifWebGLSupported() {
let { gFront, $, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -68,9 +71,3 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -11,13 +11,16 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
let error = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(error,
"The new vertex shader source was compiled with errors.");
@ -33,7 +36,7 @@ function ifWebGLSupported() {
"An assignment error is contained in the linkage status.");
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
let error = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(error,
"The new fragment shader source was compiled with errors.");
@ -50,11 +53,11 @@ function ifWebGLSupported() {
yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
vsEditor.replaceText("vec4", { line: 7, ch: 22 }, { line: 7, ch: 26 });
let error = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(!error, "The new vertex shader source was compiled successfully.");
fsEditor.replaceText("vec3", { line: 2, ch: 14 }, { line: 2, ch: 18 });
let error = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED);
ok(!error, "The new fragment shader source was compiled successfully.");
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
@ -63,9 +66,3 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
return deferred.promise;
}

View File

@ -11,8 +11,13 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let firstProgramActor = yield once(gFront, "program-linked");
let secondProgramActor = yield once(gFront, "program-linked");
yield promise.all([
once(gFront, "program-linked"),
once(gFront, "program-linked")
]);
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN)
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -78,9 +83,3 @@ function ifWebGLSupported() {
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, deferred.resolve);
return deferred.promise;
}

View File

@ -9,8 +9,7 @@ function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
front.setup({ reload: true });
let firstProgramActor = yield once(front, "program-linked");
let secondProgramActor = yield once(front, "program-linked");
let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
isnot(firstProgramActor, secondProgramActor,
"Two distinct program actors were recevide from two separate contexts.");

View File

@ -10,8 +10,8 @@ function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
front.setup({ reload: true });
let firstProgramActor = yield once(front, "program-linked");
let secondProgramActor = yield once(front, "program-linked");
let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
let firstFragmentShader = yield firstProgramActor.getFragmentShader();
let secondFragmentShader = yield secondProgramActor.getFragmentShader();

View File

@ -16,8 +16,7 @@ function ifWebGLSupported() {
ok(true, "The cached programs behave correctly before the navigation.");
navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(front, "program-linked");
let thirdProgram = yield once(front, "program-linked");
let [secondProgram, thirdProgram] = yield getPrograms(front, 2);
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
ok(true, "The cached programs behave correctly after the navigation.");

View File

@ -23,8 +23,7 @@ function ifWebGLSupported() {
// 1. Perform a simple navigation.
navigate(target, MULTIPLE_CONTEXTS_URL);
let secondProgram = yield once(front, "program-linked");
let thirdProgram = yield once(front, "program-linked");
let [secondProgram, thirdProgram] = yield getPrograms(front, 2);
let programs = yield front.getPrograms();
is(programs.length, 2,
"The second and third programs should be returned by a call to getPrograms().");
@ -65,8 +64,7 @@ function ifWebGLSupported() {
is(programs.length, 0,
"There should be no cached program actors yet.");
yield once(front, "program-linked");
yield once(front, "program-linked");
yield getPrograms(front, 2);
yield globalCreated;
let programs = yield front.getPrograms();
is(programs.length, 2,

View File

@ -10,8 +10,7 @@ function ifWebGLSupported() {
let [target, debuggee, front] = yield initBackend(OVERLAPPING_GEOMETRY_CANVAS_URL);
front.setup({ reload: true });
let firstProgramActor = yield once(front, "program-linked");
let secondProgramActor = yield once(front, "program-linked");
let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true);
yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true);

View File

@ -48,7 +48,7 @@
window.onload = function() {
canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl");
gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
gl.clearColor(0.0, 0.0, 0.0, 1.0);
initProgram(0);

View File

@ -42,7 +42,7 @@
window.onload = function() {
for (let i = 0; i < 2; i++) {
canvas[i] = document.querySelector("#canvas" + (i + 1));
gl[i] = canvas[i].getContext("webgl");
gl[i] = canvas[i].getContext("webgl", { preserveDrawingBuffer: true });
gl[i].clearColor(0.0, 0.0, 0.0, 1.0);
initProgram(i);

View File

@ -48,7 +48,7 @@
window.onload = function() {
canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl");
gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
gl.clearColor(0.0, 0.0, 0.0, 1.0);
initProgram(0);

View File

@ -35,7 +35,7 @@
window.onload = function() {
canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl");
gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
let shaderProgram = gl.createProgram();
let vertexShader, fragmentShader;

View File

@ -44,7 +44,7 @@
window.onload = function() {
canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl");
gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
gl.clearColor(0.0, 0.0, 0.0, 1.0);
initProgram();

View File

@ -12,7 +12,7 @@ let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Services.prefs.setBoolPref("devtools.debugger.log", true);
let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
let { Promise: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
@ -124,14 +124,14 @@ function once(aTarget, aEventName, aUseCapture = false) {
let deferred = promise.defer();
for (let [add, remove] of [
["on", "off"], // Use event emitter before DOM events for consistency
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
["addListener", "removeListener"]
]) {
if ((add in aTarget) && (remove in aTarget)) {
aTarget[add](aEventName, function onEvent(...aArgs) {
aTarget[remove](aEventName, onEvent, aUseCapture);
deferred.resolve.apply(deferred, aArgs);
deferred.resolve(...aArgs);
}, aUseCapture);
break;
}
@ -140,6 +140,16 @@ function once(aTarget, aEventName, aUseCapture = false) {
return deferred.promise;
}
// Hack around `once`, as that only resolves to a single (first) argument
// and discards the rest. `onceSpread` is similar, except resolves to an
// array of all of the arguments in the handler. These should be consolidated
// into the same function, but many tests will need to be changed.
function onceSpread(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (...args) => deferred.resolve(args));
return deferred.promise;
}
function observe(aNotificationName, aOwnsWeak = false) {
info("Waiting for observer notification: '" + aNotificationName + ".");
@ -273,3 +283,27 @@ function teardown(aPanel) {
removeTab(aPanel.target.tab)
]);
}
// Due to `program-linked` events firing synchronously, we cannot
// just yield/chain them together, as then we miss all actors after the
// first event since they're fired consecutively. This allows us to capture
// all actors and returns an array containing them.
//
// Takes a `front` object that is an event emitter, the number of
// programs that should be listened to and waited on, and an optional
// `onAdd` function that calls with the entire actors array on program link
function getPrograms(front, count, onAdd) {
let actors = [];
let deferred = promise.defer();
front.on("program-linked", function onLink (actor) {
if (actors.length !== count) {
actors.push(actor);
if (typeof onAdd === 'function') onAdd(actors)
}
if (actors.length === count) {
front.off("program-linked", onLink);
deferred.resolve(actors);
}
});
return deferred.promise;
}

View File

@ -77,6 +77,7 @@ this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
this._parent = aParentNode;
this._parent.classList.add("variables-view-container");
this._parent.classList.add("theme-body");
this._appendEmptyNotice();
this._onSearchboxInput = this._onSearchboxInput.bind(this);

View File

@ -654,7 +654,7 @@ this.WidgetMethods = {
* - relaxed: true if this container should allow dupes & degenerates
* - attachment: some attached primitive/object for the item
* - attributes: a batch of attributes set to the displayed element
* - finalize: function invokde when the item is removed
* - finalize: function invoked when the item is removed
* @return Item
* The item associated with the displayed element if an unstaged push,
* undefined if the item was staged for a later commit.
@ -733,6 +733,7 @@ this.WidgetMethods = {
}
this._widget.removeChild(aItem._target);
this._untangleItem(aItem);
if (!this.itemCount) this.empty();
},
/**
@ -1009,7 +1010,9 @@ this.WidgetMethods = {
// a redundant selection event, so return early.
if (targetElement != prevElement) {
this._widget.selectedItem = targetElement;
ViewHelpers.dispatchEvent(targetElement || prevElement, "select", aItem);
let dispTarget = targetElement || prevElement;
let dispName = this.suppressSelectionEvents ? "suppressed-select" : "select";
ViewHelpers.dispatchEvent(dispTarget, dispName, aItem);
}
// Updates this container to reflect the information provided by the
@ -1044,6 +1047,15 @@ this.WidgetMethods = {
set selectedValue(aValue)
this.selectedItem = this._itemsByValue.get(aValue),
/**
* Specifies if "select" events dispatched from the elements in this container
* when their respective items are selected should be suppressed or not.
*
* If this flag is set to true, then consumers of this container won't
* be normally notified when items are selected.
*/
suppressSelectionEvents: false,
/**
* Focus this container the first time an element is inserted?
*
@ -1305,6 +1317,14 @@ this.WidgetMethods = {
return null;
},
/**
* Shortcut function for getItemForPredicate which works on item attachments.
* @see getItemForPredicate
*/
getItemForAttachment: function(aPredicate, aOwner = this) {
return this.getItemForPredicate(e => aPredicate(e.attachment));
},
/**
* Finds the index of an item in the container.
*

View File

@ -236,7 +236,13 @@ Editor.prototype = {
cm.on("focus", () => this.emit("focus"));
cm.on("scroll", () => this.emit("scroll"));
cm.on("change", () => this.emit("change"));
cm.on("change", () => {
this.emit("change");
if (!this._lastDirty) {
this._lastDirty = true;
this.emit("dirty-change");
}
});
cm.on("cursorActivity", (cm) => this.emit("cursorActivity"));
cm.on("gutterClick", (cm, line, gutter, ev) => {
@ -614,6 +620,8 @@ Editor.prototype = {
setClean: function () {
let cm = editors.get(this);
this.version = cm.changeGeneration();
this._lastDirty = false;
this.emit("dirty-change");
return this.version;
},

View File

@ -234,7 +234,7 @@ StyleSheetEditor.prototype = {
this.emit("source-editor-load");
});
sourceEditor.on("change", this._onPropertyChange);
sourceEditor.on("dirty-change", this._onPropertyChange);
},
/**

View File

@ -14,7 +14,6 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope);
let FileUtils = tempScope.FileUtils;
let NetUtil = tempScope.NetUtil;
function test()
{
waitForExplicitFinish();
@ -41,9 +40,22 @@ function test()
function runTests(editor)
{
editor.sourceEditor.once("dirty-change", () => {
is(editor.sourceEditor.isClean(), false, "Editor is dirty.");
ok(editor.summary.classList.contains("unsaved"),
"Star icon is present in the corresponding summary.");
});
let beginCursor = {line: 0, ch: 0};
editor.sourceEditor.replaceText("DIRTY TEXT", beginCursor, beginCursor);
editor.sourceEditor.once("dirty-change", () => {
is(editor.sourceEditor.isClean(), true, "Editor is clean.");
ok(!editor.summary.classList.contains("unsaved"),
"Star icon is not present in the corresponding summary.");
finish();
});
editor.saveToFile(null, function (file) {
ok(file, "file should get saved directly when using a file:// URI");
finish();
});
}

View File

@ -3322,10 +3322,12 @@ JSTerm.prototype = {
iframe.addEventListener("load", function onIframeLoad(aEvent) {
iframe.removeEventListener("load", onIframeLoad, true);
iframe.style.visibility = "visible";
deferred.resolve(iframe.contentWindow);
}, true);
iframe.flex = 1;
iframe.style.visibility = "hidden";
iframe.setAttribute("src", VARIABLES_VIEW_URL);
aOptions.targetElement.appendChild(iframe);
}

View File

@ -111,6 +111,11 @@ BINPATH = bin
endif
DEFINES += -DBINPATH=$(BINPATH)
DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION)
ifdef MOZ_SHARED_ICU
DEFINES += -DMOZ_SHARED_ICU
endif
libs::
$(MAKE) -C $(DEPTH)/browser/locales langpack

View File

@ -101,6 +101,27 @@
#endif
#endif
#endif
#ifdef MOZ_SHARED_ICU
#ifdef XP_WIN
#ifdef MOZ_DEBUG
@BINPATH@/icudtd@MOZ_ICU_VERSION@.dll
@BINPATH@/icuind@MOZ_ICU_VERSION@.dll
@BINPATH@/icuucd@MOZ_ICU_VERSION@.dll
#else
@BINPATH@/icudt@MOZ_ICU_VERSION@.dll
@BINPATH@/icuin@MOZ_ICU_VERSION@.dll
@BINPATH@/icuuc@MOZ_ICU_VERSION@.dll
#endif
#elif defined(XP_MACOSX)
@BINPATH@/libicudata.@MOZ_ICU_VERSION@.dylib
@BINPATH@/libicui18n.@MOZ_ICU_VERSION@.dylib
@BINPATH@/libicuuc.@MOZ_ICU_VERSION@.dylib
#elif defined(XP_UNIX)
@BINPATH@/libicudata.so.@MOZ_ICU_VERSION@
@BINPATH@/libicui18n.so.@MOZ_ICU_VERSION@
@BINPATH@/libicuuc.so.@MOZ_ICU_VERSION@
#endif
#endif
[browser]
; [Base Browser Files]

View File

@ -129,8 +129,10 @@
<!ENTITY debuggerUI.seMenuCondBreak "Add conditional breakpoint">
<!ENTITY debuggerUI.seMenuCondBreak.key "B">
<!-- LOCALIZATION NOTE (debuggerUI.instruments.*): This is the text that
- appears in the debugger's instruments pane tabs. -->
<!-- LOCALIZATION NOTE (debuggerUI.tabs.*): This is the text that
- appears in the debugger's side pane tabs. -->
<!ENTITY debuggerUI.tabs.sources "Sources">
<!ENTITY debuggerUI.tabs.callstack "Call Stack">
<!ENTITY debuggerUI.tabs.variables "Variables">
<!ENTITY debuggerUI.tabs.events "Events">

View File

@ -69,10 +69,14 @@ noGlobalsText=No globals
# when there are no scripts.
noSourcesText=This page has no sources.
# LOCALIZATION NOTE (noEventsTExt): The text to display in the events tab
# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab
# when there are no events.
noEventListenersText=No event listeners to display
# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab
# when there are no stack frames.
noStackFramesText=No stack frames to display
# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when
# the user hovers over the checkbox used to toggle an event breakpoint.
eventCheckboxTooltip=Toggle breaking on this event

View File

@ -247,7 +247,7 @@ Desktop browser's sync prefs.
completeselectedindex="true"
placeholder="&urlbar.emptytext;"
tabscrolling="true"
onclick="SelectionHelperUI.urlbarClick();"/>
onclick="SelectionHelperUI.urlbarTextboxClick(this);"/>
<toolbarbutton id="go-button" class="urlbar-button"
command="cmd_go"/>

View File

@ -34,10 +34,9 @@ var ChromeSelectionHandler = {
this._domWinUtils = Util.getWindowUtils(window);
this._contentWindow = window;
this._targetElement = this._domWinUtils.elementFromPoint(aJson.xPos, aJson.yPos, true, false);
this._targetIsEditable = this._targetElement instanceof Components.interfaces.nsIDOMXULTextBoxElement;
if (!this._targetIsEditable) {
this._onFail("not an editable?");
this._onFail("not an editable?", this._targetElement);
return;
}

View File

@ -344,9 +344,9 @@ var SelectionHelperUI = {
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "attach_edit_session_to_content":
let event = aSubject;
this.attachEditSession(Browser.selectedTab.browser,
event.clientX, event.clientY);
// We receive this from text input bindings when this module
// isn't accessible.
this.chromeTextboxClick(aSubject);
break;
case "apzc-transform-begin":
@ -514,6 +514,40 @@ var SelectionHelperUI = {
});
},
/*
* Event handler on the navbar text input. Called from navbar bindings
* when focus is applied to the edit.
*/
urlbarTextboxClick: function(aEdit) {
// workaround for bug 925457: taping browser chrome resets last tap
// co-ordinates to 'undefined' so that we know not to shift the browser
// when the keyboard is up in SelectionHandler's _calcNewContentPosition().
Browser.selectedTab.browser.messageManager.sendAsyncMessage("Browser:ResetLastPos", {
xPos: null,
yPos: null
});
if (InputSourceHelper.isPrecise || !aEdit.textLength) {
return;
}
// Enable selection when there's text in the control
let innerRect = aEdit.inputField.getBoundingClientRect();
this.attachEditSession(ChromeSelectionHandler,
innerRect.left,
innerRect.top);
},
/*
* Click handler for chrome pages loaded into the browser (about:config).
* Called from the text input bindings via the attach_edit_session_to_content
* observer.
*/
chromeTextboxClick: function (aEvent) {
this.attachEditSession(Browser.selectedTab.browser,
aEvent.clientX, aEvent.clientY);
},
/*
* Handy debug routines that work independent of selection. They
* make use of the selection overlay for drawing points.
@ -835,20 +869,10 @@ var SelectionHelperUI = {
* Event handlers for document events
*/
urlbarClick: function() {
// Workaround for bug 925457: taping browser chrome resets last tap
// co-ordinates to 'undefined' so that we know not to shift the browser
// when the keyboard is up (in SelectionHandler._calcNewContentPosition())
Browser.selectedTab.browser.messageManager.sendAsyncMessage("Browser:ResetLastPos", {
xPos: null,
yPos: null
});
},
/*
* Handles taps that move the current caret around in text edits,
* clear active selection and focus when neccessary, or change
* modes.
* modes. Only active afer SelectionHandlerUI is initialized.
*/
_onClick: function(aEvent) {
if (this.layerMode == kChromeLayer && this._targetIsEditable) {

View File

@ -9,6 +9,10 @@
min-width: 50px;
}
#sources-pane > tabs {
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-and-editor-splitter {
-moz-border-start-color: transparent;
}
@ -20,7 +24,7 @@
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-toolbar .devtools-toolbarbutton {
#sources-toolbar > #sources-controls > .devtools-toolbarbutton {
min-width: 32px;
}
@ -87,15 +91,23 @@
padding: 2px;
}
.list-widget-item:not(.selected):not(.empty):hover {
.theme-light .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.85)), Highlight;
}
.list-widget-item.selected.light {
.theme-light .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.85), rgba(255,255,255,0.8)), Highlight;
color: #000;
}
.theme-dark .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0.05));
}
.theme-dark .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.025));
}
.list-widget-item.selected {
background: Highlight;
color: HighlightText;
@ -106,21 +118,52 @@
padding: 2px;
}
/* Stack frames view */
/* Breadcrumbs stack frames view */
.breadcrumbs-widget-item {
max-width: none;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
.dbg-stackframe-menuitem[checked] {
margin-top: 3px;
margin-bottom: 3px;
outline: 1px solid #eee;
font-weight: 600;
/* Classic stack frames view */
.dbg-classic-stackframe {
display: block;
padding: 4px;
}
.dbg-stackframe-menuitem-details {
-moz-padding-start: 16px;
.dbg-classic-stackframe-title {
font-weight: 600;
color: #046;
}
.dbg-classic-stackframe-details:-moz-locale-dir(ltr) {
float: right;
}
.dbg-classic-stackframe-details:-moz-locale-dir(rtl) {
float: left;
}
.dbg-classic-stackframe-details-url {
max-width: 90%;
text-align: end;
color: #666;
}
.dbg-classic-stackframe-details-sep {
color: #aaa;
}
.dbg-classic-stackframe-details-line {
color: #58b;
}
#callstack-list .side-menu-widget-item.selected label {
color: #fff;
}
/* Sources and breakpoints view */
@ -180,8 +223,9 @@
padding: 0 !important;
}
#instruments-pane > tabpanels > tabpanel {
background: #fff;
#instruments-pane .side-menu-widget-container,
#instruments-pane .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}
/* Watch expressions view */
@ -203,6 +247,7 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
color: inherit;
}
/* Event listeners view */
@ -227,6 +272,10 @@
color: #666;
}
#event-listeners .side-menu-widget-item.selected {
background: none !important;
}
/* Searchbox and the search operations help panel */
#searchbox {
@ -380,6 +429,11 @@
/* Toolbar controls */
.devtools-sidebar-tabs > tabs > tab {
min-height: 25px !important;
padding: 0 !important;
}
#resumption-panel-desc {
width: 200px;
}
@ -468,12 +522,17 @@
max-height: 80vh;
}
#body[layout=vertical] #sources-pane > tabs {
-moz-border-end: none;
}
#body[layout=vertical] #instruments-pane {
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar. */
}
#body[layout=vertical] .side-menu-widget-container {
#body[layout=vertical] .side-menu-widget-container,
#body[layout=vertical] .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}

View File

@ -312,6 +312,10 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-container {
box-shadow: none !important;
}
.side-menu-widget-item[odd] {
background: rgba(255,255,255,0.05);
}
@ -363,10 +367,6 @@ box.requests-menu-status[code^="5"] {
-moz-padding-start: 3px;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #10c !important;
}
/* Headers tabpanel */
#headers-summary-status,

View File

@ -281,15 +281,17 @@
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
.side-menu-widget-container:-moz-locale-dir(ltr),
.side-menu-widget-empty-notice-container:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(rtl) {
.side-menu-widget-container:-moz-locale-dir(rtl),
.side-menu-widget-empty-notice-container:-moz-locale-dir(rtl) {
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
.side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
@ -328,7 +330,9 @@
.side-menu-widget-item[theme="light"] {
border-top: 1px solid hsla(210,8%,75%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
margin-top: -1px;
margin-bottom: -1px;
}
.side-menu-widget-item[theme="dark"]:last-of-type {
@ -339,15 +343,11 @@
box-shadow: inset 0 -1px 0 hsla(210,8%,75%,.25);
}
.side-menu-widget-item[theme="dark"].selected {
.side-menu-widget-item.selected {
background: linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15);
}
.side-menu-widget-item[theme="light"].selected {
/* Nothing here yet */
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow {
background-size: auto, 1px 100%;
background-repeat: no-repeat;
@ -432,10 +432,6 @@
/* VariablesView */
.variables-view-container {
background: #fff;
}
.variables-view-empty-notice {
color: GrayText;
padding: 2px;
@ -445,11 +441,6 @@
color: #fff;
}
.variables-view-scope:focus > .title {
background: Highlight;
color: HighlightText;
}
.variables-view-scope > .variables-view-element-details:not(:empty) {
-moz-margin-start: 2px;
-moz-margin-end: 1px;
@ -458,13 +449,12 @@
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
transition: background 1s ease-in-out, color 1s ease-in-out;
}
.variable-or-property[changed] {
background: rgba(255,255,0,0.65);
transition-duration: 0.4s;
color: black;
transition-duration: .4s;
}
.variable-or-property > .title > .value {
@ -473,12 +463,6 @@
-moz-padding-end: 4px;
}
.variable-or-property:focus > .title {
background: Highlight;
color: HighlightText;
border-radius: 4px;
}
.variable-or-property[editable] > .title > .value {
cursor: text;
}
@ -495,52 +479,22 @@
}
.variables-view-variable:not(:last-child) {
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(128, 128, 128, .15);
}
.variables-view-variable > .title > .name {
font-weight: 600;
}
.variables-view-variable:not(:focus) > .title > .name {
color: #048;
}
.variables-view-property:not(:focus) > .title > .name {
color: #881090;
}
/* Token value colors */
.variable-or-property:not(:focus) > .title > .token-undefined {
color: #bbb;
}
.variable-or-property:not(:focus) > .title > .token-null {
color: #999;
}
.variable-or-property:not(:focus) > .title > .token-boolean {
color: #10c;
}
.variable-or-property:not(:focus) > .title > .token-number {
color: #c00;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #282;
}
.variable-or-property:not(:focus) > .title > .token-other {
color: #333;
.variable-or-property:focus > .title > label {
color: inherit !important;
}
/* Custom configurable/enumerable/writable or frozen/sealed/extensible
* variables and properties */
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]):not([scope]) > .title > .name {
opacity: 0.5;
opacity: 0.6;
}
.variable-or-property[non-configurable] > .title > .name {
@ -551,6 +505,10 @@
border-bottom: 1px dashed #f99;
}
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property-non-writable-icon {
background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
width: 16px;
@ -577,27 +535,6 @@
color: #666;
}
/* Special variables and properties */
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[exception]:not(:focus) > .title > .name {
color: #a00;
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[scope]:not(:focus) > .title > .name {
color: #00a;
text-shadow: 0 0 8px #ccf;
}
/* Aligned values */
.variables-view-container[aligned-values] .title > .separator {
@ -634,7 +571,7 @@
.variable-or-property[non-configurable] > tooltip > label[value=configurable],
.variable-or-property[non-writable] > tooltip > label[value=writable],
.variable-or-property[non-extensible] > tooltip > label[value=extensible] {
color: #f44;
color: #800;
text-decoration: line-through;
}
@ -680,14 +617,13 @@
.element-name-input {
-moz-margin-start: -2px !important;
-moz-margin-end: 2px !important;
color: #048;
font-weight: 600;
}
.element-value-input,
.element-name-input {
border: 1px solid #999 !important;
box-shadow: 1px 2px 4px #aaa;
border: 1px solid rgba(128, 128, 128, .5) !important;
color: inherit;
}
/* Variables and properties searching */

View File

@ -3594,11 +3594,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
#navigator-toolbox[inFullscreen]:not(:-moz-lwtheme)::before {
height: calc(@tabHeight@ + 11px) !important;
}
#main-window[inFullscreen][privatebrowsingmode=temporary],
#main-window[inFullscreen]:-moz-lwtheme {
/* This additional padding matches the change in height in the pseudo-element
* above. The rules combined force the top 22px of the background image to
* be hidden, so there image doesn't jump around with the loss of the titlebar */
* above. */
padding-top: 11px;
}
#main-window[inFullscreen]:not([privatebrowsingmode=temporary]):-moz-lwtheme {
/* In combination with the previous rule, forces the top 22px of the
* background image to be hidden, so the image doesn't jump around with
* the loss of the titlebar. */
background-position: right -11px;
}
}

View File

@ -11,6 +11,10 @@
min-width: 50px;
}
#sources-pane > tabs {
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-and-editor-splitter {
-moz-border-start-color: transparent;
}
@ -22,7 +26,7 @@
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-toolbar .devtools-toolbarbutton {
#sources-toolbar > #sources-controls > .devtools-toolbarbutton {
min-width: 32px;
}
@ -89,15 +93,23 @@
padding: 2px;
}
.list-widget-item:not(.selected):not(.empty):hover {
.theme-light .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.85)), Highlight;
}
.list-widget-item.selected.light {
.theme-light .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.85), rgba(255,255,255,0.8)), Highlight;
color: #000;
}
.theme-dark .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0.05));
}
.theme-dark .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.025));
}
.list-widget-item.selected {
background: Highlight;
color: HighlightText;
@ -108,21 +120,52 @@
padding: 2px;
}
/* Stack frames view */
/* Breadcrumbs stack frames view */
.breadcrumbs-widget-item {
max-width: none;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
.dbg-stackframe-menuitem[checked] {
margin-top: 3px;
margin-bottom: 3px;
outline: 1px solid #eee;
font-weight: 600;
/* Classic stack frames view */
.dbg-classic-stackframe {
display: block;
padding: 4px;
}
.dbg-stackframe-menuitem-details {
-moz-padding-start: 16px;
.dbg-classic-stackframe-title {
font-weight: 600;
color: #046;
}
.dbg-classic-stackframe-details:-moz-locale-dir(ltr) {
float: right;
}
.dbg-classic-stackframe-details:-moz-locale-dir(rtl) {
float: left;
}
.dbg-classic-stackframe-details-url {
max-width: 90%;
text-align: end;
color: #666;
}
.dbg-classic-stackframe-details-sep {
color: #aaa;
}
.dbg-classic-stackframe-details-line {
color: #58b;
}
#callstack-list .side-menu-widget-item.selected label {
color: #fff;
}
/* Sources and breakpoints view */
@ -182,8 +225,9 @@
padding: 0 !important;
}
#instruments-pane > tabpanels > tabpanel {
background: #fff;
#instruments-pane .side-menu-widget-container,
#instruments-pane .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}
/* Watch expressions view */
@ -205,6 +249,7 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
color: inherit;
}
/* Event listeners view */
@ -229,6 +274,10 @@
color: #666;
}
#event-listeners .side-menu-widget-item.selected {
background: none !important;
}
/* Searchbox and the search operations help panel */
#searchbox {
@ -382,6 +431,11 @@
/* Toolbar controls */
.devtools-sidebar-tabs > tabs > tab {
min-height: 1em !important;
padding: 0 !important;
}
#resumption-panel-desc {
width: 200px;
}
@ -470,12 +524,17 @@
max-height: 80vh;
}
#body[layout=vertical] #sources-pane > tabs {
-moz-border-end: none;
}
#body[layout=vertical] #instruments-pane {
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar. */
}
#body[layout=vertical] .side-menu-widget-container {
#body[layout=vertical] .side-menu-widget-container,
#body[layout=vertical] .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}

View File

@ -312,6 +312,10 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-container {
box-shadow: none !important;
}
.side-menu-widget-item[odd] {
background: rgba(255,255,255,0.05);
}
@ -363,10 +367,6 @@ box.requests-menu-status[code^="5"] {
-moz-padding-start: 3px;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #10c !important;
}
/* Headers tabpanel */
#headers-summary-status,

View File

@ -281,15 +281,17 @@
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
.side-menu-widget-container:-moz-locale-dir(ltr),
.side-menu-widget-empty-notice-container:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(rtl) {
.side-menu-widget-container:-moz-locale-dir(rtl),
.side-menu-widget-empty-notice-container:-moz-locale-dir(rtl) {
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
.side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
@ -328,7 +330,9 @@
.side-menu-widget-item[theme="light"] {
border-top: 1px solid hsla(210,8%,75%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
margin-top: -1px;
margin-bottom: -1px;
}
.side-menu-widget-item[theme="dark"]:last-of-type {
@ -339,15 +343,11 @@
box-shadow: inset 0 -1px 0 hsla(210,8%,75%,.25);
}
.side-menu-widget-item[theme="dark"].selected {
.side-menu-widget-item.selected {
background: linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15);
}
.side-menu-widget-item[theme="light"].selected {
/* Nothing here yet */
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow {
background-size: auto, 1px 100%;
background-repeat: no-repeat;
@ -426,10 +426,6 @@
/* VariablesView */
.variables-view-container {
background: #fff;
}
.variables-view-empty-notice {
color: GrayText;
padding: 2px;
@ -439,11 +435,6 @@
color: #fff;
}
.variables-view-scope:focus > .title {
background: Highlight;
color: HighlightText;
}
.variables-view-scope > .variables-view-element-details:not(:empty) {
-moz-margin-start: 2px;
-moz-margin-end: 1px;
@ -452,13 +443,12 @@
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
transition: background 1s ease-in-out, color 1s ease-in-out;
}
.variable-or-property[changed] {
background: rgba(255,255,0,0.65);
transition-duration: 0.4s;
color: black;
transition-duration: .4s;
}
.variable-or-property > .title > .value {
@ -467,12 +457,6 @@
-moz-padding-end: 4px;
}
.variable-or-property:focus > .title {
background: Highlight;
color: HighlightText;
border-radius: 4px;
}
.variable-or-property[editable] > .title > .value {
cursor: text;
}
@ -489,52 +473,22 @@
}
.variables-view-variable:not(:last-child) {
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(128, 128, 128, .15);
}
.variables-view-variable > .title > .name {
font-weight: 600;
}
.variables-view-variable:not(:focus) > .title > .name {
color: #048;
}
.variables-view-property:not(:focus) > .title > .name {
color: #881090;
}
/* Token value colors */
.variable-or-property:not(:focus) > .title > .token-undefined {
color: #bbb;
}
.variable-or-property:not(:focus) > .title > .token-null {
color: #999;
}
.variable-or-property:not(:focus) > .title > .token-boolean {
color: #10c;
}
.variable-or-property:not(:focus) > .title > .token-number {
color: #c00;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #282;
}
.variable-or-property:not(:focus) > .title > .token-other {
color: #333;
.variable-or-property:focus > .title > label {
color: inherit !important;
}
/* Custom configurable/enumerable/writable or frozen/sealed/extensible
* variables and properties */
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]):not([scope]) > .title > .name {
opacity: 0.5;
opacity: 0.6;
}
.variable-or-property[non-configurable] > .title > .name {
@ -545,6 +499,10 @@
border-bottom: 1px dashed #f99;
}
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property-non-writable-icon {
background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
width: 16px;
@ -571,27 +529,6 @@
color: #666;
}
/* Special variables and properties */
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[exception]:not(:focus) > .title > .name {
color: #a00;
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[scope]:not(:focus) > .title > .name {
color: #00a;
text-shadow: 0 0 8px #ccf;
}
/* Aligned values */
.variables-view-container[aligned-values] .title > .separator {
@ -674,14 +611,13 @@
.element-name-input {
-moz-margin-start: -2px !important;
-moz-margin-end: 2px !important;
color: #048;
font-weight: 600;
}
.element-value-input,
.element-name-input {
border: 1px solid #999 !important;
box-shadow: 1px 2px 4px #aaa;
border: 1px solid rgba(128, 128, 128, .5) !important;
color: inherit;
}
/* Variables and properties searching */

View File

@ -51,7 +51,8 @@
background-color: rgba(0,0,0,0.5);
}
.theme-bg-contrast { /* contrast bg color to attract attention on a container */
.theme-bg-contrast,
.variable-or-property[changed] { /* contrast bg color to attract attention on a container */
background: #a18650;
}
@ -73,7 +74,9 @@
.theme-comment,
.cm-s-mozilla .cm-meta,
.cm-s-mozilla .cm-hr,
.cm-s-mozilla .cm-comment { /* grey */
.cm-s-mozilla .cm-comment,
.variable-or-property .token-undefined,
.variable-or-property .token-null { /* grey */
color: #5c6773;
}
@ -88,7 +91,9 @@
}
.theme-fg-color1,
.cm-s-mozilla .cm-number { /* green */
.cm-s-mozilla .cm-number,
.variable-or-property .token-number,
.variable-or-property[return] > .title > .name { /* green */
color: #5c9966;
}
@ -97,14 +102,18 @@
.cm-s-mozilla .cm-variable,
.cm-s-mozilla .cm-def,
.cm-s-mozilla .cm-property,
.cm-s-mozilla .cm-qualifier { /* blue */
.cm-s-mozilla .cm-qualifier,
.variables-view-variable > .title > .name,
.variable-or-property[scope] > .title > .name { /* blue */
color: #3689b2;
}
.theme-fg-color3,
.cm-s-mozilla .cm-builtin,
.cm-s-mozilla .cm-tag,
.cm-s-mozilla .cm-header { /* pink/lavender */
.cm-s-mozilla .cm-header,
.variables-view-property > .title > .name,
.variable-or-property[safe-getter] > .title > .name { /* pink/lavender */
color: #a673bf;
}
@ -120,14 +129,17 @@
.theme-fg-color6,
.cm-s-mozilla .cm-string,
.cm-s-mozilla .cm-string-2 { /* Orange */
.cm-s-mozilla .cm-string-2,
.variable-or-property .token-string { /* Orange */
color: #b26b47;
}
.theme-fg-color7,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error { /* Red */
.cm-s-mozilla .cm-error,
.variable-or-property .token-boolean,
.variable-or-property[exception] > .title > .name { /* Red */
color: #bf5656;
}
@ -148,6 +160,12 @@
box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
}
.variables-view-scope:focus > .title,
.variable-or-property:focus > .title {
background: #3689b2; /* fg-color2 */
color: white;
}
/* CodeMirror specific styles.
* Best effort to match the existing theme, some of the colors
* are duplicated here to prevent weirdness in the main theme. */

View File

@ -51,7 +51,8 @@
background: #EFEFEF;
}
.theme-bg-contrast { /* contrast bg color to attract attention on a container */
.theme-bg-contrast,
.variable-or-property[changed] { /* contrast bg color to attract attention on a container */
background: #a18650;
}
@ -72,7 +73,9 @@
.theme-comment,
.cm-s-mozilla .cm-meta,
.cm-s-mozilla .cm-hr,
.cm-s-mozilla .cm-comment { /* grey */
.cm-s-mozilla .cm-comment,
.variable-or-property .token-undefined,
.variable-or-property .token-null { /* grey */
color: hsl(90,2%,46%);
}
@ -87,7 +90,9 @@
}
.theme-fg-color1,
.cm-s-mozilla .cm-number { /* green */
.cm-s-mozilla .cm-number,
.variable-or-property .token-number,
.variable-or-property[return] > .title > .name { /* green */
color: hsl(72,100%,27%);
}
@ -96,14 +101,18 @@
.cm-s-mozilla .cm-builtin,
.cm-s-mozilla .cm-def,
.cm-s-mozilla .cm-property,
.cm-s-mozilla .cm-qualifier { /* blue */
.cm-s-mozilla .cm-qualifier,
.variables-view-variable > .title > .name,
.variable-or-property[scope] > .title > .name { /* blue */
color: hsl(208,56%,40%);
}
.theme-fg-color3,
.cm-s-mozilla .cm-variable,
.cm-s-mozilla .cm-tag,
.cm-s-mozilla .cm-header { /* dark blue */
.cm-s-mozilla .cm-header,
.variables-view-property > .title > .name,
.variable-or-property[safe-getter] > .title > .name { /* dark blue */
color: hsl(208,81%,21%)
}
@ -119,14 +128,17 @@
.theme-fg-color6,
.cm-s-mozilla .cm-string,
.cm-s-mozilla .cm-string-2 { /* Orange */
.cm-s-mozilla .cm-string-2,
.variable-or-property .token-string { /* Orange */
color: hsl(24,85%,39%);
}
.theme-fg-color7,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error { /* Red */
.cm-s-mozilla .cm-error,
.variable-or-property .token-boolean,
.variable-or-property[exception] > .title > .name { /* Red */
color: #bf5656;
}
@ -147,6 +159,12 @@
box-shadow: 0 0 0 1px #EFEFEF;
}
.variables-view-scope:focus > .title,
.variable-or-property:focus > .title {
background: hsl(208,56%,40%); /* fg-color2 */
color: white;
}
/* CodeMirror specific styles.
* Best effort to match the existing theme, some of the colors
* are duplicated here to prevent weirdness in the main theme. */

View File

@ -260,11 +260,15 @@
}
.devtools-sidebar-tabs > tabs > tab {
background-size: calc(100% - 2px) 100%, 1px 100%;
background-size: calc(100% - 1px) 100%, 1px 100%;
background-repeat: no-repeat;
background-position: 1px, 0;
}
.devtools-sidebar-tabs > tabs > tab:not(:last-of-type) {
background-size: calc(100% - 2px) 100%, 1px 100%;
}
.devtools-sidebar-tabs:-moz-locale-dir(rtl) > tabs > tab {
background-position: calc(100% - 1px), 100%;
}

View File

@ -291,11 +291,11 @@ a {
.inlined-variables-view iframe {
display: block;
flex: 1;
margin-top: 5px;
margin-bottom: 15px;
-moz-margin-end: 15px;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 0 12px #dfdfdf;
border: 1px solid rgba(128, 128, 128, .5);
border-radius: 3px;
}
#webconsole-sidebar > tabs {
@ -354,6 +354,10 @@ a {
background: #131c26; /* mainBackgroundColor */
}
.theme-dark .inlined-variables-view iframe {
border-color: #333;
}
.theme-light .jsterm-input-container {
background-color: #fff; /* mainBackgroundColor */
border-color: ThreeDShadow;
@ -370,3 +374,8 @@ a {
.theme-light .navigation-marker .url {
background: #fff; /* mainBackgroundColor */
}
.theme-light .inlined-variables-view iframe {
border-color: #ccc;
}

View File

@ -9,6 +9,10 @@
min-width: 50px;
}
#sources-pane > tabs {
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-and-editor-splitter {
-moz-border-start-color: transparent;
}
@ -20,7 +24,7 @@
-moz-border-end: 1px solid #222426; /* Match the sources list's dark margin. */
}
#sources-toolbar .devtools-toolbarbutton {
#sources-toolbar > #sources-controls > .devtools-toolbarbutton {
min-width: 32px;
}
@ -87,15 +91,23 @@
padding: 2px;
}
.list-widget-item:not(.selected):not(.empty):hover {
.theme-light .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.85)), Highlight;
}
.list-widget-item.selected.light {
.theme-light .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.85), rgba(255,255,255,0.8)), Highlight;
color: #000;
}
.theme-dark .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0.05));
}
.theme-dark .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.025));
}
.list-widget-item.selected {
background: Highlight;
color: HighlightText;
@ -106,21 +118,52 @@
padding: 2px;
}
/* Stack frames view */
/* Breadcrumbs stack frames view */
.breadcrumbs-widget-item {
max-width: none;
}
.dbg-stackframe-details {
-moz-padding-start: 4px;
}
.dbg-stackframe-menuitem[checked] {
margin-top: 3px;
margin-bottom: 3px;
outline: 1px solid #eee;
font-weight: 600;
/* Classic stack frames view */
.dbg-classic-stackframe {
display: block;
padding: 4px;
}
.dbg-stackframe-menuitem-details {
-moz-padding-start: 16px;
.dbg-classic-stackframe-title {
font-weight: 600;
color: #046;
}
.dbg-classic-stackframe-details:-moz-locale-dir(ltr) {
float: right;
}
.dbg-classic-stackframe-details:-moz-locale-dir(rtl) {
float: left;
}
.dbg-classic-stackframe-details-url {
max-width: 90%;
text-align: end;
color: #666;
}
.dbg-classic-stackframe-details-sep {
color: #aaa;
}
.dbg-classic-stackframe-details-line {
color: #58b;
}
#callstack-list .side-menu-widget-item.selected label {
color: #fff;
}
/* Sources and breakpoints view */
@ -180,8 +223,9 @@
padding: 0 !important;
}
#instruments-pane > tabpanels > tabpanel {
background: #fff;
#instruments-pane .side-menu-widget-container,
#instruments-pane .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}
/* Watch expressions view */
@ -203,6 +247,7 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
color: inherit;
}
/* Event listeners view */
@ -227,6 +272,10 @@
color: #666;
}
#event-listeners .side-menu-widget-item.selected {
background: none !important;
}
/* Searchbox and the search operations help panel */
#searchbox {
@ -380,6 +429,11 @@
/* Toolbar controls */
.devtools-sidebar-tabs > tabs > tab {
min-height: 25px !important;
padding: 0 !important;
}
#resumption-panel-desc {
width: 200px;
}
@ -473,12 +527,17 @@
max-height: 80vh;
}
#body[layout=vertical] #sources-pane > tabs {
-moz-border-end: none;
}
#body[layout=vertical] #instruments-pane {
margin: 0 !important;
/* To prevent all the margin hacks to hide the sidebar. */
}
#body[layout=vertical] .side-menu-widget-container {
#body[layout=vertical] .side-menu-widget-container,
#body[layout=vertical] .side-menu-widget-empty-notice-container {
box-shadow: none !important;
}

View File

@ -312,6 +312,10 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-container {
box-shadow: none !important;
}
.side-menu-widget-item[odd] {
background: rgba(255,255,255,0.05);
}
@ -363,10 +367,6 @@ box.requests-menu-status[code^="5"] {
-moz-padding-start: 3px;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #10c !important;
}
/* Headers tabpanel */
#headers-summary-status,

View File

@ -285,15 +285,17 @@
/* SideMenuWidget container */
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(ltr) {
.side-menu-widget-container:-moz-locale-dir(ltr),
.side-menu-widget-empty-notice-container:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true]:-moz-locale-dir(rtl) {
.side-menu-widget-container:-moz-locale-dir(rtl),
.side-menu-widget-empty-notice-container:-moz-locale-dir(rtl) {
box-shadow: inset 1px 0 0 #222426;
}
.side-menu-widget-container[with-arrows=true] .side-menu-widget-group {
.side-menu-widget-group {
/* To allow visibility of the dark margin shadow. */
-moz-margin-end: 1px;
}
@ -332,7 +334,9 @@
.side-menu-widget-item[theme="light"] {
border-top: 1px solid hsla(210,8%,75%,.25);
border-bottom: 1px solid hsla(210,16%,76%,.1);
margin-top: -1px;
margin-bottom: -1px;
}
.side-menu-widget-item[theme="dark"]:last-of-type {
@ -343,15 +347,11 @@
box-shadow: inset 0 -1px 0 hsla(210,8%,75%,.25);
}
.side-menu-widget-item[theme="dark"].selected {
.side-menu-widget-item.selected {
background: linear-gradient(hsl(206,61%,40%), hsl(206,61%,31%)) repeat-x top left !important;
box-shadow: inset 0 1px 0 hsla(210,40%,83%,.15);
}
.side-menu-widget-item[theme="light"].selected {
/* Nothing here yet */
}
.side-menu-widget-item.selected > .side-menu-widget-item-arrow {
background-size: auto, 1px 100%;
background-repeat: no-repeat;
@ -429,10 +429,6 @@
/* VariablesView */
.variables-view-container {
background: #fff;
}
.variables-view-empty-notice {
color: GrayText;
padding: 2px;
@ -442,11 +438,6 @@
color: #fff;
}
.variables-view-scope:focus > .title {
background: Highlight;
color: HighlightText;
}
.variables-view-scope > .variables-view-element-details:not(:empty) {
-moz-margin-start: 2px;
-moz-margin-end: 1px;
@ -455,13 +446,12 @@
/* Generic traits applied to both variables and properties */
.variable-or-property {
transition: background 1s ease-in-out;
color: #000;
transition: background 1s ease-in-out, color 1s ease-in-out;
}
.variable-or-property[changed] {
background: rgba(255,255,0,0.65);
transition-duration: 0.4s;
color: black;
transition-duration: .4s;
}
.variable-or-property > .title > .value {
@ -470,12 +460,6 @@
-moz-padding-end: 4px;
}
.variable-or-property:focus > .title {
background: Highlight;
color: HighlightText;
border-radius: 4px;
}
.variable-or-property[editable] > .title > .value {
cursor: text;
}
@ -492,52 +476,22 @@
}
.variables-view-variable:not(:last-child) {
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(128, 128, 128, .15);
}
.variables-view-variable > .title > .name {
font-weight: 600;
}
.variables-view-variable:not(:focus) > .title > .name {
color: #048;
}
.variables-view-property:not(:focus) > .title > .name {
color: #881090;
}
/* Token value colors */
.variable-or-property:not(:focus) > .title > .token-undefined {
color: #bbb;
}
.variable-or-property:not(:focus) > .title > .token-null {
color: #999;
}
.variable-or-property:not(:focus) > .title > .token-boolean {
color: #10c;
}
.variable-or-property:not(:focus) > .title > .token-number {
color: #c00;
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #282;
}
.variable-or-property:not(:focus) > .title > .token-other {
color: #333;
.variable-or-property:focus > .title > label {
color: inherit !important;
}
/* Custom configurable/enumerable/writable or frozen/sealed/extensible
* variables and properties */
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]):not([scope]) > .title > .name {
opacity: 0.5;
opacity: 0.6;
}
.variable-or-property[non-configurable] > .title > .name {
@ -548,6 +502,10 @@
border-bottom: 1px dashed #f99;
}
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property-non-writable-icon {
background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
width: 16px;
@ -574,27 +532,6 @@
color: #666;
}
/* Special variables and properties */
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[exception]:not(:focus) > .title > .name {
color: #a00;
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[scope]:not(:focus) > .title > .name {
color: #00a;
text-shadow: 0 0 8px #ccf;
}
/* Aligned values */
.variables-view-container[aligned-values] .title > .separator {
@ -677,14 +614,13 @@
.element-name-input {
-moz-margin-start: -2px !important;
-moz-margin-end: 2px !important;
color: #048;
font-weight: 600;
}
.element-value-input,
.element-name-input {
border: 1px solid #999 !important;
box-shadow: 1px 2px 4px #aaa;
border: 1px solid rgba(128, 128, 128, .5) !important;
color: inherit;
}
/* Variables and properties searching */

31
build/autoconf/icu.m4 Normal file
View File

@ -0,0 +1,31 @@
dnl This Source Code Form is subject to the terms of the Mozilla Public
dnl License, v. 2.0. If a copy of the MPL was not distributed with this
dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
dnl Set the MOZ_ICU_VERSION variable to denote the current version of the
dnl ICU library, and also the MOZ_SHARED_ICU which would be true if we are
dnl linking against a shared library of ICU, either one that we build from
dnl our copy of ICU or the system provided library.
AC_DEFUN([MOZ_CONFIG_ICU], [
icudir="$_topsrcdir/intl/icu/source"
if test ! -d "$icudir"; then
icudir="$_topsrcdir/../../intl/icu/source"
if test ! -d "$icudir"; then
AC_MSG_ERROR([Cannot find the ICU directory])
fi
fi
version=`sed -n 's/^[[:space:]]*#[[:space:]]*define[[:space:]][[:space:]]*U_ICU_VERSION_MAJOR_NUM[[:space:]][[:space:]]*\([0-9][0-9]*\)[[:space:]]*$/\1/p' "$icudir/common/unicode/uvernum.h"`
if test x"$version" = x; then
AC_MSG_ERROR([cannot determine icu version number from uvernum.h header file $lineno])
fi
MOZ_ICU_VERSION="$version"
if test -n "${JS_SHARED_LIBRARY}${MOZ_NATIVE_ICU}"; then
MOZ_SHARED_ICU=1
fi
AC_SUBST(MOZ_ICU_VERSION)
AC_SUBST(MOZ_SHARED_ICU)
])

View File

@ -4,14 +4,12 @@
package org.mozilla.gecko;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.GeckoLayerClient.DrawListener;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.util.GeckoEventListener;
import android.app.Activity;
import android.app.Instrumentation;
@ -24,112 +22,65 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import org.json.JSONObject;
import com.jayway.android.robotium.solo.Solo;
import static org.mozilla.gecko.FennecNativeDriver.LogLevel;
public class FennecNativeActions implements Actions {
private static final String LOGTAG = "FennecNativeActions";
private Solo mSolo;
private Instrumentation mInstr;
private Activity mGeckoApp;
private Assert mAsserter;
// Objects for reflexive access of fennec classes.
private ClassLoader mClassLoader;
private Class mApiClass;
private Class mEventListenerClass;
private Class mDrawListenerClass;
private Method mRegisterEventListener;
private Method mUnregisterEventListener;
private Method mBroadcastEvent;
private Method mPreferencesGetEvent;
private Method mPreferencesObserveEvent;
private Method mPreferencesRemoveObserversEvent;
private Method mSetDrawListener;
private Method mQuerySql;
private Object mRobocopApi;
private static final String LOGTAG = "FennecNativeActions";
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) {
mSolo = robocop;
mInstr = instrumentation;
mGeckoApp = activity;
mAsserter = asserter;
// Set up reflexive access of java classes and methods.
try {
mClassLoader = activity.getClassLoader();
mApiClass = mClassLoader.loadClass("org.mozilla.gecko.RobocopAPI");
mEventListenerClass = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
mDrawListenerClass = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoLayerClient$DrawListener");
mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
mUnregisterEventListener = mApiClass.getMethod("unregisterEventListener", String.class, mEventListenerClass);
mBroadcastEvent = mApiClass.getMethod("broadcastEvent", String.class, String.class);
mPreferencesGetEvent = mApiClass.getMethod("preferencesGetEvent", Integer.TYPE, String[].class);
mPreferencesObserveEvent = mApiClass.getMethod("preferencesObserveEvent", Integer.TYPE, String[].class);
mPreferencesRemoveObserversEvent = mApiClass.getMethod("preferencesRemoveObserversEvent", Integer.TYPE);
mSetDrawListener = mApiClass.getMethod("setDrawListener", mDrawListenerClass);
mQuerySql = mApiClass.getMethod("querySql", String.class, String.class);
mRobocopApi = mApiClass.getConstructor(Activity.class).newInstance(activity);
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
}
class wakeInvocationHandler implements InvocationHandler {
private final GeckoEventExpecter mEventExpecter;
public wakeInvocationHandler(GeckoEventExpecter expecter) {
mEventExpecter = expecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
//Depending on the method, return a completely different type.
if(methodName.equals("toString")) {
return this.toString();
}
if(methodName.equals("equals")) {
return
args[0] == null ? false :
this.toString().equals(args[0].toString());
}
if(methodName.equals("clone")) {
return this;
}
if(methodName.equals("hashCode")) {
return 314;
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"Waking up on "+methodName);
mEventExpecter.notifyOfEvent(args);
return null;
}
GeckoLoader.loadSQLiteLibs(activity, activity.getApplication().getPackageResourcePath());
}
class GeckoEventExpecter implements RepeatedEventExpecter {
private final String mGeckoEvent;
private Object[] mRegistrationParams;
private boolean mEventEverReceived;
private String mEventData;
private BlockingQueue<String> mEventDataQueue;
private static final int MAX_WAIT_MS = 90000;
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
private volatile boolean mIsRegistered;
private final String mGeckoEvent;
private final GeckoEventListener mListener;
private volatile boolean mEventEverReceived;
private String mEventData;
private BlockingQueue<String> mEventDataQueue;
GeckoEventExpecter(final String geckoEvent) {
if (TextUtils.isEmpty(geckoEvent)) {
throw new IllegalArgumentException("geckoEvent must not be empty");
}
if (registrationParams == null || registrationParams.length == 0) {
throw new IllegalArgumentException("registrationParams must not be empty");
}
mGeckoEvent = geckoEvent;
mRegistrationParams = registrationParams;
mEventDataQueue = new LinkedBlockingQueue<String>();
final GeckoEventExpecter expecter = this;
mListener = new GeckoEventListener() {
@Override
public void handleMessage(final String event, final JSONObject message) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"handleMessage called for: " + event + "; expecting: " + mGeckoEvent);
mAsserter.is(event, mGeckoEvent, "Given message occurred for registered event");
expecter.notifyOfEvent(message);
}
};
GeckoAppShell.registerEventListener(mGeckoEvent, mListener);
mIsRegistered = true;
}
public void blockForEvent() {
@ -137,9 +88,10 @@ public class FennecNativeActions implements Actions {
}
private void blockForEvent(long millis, boolean failOnTimeout) {
if (mRegistrationParams == null) {
if (!mIsRegistered) {
throw new IllegalStateException("listener not registered");
}
try {
mEventData = mEventDataQueue.poll(millis, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
@ -161,12 +113,13 @@ public class FennecNativeActions implements Actions {
}
public void blockUntilClear(long millis) {
if (mRegistrationParams == null) {
if (!mIsRegistered) {
throw new IllegalStateException("listener not registered");
}
if (millis <= 0) {
throw new IllegalArgumentException("millis must be > 0");
}
// wait for at least one event
try {
mEventData = mEventDataQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS);
@ -205,139 +158,82 @@ public class FennecNativeActions implements Actions {
}
public void unregisterListener() {
if (mRegistrationParams == null) {
if (!mIsRegistered) {
throw new IllegalStateException("listener not registered");
}
try {
FennecNativeDriver.log(LogLevel.INFO, "EventExpecter: no longer listening for "+mGeckoEvent);
mUnregisterEventListener.invoke(mRobocopApi, mRegistrationParams);
mRegistrationParams = null;
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(LogLevel.INFO,
"EventExpecter: no longer listening for " + mGeckoEvent);
GeckoAppShell.unregisterEventListener(mGeckoEvent, mListener);
mIsRegistered = false;
}
public synchronized boolean eventReceived() {
public boolean eventReceived() {
return mEventEverReceived;
}
void notifyOfEvent(Object[] args) {
void notifyOfEvent(final JSONObject message) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"received event " + mGeckoEvent);
synchronized (this) {
mEventEverReceived = true;
}
"received event " + mGeckoEvent);
mEventEverReceived = true;
try {
mEventDataQueue.put(args[1].toString());
mEventDataQueue.put(message.toString());
} catch (InterruptedException e) {
FennecNativeDriver.log(LogLevel.ERROR,
"EventExpecter dropped event: "+args[1].toString());
FennecNativeDriver.log(LogLevel.ERROR, e);
"EventExpecter dropped event: " + message.toString(), e);
}
}
}
public RepeatedEventExpecter expectGeckoEvent(String geckoEvent) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"waiting for "+geckoEvent);
try {
Object[] finalParams = new Object[2];
finalParams[0] = geckoEvent;
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
Object proxy = Proxy.newProxyInstance(mClassLoader, new Class[] { mEventListenerClass }, wIH);
finalParams[1] = proxy;
mRegisterEventListener.invoke(mRobocopApi, finalParams);
return expecter;
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
return null;
public RepeatedEventExpecter expectGeckoEvent(final String geckoEvent) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, "waiting for " + geckoEvent);
return new GeckoEventExpecter(geckoEvent);
}
public void sendGeckoEvent(String geckoEvent, String data) {
try {
mBroadcastEvent.invoke(mRobocopApi, geckoEvent, data);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
}
private void sendPreferencesEvent(Method method, int requestId, String[] prefNames) {
try {
method.invoke(mRobocopApi, requestId, prefNames);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
public void sendGeckoEvent(final String geckoEvent, final String data) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(geckoEvent, data));
}
public void sendPreferencesGetEvent(int requestId, String[] prefNames) {
sendPreferencesEvent(mPreferencesGetEvent, requestId, prefNames);
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesGetEvent(requestId, prefNames));
}
public void sendPreferencesObserveEvent(int requestId, String[] prefNames) {
sendPreferencesEvent(mPreferencesObserveEvent, requestId, prefNames);
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesObserveEvent(requestId, prefNames));
}
public void sendPreferencesRemoveObserversEvent(int requestId) {
try {
mPreferencesRemoveObserversEvent.invoke(mRobocopApi, requestId);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;
DrawListenerProxy(PaintExpecter paintExpecter) {
mPaintExpecter = paintExpecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"Received drawFinished notification");
mPaintExpecter.notifyOfEvent(args);
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesRemoveObserversEvent(requestId));
}
class PaintExpecter implements RepeatedEventExpecter {
private boolean mPaintDone;
private boolean mListening;
private static final int MAX_WAIT_MS = 90000;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
Object proxy = Proxy.newProxyInstance(mClassLoader, new Class[] { mDrawListenerClass }, new DrawListenerProxy(this));
mSetDrawListener.invoke(mRobocopApi, proxy);
private boolean mPaintDone;
private boolean mListening;
private final GeckoLayerClient mLayerClient;
PaintExpecter() {
final PaintExpecter expecter = this;
mLayerClient = GeckoAppShell.getLayerView().getLayerClient();
mLayerClient.setDrawListener(new DrawListener() {
@Override
public void drawFinished() {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"Received drawFinished notification");
expecter.notifyOfEvent();
}
});
mListening = true;
}
void notifyOfEvent(Object[] args) {
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
private synchronized void notifyOfEvent() {
mPaintDone = true;
this.notifyAll();
}
private synchronized void blockForEvent(long millis, boolean failOnTimeout) {
@ -431,23 +327,16 @@ public class FennecNativeActions implements Actions {
if (!mListening) {
throw new IllegalStateException("listener not registered");
}
try {
FennecNativeDriver.log(LogLevel.INFO, "PaintExpecter: no longer listening for events");
mListening = false;
mSetDrawListener.invoke(mRobocopApi, (Object)null);
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(LogLevel.INFO,
"PaintExpecter: no longer listening for events");
mLayerClient.setDrawListener(null);
mListening = false;
}
}
public RepeatedEventExpecter expectPaint() {
try {
return new PaintExpecter();
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
return null;
}
return new PaintExpecter();
}
public void sendSpecialKey(SpecialKey button) {
@ -495,14 +384,7 @@ public class FennecNativeActions implements Actions {
mSolo.drag(startingX, endingX, startingY, endingY, 10);
}
public Cursor querySql(String dbPath, String sql) {
try {
return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql);
} catch(InvocationTargetException ex) {
Log.e(LOGTAG, "Error invoking method", ex);
} catch(IllegalAccessException ex) {
Log.e(LOGTAG, "Error using field", ex);
}
return null;
public Cursor querySql(final String dbPath, final String sql) {
return new SQLiteBridge(dbPath).rawQuery(sql, null);
}
}

View File

@ -4,6 +4,10 @@
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanningPerfAPI;
import org.mozilla.gecko.util.GeckoEventListener;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
@ -20,11 +24,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.view.View;
@ -46,18 +45,6 @@ public class FennecNativeDriver implements Driver {
private static String mLogFile = null;
private static LogLevel mLogLevel = LogLevel.INFO;
// Objects for reflexive access of fennec classes.
private ClassLoader mClassLoader;
private Class mApiClass;
private Class mEventListenerClass;
private Method mRegisterEventListener;
private Method mGetPixels;
private Method mStartFrameRecording;
private Method mStopFrameRecording;
private Method mStartCheckerboardRecording;
private Method mStopCheckerboardRecording;
private Object mRobocopApi;
public enum LogLevel {
DEBUG(1),
INFO(2),
@ -83,25 +70,6 @@ public class FennecNativeDriver implements Driver {
// Set up table of fennec_ids.
mLocators = convertTextToTable(getFile(mRootPath + "/fennec_ids.txt"));
// Set up reflexive access of java classes and methods.
try {
mClassLoader = activity.getClassLoader();
mApiClass = mClassLoader.loadClass("org.mozilla.gecko.RobocopAPI");
mEventListenerClass = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
mGetPixels = mApiClass.getMethod("getViewPixels", View.class);
mStartFrameRecording = mApiClass.getDeclaredMethod("startFrameTimeRecording");
mStopFrameRecording = mApiClass.getDeclaredMethod("stopFrameTimeRecording");
mStartCheckerboardRecording = mApiClass.getDeclaredMethod("startCheckerboardRecording");
mStopCheckerboardRecording = mApiClass.getDeclaredMethod("stopCheckerboardRecording");
mRobocopApi = mApiClass.getConstructor(Activity.class).newInstance(activity);
} catch (Exception e) {
log(LogLevel.ERROR, e);
}
}
//Information on the location of the Gecko Frame.
@ -172,99 +140,59 @@ public class FennecNativeDriver implements Driver {
}
public void startFrameRecording() {
try {
mStartFrameRecording.invoke(null);
} catch (IllegalAccessException e) {
log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
log(LogLevel.ERROR, e);
}
PanningPerfAPI.startFrameTimeRecording();
}
public int stopFrameRecording() {
try {
List<Long> frames = (List<Long>)mStopFrameRecording.invoke(null);
int badness = 0;
for (int i = 1; i < frames.size(); i++) {
long frameTime = frames.get(i) - frames.get(i - 1);
int delay = (int)(frameTime - FRAME_TIME_THRESHOLD);
// for each frame we miss, add the square of the delay. This
// makes large delays much worse than small delays.
if (delay > 0) {
badness += delay * delay;
}
final List<Long> frames = PanningPerfAPI.stopFrameTimeRecording();
int badness = 0;
for (int i = 1; i < frames.size(); i++) {
long frameTime = frames.get(i) - frames.get(i - 1);
int delay = (int)(frameTime - FRAME_TIME_THRESHOLD);
// for each frame we miss, add the square of the delay. This
// makes large delays much worse than small delays.
if (delay > 0) {
badness += delay * delay;
}
// Don't do any averaging of the numbers because really we want to
// know how bad the jank was at its worst
return badness;
} catch (IllegalAccessException e) {
log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
log(LogLevel.ERROR, e);
}
// higher values are worse, and the test failing is the worst!
return Integer.MAX_VALUE;
// Don't do any averaging of the numbers because really we want to
// know how bad the jank was at its worst
return badness;
}
public void startCheckerboardRecording() {
try {
mStartCheckerboardRecording.invoke(null);
} catch (IllegalAccessException e) {
log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
log(LogLevel.ERROR, e);
}
PanningPerfAPI.startCheckerboardRecording();
}
public float stopCheckerboardRecording() {
try {
List<Float> checkerboard = (List<Float>)mStopCheckerboardRecording.invoke(null);
float total = 0;
for (float val : checkerboard) {
total += val;
}
return total * 100.0f;
} catch (IllegalAccessException e) {
log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
log(LogLevel.ERROR, e);
final List<Float> checkerboard = PanningPerfAPI.stopCheckerboardRecording();
float total = 0;
for (float val : checkerboard) {
total += val;
}
return 0.0f;
return total * 100.0f;
}
private View getSurfaceView() {
ArrayList<View> views = mSolo.getCurrentViews();
try {
Class c = Class.forName("org.mozilla.gecko.gfx.LayerView");
for (View v : views) {
if (c.isInstance(v)) {
return v;
}
private LayerView getSurfaceView() {
final LayerView layerView = mSolo.getView(LayerView.class, 0);
if (layerView == null) {
log(LogLevel.WARN, "getSurfaceView could not find LayerView");
for (final View v : mSolo.getViews()) {
log(LogLevel.WARN, " View: " + v);
}
} catch (ClassNotFoundException e) {
log(LogLevel.ERROR, e);
}
log(LogLevel.WARN, "getSurfaceView could not find LayerView");
for (View v : views) {
log(LogLevel.WARN, v.toString());
}
return null;
return layerView;
}
public PaintedSurface getPaintedSurface() {
View view = getSurfaceView();
final LayerView view = getSurfaceView();
if (view == null) {
return null;
}
IntBuffer pixelBuffer;
try {
pixelBuffer = (IntBuffer)mGetPixels.invoke(mRobocopApi, view);
} catch (Exception e) {
log(LogLevel.ERROR, e);
return null;
}
final IntBuffer pixelBuffer = view.getPixels();
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
@ -312,27 +240,6 @@ public class FennecNativeDriver implements Driver {
public int mScrollHeight=0;
public int mPageHeight=10;
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {
try {
// Disect the JSON object into the appropriate variables
JSONObject jo = ((JSONObject)args[1]);
mScrollHeight = jo.getInt("y");
mHeight = jo.getInt("cheight");
// We don't want a height of 0. That means it's a bad response.
if (mHeight > 0) {
mPageHeight = jo.getInt("height");
}
} catch( Throwable e) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
"WARNING: ScrollReceived, but read wrong!");
}
return null;
}
}
public int getScrollHeight() {
return mScrollHeight;
}
@ -344,20 +251,23 @@ public class FennecNativeDriver implements Driver {
}
public void setupScrollHandling() {
//Setup scrollHandler to catch "robocop:scroll" events.
try {
Class [] interfaces = new Class[1];
interfaces[0] = mEventListenerClass;
Object[] finalParams = new Object[2];
finalParams[0] = "robocop:scroll";
finalParams[1] = Proxy.newProxyInstance(mClassLoader, interfaces, new scrollHandler());
mRegisterEventListener.invoke(mRobocopApi, finalParams);
} catch (IllegalAccessException e) {
log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
log(LogLevel.ERROR, e);
}
GeckoAppShell.registerEventListener("robocop:scroll", new GeckoEventListener() {
@Override
public void handleMessage(final String event, final JSONObject message) {
try {
mScrollHeight = message.getInt("y");
mHeight = message.getInt("cheight");
// We don't want a height of 0. That means it's a bad response.
if (mHeight > 0) {
mPageHeight = message.getInt("height");
}
} catch (JSONException e) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.WARN,
"WARNING: ScrollReceived, but message does not contain " +
"expected fields: " + e);
}
}
});
}
/**

View File

@ -27,3 +27,6 @@ if CONFIG['HOST_OS_ARCH'] != 'WINNT':
if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
DEFINES['GKMEDIAS_SHARED_LIBRARY'] = True
if CONFIG['MOZ_SHARED_ICU']:
DEFINES['MOZ_SHARED_ICU'] = True

View File

@ -1131,7 +1131,7 @@ kvm.h
spawn.h
err.h
xlocale.h
#if MOZ_NATIVE_ICU==1
#ifdef MOZ_SHARED_ICU
unicode/locid.h
unicode/numsys.h
unicode/ucal.h

View File

@ -3896,6 +3896,17 @@ if test -n "$MOZ_NATIVE_FFI"; then
MOZ_JS_STATIC_LIBS="$MOZ_JS_STATIC_LIBS $MOZ_FFI_LIBS"
fi
# split JS out by default to avoid VS2005 PGO crash (bug 591836).
if test "$OS_ARCH" = "WINNT"; then
JS_SHARED_LIBRARY=1
fi
MOZ_ARG_ENABLE_BOOL(shared-js,
[ --enable-shared-js
Create a shared JavaScript library.],
JS_SHARED_LIBRARY=1,
JS_SHARED_LIBRARY=)
dnl ========================================================
dnl System ICU Support
dnl ========================================================
@ -3961,7 +3972,7 @@ MOZ_MEDIA_NAVIGATOR=
MOZ_OMX_PLUGIN=
MOZ_VP8=
MOZ_VP8_ERROR_CONCEALMENT=
MOZ_VP8_ENCODER=
MOZ_VP8_ENCODER=1
MOZ_WEBSPEECH=1
VPX_AS=
VPX_ASFLAGS=
@ -5127,7 +5138,6 @@ if test -n "$MOZ_WEBRTC"; then
AC_DEFINE(MOZ_WEBRTC_ASSERT_ALWAYS)
MOZ_RAW=1
MOZ_VP8=1
MOZ_VP8_ENCODER=1
MOZ_VP8_ERROR_CONCEALMENT=1
dnl enable once Signaling lands
@ -5464,7 +5474,7 @@ if test -n "$MOZ_VP8" -a -z "$MOZ_NATIVE_LIBVPX"; then
;;
*:x86)
if $CC -E -dM -</dev/null | grep -q __ELF__; then
VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
VPX_ASFLAGS="-f elf32 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
fi
;;
@ -7727,19 +7737,7 @@ dnl =
dnl ========================================================
MOZ_ARG_HEADER(Static build options)
# split JS out by default to avoid VS2005 PGO crash (bug 591836).
if test "$OS_ARCH" = "WINNT"; then
ENABLE_SHARED_JS=1
fi
MOZ_ARG_ENABLE_BOOL(shared-js,
[ --enable-shared-js
Create a shared JavaScript library.],
ENABLE_SHARED_JS=1,
ENABLE_SHARED_JS=)
if test -n "$ENABLE_SHARED_JS"; then
JS_SHARED_LIBRARY=1
if test -n "$JS_SHARED_LIBRARY"; then
MOZ_JS_LIBS="$MOZ_JS_SHARED_LIBS"
else
MOZ_JS_LIBS="$MOZ_JS_STATIC_LIBS"
@ -8788,6 +8786,81 @@ HAVE_SYS_MOUNT_H
AC_SUBST(STLPORT_LIBS)
MOZ_ARG_WITH_STRING(intl-api,
[ --with-intl-api, --with-intl-api=build, --without-intl-api
Determine the status of the ECMAScript Internationalization API. The first
(or lack of any of these) builds and exposes the API. The second builds it
but doesn't use ICU or expose the API to script. The third doesn't build
ICU at all.],
_INTL_API=$withval,
_INTL_API=yes)
WITH_INTL="--with-intl-api=$_INTL_API"
ENABLE_INTL_API=
case "$_INTL_API" in
no)
;;
build)
ENABLE_INTL_API=1
;;
yes)
ENABLE_INTL_API=1
;;
*)
AC_MSG_ERROR([Invalid value passed to --with-intl-api: $_INTL_API])
;;
esac
if test -n "$ENABLE_INTL_API"; then
if test "$MOZ_BUILD_APP" = "browser"; then
WITH_INTL="--with-intl-api"
else
# Internationalization isn't built or exposed by default in non-desktop
# builds. Bugs to enable:
#
# Android: bug 864843
# B2G: bug 866301
WITH_INTL="--without-intl-api"
ENABLE_INTL_API=
fi
fi
dnl Settings for the implementation of the ECMAScript Internationalization API
if test -n "$ENABLE_INTL_API"; then
AC_DEFINE(ENABLE_INTL_API)
MOZ_CONFIG_ICU()
dnl Build ICU as a shared library for shared js builds.
if test -z "$MOZ_NATIVE_ICU" -a -n "$JS_SHARED_LIBRARY"; then
case "$OS_TARGET" in
WINNT)
ICU_LIB_NAMES="icuin icuuc icudt"
DBG_SUFFIX=
if test -n "$MOZ_DEBUG"; then
DBG_SUFFIX=d
fi
MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/js/src/intl/icu/target/lib/$(LIB_PREFIX)$(lib)$(DBG_SUFFIX).$(LIB_SUFFIX))'
;;
Darwin)
ICU_LIB_NAMES="icui18n icuuc icudata"
MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/js/src/intl/icu/target/lib/$(DLL_PREFIX)$(lib).$(MOZ_ICU_VERSION)$(DLL_SUFFIX))'
;;
Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
ICU_LIB_NAMES="icui18n icuuc icudata"
MOZ_ICU_LIBS='$(foreach lib,$(ICU_LIB_NAMES),$(DEPTH)/js/src/intl/icu/target/lib/$(DLL_PREFIX)$(lib)$(DLL_SUFFIX).$(MOZ_ICU_VERSION))'
;;
*)
AC_MSG_ERROR([ECMAScript Internationalization API is not yet supported on this platform])
esac
fi
fi
AC_SUBST(DBG_SUFFIX)
AC_SUBST(ENABLE_INTL_API)
AC_SUBST(ICU_LIB_NAMES)
AC_SUBST(MOZ_ICU_LIBS)
export WRITE_MOZINFO=1
AC_OUTPUT()
unset WRITE_MOZINFO
@ -8966,7 +9039,7 @@ fi
# Run jemalloc configure script
if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -o -n "$MOZ_REPLACE_MALLOC"; then
ac_configure_args="$_SUBDIR_CONFIG_ARGS --build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_"
ac_configure_args="--build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_"
if test -n "$MOZ_REPLACE_MALLOC"; then
# When using replace_malloc, we always want memalign and valloc exported from jemalloc.
ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes"
@ -9161,26 +9234,6 @@ dist=$MOZ_BUILD_ROOT/dist
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
ac_configure_args="$ac_configure_args --enable-threadsafe"
MOZ_ARG_WITH_STRING(intl-api,
[ --with-intl-api, --with-intl-api=build, --without-intl-api
Determine the status of the ECMAScript Internationalization API. The first
(or lack of any of these) builds and exposes the API. The second builds it
but doesn't use ICU or expose the API to script. The third doesn't build
ICU at all.],
WITH_INTL="--with-intl-api=$withval"
)
if test -z "$WITH_INTL"; then
if test "$MOZ_BUILD_APP" = "browser"; then
WITH_INTL="--with-intl-api"
else
# Internationalization isn't built or exposed by default in non-desktop
# builds. Bugs to enable:
#
# Android: bug 864843
# B2G: bug 866301
WITH_INTL="--without-intl-api"
fi
fi
ac_configure_args="$ac_configure_args $WITH_INTL"
if test "$BUILD_CTYPES"; then

View File

@ -171,9 +171,11 @@ static const char* const gWebMTypes[3] = {
nullptr
};
static char const *const gWebMCodecs[5] = {
static char const *const gWebMCodecs[7] = {
"vp8",
"vp8.0",
"vp9",
"vp9.0",
"vorbis",
"opus",
nullptr

View File

@ -421,6 +421,18 @@ bool OmxDecoder::TryLoad() {
// read audio metadata
if (mAudioSource.get()) {
// For RTSP, we don't read the audio source for now.
// The metadata of RTSP will be obtained through SDP at connection time.
if (mResource->GetRtspPointer()) {
sp<MetaData> meta = mAudioSource->getFormat();
if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) ||
!meta->findInt32(kKeySampleRate, &mAudioSampleRate)) {
NS_WARNING("Couldn't get audio metadata from OMX decoder");
return false;
}
return true;
}
// To reliably get the channel and sample rate data we need to read from the
// audio source until we get a INFO_FORMAT_CHANGE status
status_t err = mAudioSource->read(&mAudioBuffer);

View File

@ -62,6 +62,15 @@ public:
return NS_OK;
}
// Override FindStartTime() to return null pointer.
// For Rtsp, we don't have the first video frame in DECODING_METADATA state.
// It will be available until player request Play() and media decoder enters
// DECODING state.
virtual VideoData* FindStartTime(int64_t& aOutStartTime)
MOZ_FINAL MOZ_OVERRIDE {
return nullptr;
}
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
// The lifetime of mRtspResource is controlled by MediaDecoder. MediaDecoder

View File

@ -163,7 +163,7 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder)
#endif
// Zero these member vars to avoid crashes in VP8 destroy and Vorbis clear
// functions when destructor is called before |Init|.
memset(&mVP8, 0, sizeof(vpx_codec_ctx_t));
memset(&mVPX, 0, sizeof(vpx_codec_ctx_t));
memset(&mVorbisBlock, 0, sizeof(vorbis_block));
memset(&mVorbisDsp, 0, sizeof(vorbis_dsp_state));
memset(&mVorbisInfo, 0, sizeof(vorbis_info));
@ -177,7 +177,7 @@ WebMReader::~WebMReader()
mVideoPackets.Reset();
mAudioPackets.Reset();
vpx_codec_destroy(&mVP8);
vpx_codec_destroy(&mVPX);
vorbis_block_clear(&mVorbisBlock);
vorbis_dsp_clear(&mVorbisDsp);
@ -194,9 +194,6 @@ WebMReader::~WebMReader()
nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor)
{
if (vpx_codec_dec_init(&mVP8, vpx_codec_vp8_dx(), nullptr, 0)) {
return NS_ERROR_FAILURE;
}
vorbis_info_init(&mVorbisInfo);
vorbis_comment_init(&mVorbisComment);
@ -285,6 +282,18 @@ nsresult WebMReader::ReadMetadata(MediaInfo* aInfo,
return NS_ERROR_FAILURE;
}
vpx_codec_iface_t* dx = nullptr;
mVideoCodec = nestegg_track_codec_id(mContext, track);
if (mVideoCodec == NESTEGG_CODEC_VP8) {
dx = vpx_codec_vp8_dx();
} else if (mVideoCodec == NESTEGG_CODEC_VP9) {
dx = vpx_codec_vp9_dx();
}
if (!dx || vpx_codec_dec_init(&mVPX, dx, nullptr, 0)) {
Cleanup();
return NS_ERROR_FAILURE;
}
// Picture region, taking into account cropping, before scaling
// to the display size.
nsIntRect pictureRect(params.crop_left,
@ -868,7 +877,11 @@ bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
vpx_codec_stream_info_t si;
memset(&si, 0, sizeof(si));
si.sz = sizeof(si);
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
if (mVideoCodec == NESTEGG_CODEC_VP8) {
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
} else if (mVideoCodec == NESTEGG_CODEC_VP9) {
vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si);
}
if (aKeyframeSkip && (!si.is_kf || tstamp_usecs < aTimeThreshold)) {
// Skipping to next keyframe...
parsed++; // Assume 1 frame per chunk.
@ -879,7 +892,7 @@ bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
aKeyframeSkip = false;
}
if (vpx_codec_decode(&mVP8, data, length, nullptr, 0)) {
if (vpx_codec_decode(&mVPX, data, length, nullptr, 0)) {
return false;
}
@ -894,7 +907,7 @@ bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
vpx_codec_iter_t iter = nullptr;
vpx_image_t *img;
while ((img = vpx_codec_get_frame(&mVP8, &iter))) {
while ((img = vpx_codec_get_frame(&mVPX, &iter))) {
NS_ASSERTION(img->fmt == IMG_FMT_I420, "WebM image format is not I420");
// Chroma shifts are rounded down as per the decoding examples in the VP8 SDK

View File

@ -181,7 +181,7 @@ private:
nestegg* mContext;
// VP8 decoder state
vpx_codec_ctx_t mVP8;
vpx_codec_ctx_t mVPX;
// Vorbis decoder state
vorbis_info mVorbisInfo;
@ -234,6 +234,8 @@ private:
// Codec ID of audio track
int mAudioCodec;
// Codec ID of video track
int mVideoCodec;
};

View File

@ -1256,6 +1256,7 @@ Navigator::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads,
}
NS_ENSURE_TRUE_VOID(mWindow->GetDocShell());
nsGlobalWindow* win = static_cast<nsGlobalWindow*>(mWindow.get());
win->SetHasGamepadEventListener(true);
win->GetGamepads(aGamepads);
}
#endif

View File

@ -66,11 +66,6 @@
}
var tests = [
function() {
ok(!("getDataStores" in navigator), "getDataStores should not exist");
runTest();
},
// Permissions
function() {
SpecialPowers.pushPermissions(
@ -83,7 +78,13 @@
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true],
["dom.datastore.enabled", true],
["dom.testing.ignore_ipc_principal", true]]}, runTest);
["dom.testing.ignore_ipc_principal", true],
["dom.testing.datastore_enabled_for_hosted_apps", false]]}, runTest);
},
function() {
ok(!("getDataStores" in navigator), "getDataStores should not exist");
runTest();
},
function() {

View File

@ -0,0 +1,46 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const Bob = { ss: "237-23-7732", name: "Bob" };
let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
let event = yield undefined;
let db = event.target.result;
event.target.onsuccess = continueToNextStep;
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
objectStore.createIndex("name", "name", { unique: true });
objectStore.add(Bob);
yield undefined;
// This direct eval causes locals to be aliased, and thus allocated on
// the scope chain. Comment it out (and the workarounds below) and
// the test passes. Bug 943409.
eval('');
db.transaction("foo", "readwrite").objectStore("foo")
.index("name").openCursor().onsuccess = function(event) {
event.target.transaction.oncomplete = continueToNextStep;
let cursor = event.target.result;
if (cursor) {
let objectStore = event.target.transaction.objectStore("foo");
objectStore.delete(Bob.ss)
.onsuccess = function(event) { cursor.continue(); };
}
};
yield undefined;
finishTest();
objectStore = null; // Bug 943409 workaround.
yield undefined;
}

View File

@ -35,6 +35,11 @@ function testSteps()
let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
objectStore.createIndex("name", "name", { unique: true });
// This direct eval causes locals to be aliased, and thus allocated on
// the scope chain. Comment it out (and the workarounds below) and
// the test passes. Bug 943409.
eval('');
for (let i = 0; i < objectStoreData.length - 1; i++) {
objectStore.add(objectStoreData[i]);
}
@ -111,5 +116,8 @@ function testSteps()
is(sawRemoved, false, "Didn't see item that was removed");
finishTest();
objectStore = null; // Bug 943409 workaround.
yield undefined;
}

View File

@ -34,6 +34,9 @@ function testSteps()
event.target.onsuccess = continueToNextStep;
// Bug 943409.
eval('');
for (let objectStoreIndex in objectStoreData) {
const objectStoreInfo = objectStoreData[objectStoreIndex];
let objectStore = db.createObjectStore(objectStoreInfo.name,
@ -137,6 +140,8 @@ function testSteps()
.objectStore(objectStoreName).clear()
.onsuccess = continueToNextStep;
yield undefined;
objectStore = index = null; // Bug 943409 workaround.
}
}

View File

@ -18,6 +18,9 @@ function testSteps()
let db = event.target.result;
db.onerror = errorHandler;
// Bug 943409.
eval('');
for each (let autoIncrement in [false, true]) {
let objectStore =
db.createObjectStore(autoIncrement, { keyPath: "id",
@ -159,9 +162,13 @@ function testSteps()
is(event.target.result, indexCount,
"Correct number of entries in index");
index = event = null; // Bug 943409 workaround.
}
objectStore = event = null; // Bug 943409 workaround.
}
finishTest();
event = db = request = null; // Bug 943409 workaround.
yield undefined;
}

View File

@ -21,6 +21,7 @@ support-files =
[test_create_index.js]
[test_create_index_with_integer_keys.js]
[test_create_objectStore.js]
[test_cursor_cycle.js]
[test_cursor_mutation.js]
[test_cursor_update_updates_indexes.js]
[test_cursors.js]

View File

@ -132,19 +132,29 @@ void nsPluginTag::InitMime(const char* const* aMimeTypes,
}
for (uint32_t i = 0; i < aVariantCount; i++) {
if (!aMimeTypes[i] || !nsPluginHost::IsTypeWhitelisted(aMimeTypes[i])) {
if (!aMimeTypes[i]) {
continue;
}
nsAutoCString mimeType(aMimeTypes[i]);
// Convert the MIME type, which is case insensitive, to lowercase in order
// to properly handle a mixed-case type.
ToLowerCase(mimeType);
if (!nsPluginHost::IsTypeWhitelisted(mimeType.get())) {
continue;
}
// Look for certain special plugins.
if (nsPluginHost::IsJavaMIMEType(aMimeTypes[i])) {
if (nsPluginHost::IsJavaMIMEType(mimeType.get())) {
mIsJavaPlugin = true;
} else if (strcmp(aMimeTypes[i], "application/x-shockwave-flash") == 0) {
} else if (mimeType.EqualsLiteral("application/x-shockwave-flash")) {
mIsFlashPlugin = true;
}
// Fill in our MIME type array.
mMimeTypes.AppendElement(nsCString(aMimeTypes[i]));
mMimeTypes.AppendElement(mimeType);
// Now fill in the MIME descriptions.
if (aMimeDescriptions && aMimeDescriptions[i]) {

View File

@ -0,0 +1,8 @@
function handleRequest(request, response)
{
response.processAsync();
response.setHeader("Content-Type", "application/x-Second-Test", false);
response.write("Hello world.\n");
response.finish();
}

View File

@ -11,6 +11,7 @@ support-files =
loremipsum_file.txt
loremipsum_nocache.txt
loremipsum_nocache.txt^headers^
mixed_case_mime.sjs
neverending.sjs
npruntime_identifiers_subpage.html
plugin-stream-referer.sjs
@ -41,6 +42,7 @@ support-files =
[test_instance_unparent2.html]
[test_instance_unparent3.html]
[test_instantiation.html]
[test_mixed_case_mime.html]
[test_multipleinstanceobjects.html]
[test_newstreamondestroy.html]
[test_npn_asynccall.html]

View File

@ -0,0 +1,29 @@
<body>
<head>
<title>Test mixed case mimetype for plugins</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script>
SimpleTest.expectAssertions(0, 1);
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
function frameLoaded() {
var contentDocument = document.getElementById('testframe').contentDocument;
ok(contentDocument.body.innerHTML.length > 0, "Frame content shouldn't be empty.");
ok(contentDocument.plugins.length > 0, "Frame content should have a plugin.");
var plugin = contentDocument.plugins[0];
is(plugin.type.toLowerCase(), "application/x-second-test", "Should have loaded the second test plugin.");
SimpleTest.finish();
}
</script>
</head>
<body>
<p id="display"></p>
<iframe id="testframe" name="testframe" onload="frameLoaded()" src="mixed_case_mime.sjs"></iframe>
</body>
</html>

View File

@ -24,7 +24,7 @@
<string>Second plug-in for testing purposes.</string>
<key>WebPluginMIMETypes</key>
<dict>
<key>application/x-second-test</key>
<key>application/x-Second-Test</key>
<dict>
<key>WebPluginExtensions</key>
<array>

View File

@ -29,7 +29,7 @@ BEGIN
VALUE "FileOpenName", "Second test type"
VALUE "FileVersion", "1.0"
VALUE "InternalName", "npsecondtest"
VALUE "MIMEType", "application/x-second-test"
VALUE "MIMEType", "application/x-Second-Test"
VALUE "OriginalFilename", "npsecondtest.dll"
VALUE "ProductName", "Second Test Plug-in"
VALUE "ProductVersion", "1.0"

Some files were not shown because too many files have changed in this diff Show More