Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-12-09 17:43:44 -05:00
commit 72c57be9ea
113 changed files with 1618 additions and 958 deletions

View File

@ -1,4 +1,4 @@
{
"revision": "7343851c97c278a338434d2632098a263e19bbb6",
"revision": "d5f4a104c0b79b8fe13b7883dd531249ed251146",
"repo_path": "/integration/gaia-central"
}

View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=B2G
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=28.0a1
MOZ_APP_VERSION=29.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_UA_OS_AGNOSTIC=1
@ -56,7 +56,9 @@ MOZ_TOOLKIT_SEARCH=
MOZ_PLACES=
MOZ_B2G=1
#MOZ_NUWA_PROCESS=1
if test "$OS_TARGET" = "Android"; then
MOZ_NUWA_PROCESS=1
fi
MOZ_FOLD_LIBS=1
MOZ_JSDOWNLOADS=1

View File

@ -477,7 +477,7 @@ let CustomizableUIInternal = {
this.insertWidgetBefore(node, currentNode, container, aArea);
if (gResetting) {
this.notifyListeners("onWidgetReset", id, aArea);
this.notifyListeners("onWidgetReset", node, container);
}
}
@ -527,7 +527,7 @@ let CustomizableUIInternal = {
}
if (gResetting) {
this.notifyListeners("onAreaReset", aArea);
this.notifyListeners("onAreaReset", aArea, container);
}
} finally {
this.endBatchUpdate();
@ -668,6 +668,8 @@ let CustomizableUIInternal = {
}
let area = gAreas.get(aArea);
let isToolbar = area.get("type") == CustomizableUI.TYPE_TOOLBAR;
let isOverflowable = isToolbar && area.get("overflowable");
let showInPrivateBrowsing = gPalette.has(aWidgetId)
? gPalette.get(aWidgetId).showInPrivateBrowsing
: true;
@ -679,12 +681,15 @@ let CustomizableUIInternal = {
continue;
}
let container = areaNode.customizationTarget;
let widgetNode = container.ownerDocument.getElementById(aWidgetId);
let widgetNode = window.document.getElementById(aWidgetId);
if (!widgetNode) {
ERROR("Widget not found, unable to remove");
continue;
}
let container = areaNode.customizationTarget;
if (isOverflowable) {
container = areaNode.overflowable.getContainerFor(widgetNode);
}
this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true);
@ -702,7 +707,7 @@ let CustomizableUIInternal = {
}
this.notifyListeners("onWidgetAfterDOMChange", widgetNode, null, container, true);
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
if (isToolbar) {
areaNode.setAttribute("currentset", gPlacements.get(aArea).join(','));
}
@ -2094,47 +2099,330 @@ this.CustomizableUI = {
get WIDE_PANEL_CLASS() "panel-wide-item",
get PANEL_COLUMN_COUNT() 3,
/**
* Add a listener object that will get fired for various events regarding
* customization.
*
* @param aListener the listener object to add
*
* Not all event handler methods need to be defined.
* CustomizableUI will catch exceptions. Events are dispatched
* synchronously on the UI thread, so if you can delay any/some of your
* processing, that is advisable. The following event handlers are supported:
* - onWidgetAdded(aWidgetId, aArea, aPosition)
* Fired when a widget is added to an area. aWidgetId is the widget that
* was added, aArea the area it was added to, and aPosition the position
* in which it was added.
* - onWidgetMoved(aWidgetId, aArea, aOldPosition, aNewPosition)
* Fired when a widget is moved within its area. aWidgetId is the widget
* that was moved, aArea the area it was moved in, aOldPosition its old
* position, and aNewPosition its new position.
* - onWidgetRemoved(aWidgetId, aArea)
* Fired when a widget is removed from its area. aWidgetId is the widget
* that was removed, aArea the area it was removed from.
*
* - onWidgetBeforeDOMChange(aNode, aNextNode, aContainer, aIsRemoval)
* Fired *before* a widget's DOM node is acted upon by CustomizableUI
* (to add, move or remove it). aNode is the DOM node changed, aNextNode
* the DOM node (if any) before which a widget will be inserted,
* aContainer the *actual* DOM container (could be an overflow panel in
* case of an overflowable toolbar), and aWasRemoval is true iff the
* action about to happen is the removal of the DOM node.
* - onWidgetAfterDOMChange(aNode, aNextNode, aContainer, aWasRemoval)
* Like onWidgetBeforeDOMChange, but fired after the change to the DOM
* node of the widget.
*
* - onWidgetReset(aNode, aContainer)
* Fired after a reset to default placements moves a widget's node to a
* different location. aNode is the widget's node, aContainer is the
* area it was moved into (NB: it might already have been there and been
* moved to a different position!)
* - onAreaReset(aArea, aContainer)
* Fired after a reset to default placements is complete on an area's
* DOM node. Note that this is fired for each DOM node. aArea is the area
* that was reset, aContainer the DOM node that was reset.
*
* - onWidgetCreated(aWidgetId)
* Fired when a widget with id aWidgetId has been created, but before it
* is added to any placements or any DOM nodes have been constructed.
* Only fired for API-based widgets.
* - onWidgetAfterCreation(aWidgetId, aArea)
* Fired after a widget with id aWidgetId has been created, and has been
* added to either its default area or the area in which it was placed
* previously. If the widget has no default area and/or it has never
* been placed anywhere, aArea may be null. Only fired for API-based
* widgets.
* - onWidgetDestroyed(aWidgetId)
* Fired when widgets are destroyed. aWidgetId is the widget that is
* being destroyed. Only fired for API-based widgets.
* - onWidgetInstanceRemoved(aWidgetId, aDocument)
* Fired when a window is unloaded and a widget's instance is destroyed
* because of this. Only fired for API-based widgets.
*
* - onWidgetDrag(aWidgetId, aArea)
* Fired both when and after customize mode drag handling system tries
* to determine the width and height of widget aWidgetId when dragged to a
* different area. aArea will be the area the item is dragged to, or
* undefined after the measurements have been done and the node has been
* moved back to its 'regular' area.
*
* - onCustomizeStart(aWindow)
* Fired when opening customize mode in aWindow.
* - onCustomizeEnd(aWindow)
* Fired when exiting customize mode in aWindow.
*/
addListener: function(aListener) {
CustomizableUIInternal.addListener(aListener);
},
/**
* Remove a listener added with addListener
* @param aListener the listener object to remove
*/
removeListener: function(aListener) {
CustomizableUIInternal.removeListener(aListener);
},
/**
* Register a customizable area with CustomizableUI.
* @param aName the name of the area to register. Can only contain
* alphanumeric characters, dashes (-) and underscores (_).
* @param aProps the properties of the area. The following properties are
* recognized:
* - type: the type of area. Either TYPE_TOOLBAR (default) or
* TYPE_MENU_PANEL;
* - anchor: for a menu panel or overflowable toolbar, the
* anchoring node for the panel.
* - legacy: set to true if you want customizableui to
* automatically migrate the currentset attribute
* - overflowable: set to true if your toolbar is overflowable.
* This requires an anchor, and only has an
* effect for toolbars.
* - defaultPlacements: an array of widget IDs making up the
* default contents of the area
*/
registerArea: function(aName, aProperties) {
CustomizableUIInternal.registerArea(aName, aProperties);
},
/**
* Register a concrete node for a registered area. This method is automatically
* called from any toolbar in the main browser window that has its
* "customizable" attribute set to true. There should normally be no need to
* call it yourself.
*
* Note that ideally, you should register your toolbar using registerArea
* before any of the toolbars have their XBL bindings constructed (which
* will happen when they're added to the DOM and are not hidden). If you
* don't, and your toolbar has a defaultset attribute, CustomizableUI will
* register it automatically. If your toolbar does not have a defaultset
* attribute, the node will be saved for processing when you call
* registerArea. Note that CustomizableUI won't restore state in the area,
* allow the user to customize it in customize mode, or otherwise deal
* with it, until the area has been registered.
*/
registerToolbarNode: function(aToolbar, aExistingChildren) {
CustomizableUIInternal.registerToolbarNode(aToolbar, aExistingChildren);
},
/**
* Register the menu panel node. This method should not be called by anyone
* apart from the built-in PanelUI.
* @param aPanel the panel DOM node being registered.
*/
registerMenuPanel: function(aPanel) {
CustomizableUIInternal.registerMenuPanel(aPanel);
},
/**
* Unregister a customizable area. The inverse of registerArea.
*
* Unregistering an area will remove all the (removable) widgets in the
* area, which will return to the panel, and destroy all other traces
* of the area within CustomizableUI. Note that this means the *contents*
* of the area's DOM nodes will be moved to the panel or removed, but
* the area's DOM nodes *themselves* will stay.
*
* Furthermore, by default the placements of the area will be kept in the
* saved state (!) and restored if you re-register the area at a later
* point. This is useful for e.g. add-ons that get disabled and then
* re-enabled (e.g. when they update).
*
* You can override this last behaviour (and destroy the placements
* information in the saved state) by passing true for aDestroyPlacements.
*
* @param aName the name of the area to unregister
* @param aDestroyPlacements whether to destroy the placements information
* for the area, too.
*/
unregisterArea: function(aName, aDestroyPlacements) {
CustomizableUIInternal.unregisterArea(aName, aDestroyPlacements);
},
/**
* Add a widget to an area.
* If the area to which you try to add is not known to CustomizableUI,
* this will throw.
* If the area to which you try to add has not yet been restored from its
* legacy state, this will postpone the addition.
* If the area to which you try to add is the same as the area in which
* the widget is currently placed, this will do the same as
* moveWidgetWithinArea.
* If the widget cannot be removed from its original location, this will
* no-op.
*
* This will fire an onWidgetAdded notification,
* and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification
* for each window CustomizableUI knows about.
*
* @param aWidgetId the widget to add
* @param aArea the area to add the widget to
* @param aPosition the position at which to add the widget. If you do not
* pass a position, the widget will be added to the end
* of the area.
*/
addWidgetToArea: function(aWidgetId, aArea, aPosition) {
CustomizableUIInternal.addWidgetToArea(aWidgetId, aArea, aPosition);
},
/**
* Remove a widget from its area. If the widget cannot be removed from its
* area, or is not in any area, this will no-op. Otherwise, this will fire an
* onWidgetRemoved notification, and an onWidgetBeforeDOMChange and
* onWidgetAfterDOMChange notification for each window CustomizableUI knows
* about.
*
* @param aWidgetId the widget to remove
*/
removeWidgetFromArea: function(aWidgetId) {
CustomizableUIInternal.removeWidgetFromArea(aWidgetId);
},
/**
* Move a widget within an area.
* If the widget is not in any area, this will no-op.
* If the widget is already at the indicated position, this will no-op.
*
* Otherwise, this will move the widget and fire an onWidgetMoved notification,
* and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification for
* each window CustomizableUI knows about.
*
* @param aWidgetid the widget to move
* @param aPosition the position to move the widget to.
* Negative values or values greater than the number of
* widgets will be interpreted to mean moving the widget to
* respectively the first or last position.
*/
moveWidgetWithinArea: function(aWidgetId, aPosition) {
CustomizableUIInternal.moveWidgetWithinArea(aWidgetId, aPosition);
},
/**
* Ensure a XUL-based widget created in a window after areas were
* initialized moves to its correct position.
* This is roughly equivalent to manually looking up the position and using
* insertItem in the old API, but a lot less work for consumers.
* Always prefer this over using toolbar.insertItem (which might no-op
* because it delegates to addWidgetToArea) or, worse, moving items in the
* DOM yourself.
*
* @param aWidgetId the widget that was just created
* @param aWindow the window in which you want to ensure it was added.
*
* NB: why is this API per-window, you wonder? Because if you need this,
* presumably you yourself need to create the widget in all the windows
* and need to loop through them anyway.
*/
ensureWidgetPlacedInWindow: function(aWidgetId, aWindow) {
return CustomizableUIInternal.ensureWidgetPlacedInWindow(aWidgetId, aWindow);
},
/**
* Start a batch update of items.
* During a batch update, the customization state is not saved to the user's
* preferences file, in order to reduce (possibly sync) IO.
* Calls to begin/endBatchUpdate may be nested.
*
* Callers should ensure that NO MATTER WHAT they call endBatchUpdate once
* for each call to endBatchUpdate, even if there are exceptions in the
* code in the batch update. Otherwise, for the duration of the
* Firefox session, customization state is never saved. Typically, you
* would do this using a try...finally block.
*/
beginBatchUpdate: function() {
CustomizableUIInternal.beginBatchUpdate();
},
/**
* End a batch update. See the documentation for beginBatchUpdate above.
*
* State is not saved if we believe it is identical to the last known
* saved state. State is only ever saved when all batch updates have
* finished (ie there has been 1 endBatchUpdate call for each
* beginBatchUpdate call). If any of the endBatchUpdate calls pass
* aForceDirty=true, we will flush to the prefs file.
*
* @param aForceDirty force CustomizableUI to flush to the prefs file when
* all batch updates have finished.
*/
endBatchUpdate: function(aForceDirty) {
CustomizableUIInternal.endBatchUpdate(aForceDirty);
},
/**
* Create a widget.
*
* To create a widget, you should pass an object with its desired
* properties. The following properties are supported:
*
* - id: the ID of the widget (required).
* - type: a string indicating the type of widget. Possible types
* are:
* 'button' - for simple button widgets (the default)
* 'view' - for buttons that open a panel or subview,
* depending on where they are placed.
* 'custom' - for fine-grained control over the creation
* of the widget.
* - viewId: Only useful for views (and required there): the id of the
* <panelview> that should be shown when clicking the widget.
* - onBuild(aDoc): Only useful for custom widgets (and required there); a
* function that will be invoked with the document in which
* to build a widget. Should return the DOM node that has
* been constructed.
* - onCreated(aNode): Attached to all widgets; a function that will be invoked
* whenever the widget has a DOM node constructed, passing the
* constructed node as an argument.
* - onCommand(aEvt): Only useful for button widgets; a function that will be
* invoked when the user activates the button.
* - onClick(aEvt): Attached to all widgets; a function that will be invoked
* when the user clicks the widget.
* - onViewShowing(aEvt): Only useful for views; a function that will be
* invoked when a user shows your view.
* - onViewHiding(aEvt): Only useful for views; a function that will be
* invoked when a user hides your view.
* - tooltiptext: string to use for the tooltip of the widget
* - label: string to use for the label of the widget
* - removable: whether the widget is removable (optional, default: false)
* - overflows: whether widget can overflow when in an overflowable
* toolbar (optional, default: true)
* - defaultArea: default area to add the widget to
* (optional, default: none)
* - shortcutId: id of an element that has a shortcut for this widget
* (optional, default: null). This is only used to display
* the shortcut as part of the tooltip for builtin widgets
* (which have strings inside
* customizableWidgets.properties). If you're in an add-on,
* you should not set this property.
* - showInPrivateBrowsing: whether to show the widget in private browsing
* mode (optional, default: true)
*
* @param aProperties the specifications for the widget.
*/
createWidget: function(aProperties) {
return CustomizableUIInternal.wrapWidget(
CustomizableUIInternal.createWidget(aProperties)
);
},
/**
* Destroy a widget
*
* If the widget is part of the default placements in an area, this will
* remove it from there. It will also remove any DOM instances. However,
* it will keep the widget in the placements for whatever area it was
* in at the time. You can remove it from there yourself by calling
* CustomizableUI.removeWidgetFromArea(aWidgetId).
*
* @param aWidgetId the widget to destroy
*/
destroyWidget: function(aWidgetId) {
CustomizableUIInternal.destroyWidget(aWidgetId);
},
@ -2765,7 +3053,14 @@ OverflowableToolbar.prototype = {
return [this._target, null];
}
return [this._list, nextNode];
}
},
getContainerFor: function(aNode) {
if (aNode.classList.contains("overflowedItem")) {
return this._list;
}
return this._target;
},
};
// When IDs contain special characters, we need to escape them for use with querySelector:

View File

@ -406,8 +406,8 @@ const CustomizableWidgets = [{
updateZoomResetButton();
}.bind(this),
onWidgetReset: function(aWidgetId) {
if (aWidgetId != this.id)
onWidgetReset: function(aWidgetNode) {
if (aWidgetNode != node)
return;
updateCombinedWidgetStyle(node, this.currentArea, true);
updateZoomResetButton();
@ -506,8 +506,8 @@ const CustomizableWidgets = [{
updateCombinedWidgetStyle(node);
}.bind(this),
onWidgetReset: function(aWidgetId) {
if (aWidgetId != this.id)
onWidgetReset: function(aWidgetNode) {
if (aWidgetNode != node)
return;
updateCombinedWidgetStyle(node, this.currentArea);
}.bind(this),
@ -814,4 +814,4 @@ if (isWin8OrHigher()) {
});
}
#endif
#endif
#endif

View File

@ -101,7 +101,7 @@ AreaPositionManager.prototype = {
let doc = aContainer.ownerDocument;
let draggedItem = doc.getElementById(aDraggedItemId);
// If dragging a wide item, always pick the first item in a row:
if (draggedItem &&
if (this._inPanel && draggedItem &&
draggedItem.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
return this._firstInRow(closest);
}

View File

@ -1 +1 @@
28.0a1
29.0a1

View File

@ -149,7 +149,8 @@ ToolbarView.prototype = {
_onStepOverPressed: function() {
if (DebuggerController.activeThread.paused) {
DebuggerController.StackFrames.currentFrameDepth = -1;
DebuggerController.activeThread.stepOver();
let warn = DebuggerController._ensureResumptionOrder;
DebuggerController.activeThread.stepOver(warn);
}
},
@ -159,7 +160,8 @@ ToolbarView.prototype = {
_onStepInPressed: function() {
if (DebuggerController.activeThread.paused) {
DebuggerController.StackFrames.currentFrameDepth = -1;
DebuggerController.activeThread.stepIn();
let warn = DebuggerController._ensureResumptionOrder;
DebuggerController.activeThread.stepIn(warn);
}
},
@ -169,7 +171,8 @@ ToolbarView.prototype = {
_onStepOutPressed: function() {
if (DebuggerController.activeThread.paused) {
DebuggerController.StackFrames.currentFrameDepth = -1;
DebuggerController.activeThread.stepOut();
let warn = DebuggerController._ensureResumptionOrder;
DebuggerController.activeThread.stepOut(warn);
}
},

View File

@ -484,22 +484,22 @@ function testOriginalRawDataIntegrity(arr, obj) {
function testAnonymousHeaders(fooScope, anonymousVar, anonymousScope, barVar, bazProperty) {
is(fooScope.header, true,
"A named scope should have a header visible.");
is(fooScope.target.hasAttribute("non-header"), false,
is(fooScope.target.hasAttribute("untitled"), false,
"The non-header attribute should not be applied to scopes with headers.");
is(anonymousScope.header, false,
"An anonymous scope should have a header visible.");
is(anonymousScope.target.hasAttribute("non-header"), true,
is(anonymousScope.target.hasAttribute("untitled"), true,
"The non-header attribute should not be applied to scopes without headers.");
is(barVar.header, true,
"A named variable should have a header visible.");
is(barVar.target.hasAttribute("non-header"), false,
is(barVar.target.hasAttribute("untitled"), false,
"The non-header attribute should not be applied to variables with headers.");
is(anonymousVar.header, false,
"An anonymous variable should have a header visible.");
is(anonymousVar.target.hasAttribute("non-header"), true,
is(anonymousVar.target.hasAttribute("untitled"), true,
"The non-header attribute should not be applied to variables without headers.");
}

View File

@ -72,29 +72,29 @@ function testVariablesAndPropertiesFiltering() {
is(constr2Var.expanded, true,
"The constr2Var should be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 1,
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 1,
"There should be 1 variable displayed in the local scope.");
is(withScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the function scope.");
isnot(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
isnot(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be some variables displayed in the global scope.");
is(withScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the function scope.");
is(globalScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the global scope.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"__proto__", "The only inner variable displayed should be '__proto__'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"constructor", "The first inner property displayed should be 'constructor'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[1].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[1].getAttribute("value"),
"__proto__", "The second inner property displayed should be '__proto__'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[2].getAttribute("value"),
"constructor", "The third inner property displayed should be 'constructor'");
}

View File

@ -72,36 +72,36 @@ function testVariablesAndPropertiesFiltering() {
is(constr2Var.expanded, true,
"The constr2Var should be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 1,
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 1,
"There should be 1 variable displayed in the local scope.");
is(withScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the function scope.");
is(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be no variables displayed in the global scope.");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 4,
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 4,
"There should be 4 properties displayed in the local scope.");
is(withScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the function scope.");
is(globalScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the global scope.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"__proto__", "The only inner variable displayed should be '__proto__'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"constructor", "The first inner property displayed should be 'constructor'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[1].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[1].getAttribute("value"),
"__proto__", "The second inner property displayed should be '__proto__'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[2].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[2].getAttribute("value"),
"constructor", "The third inner property displayed should be 'constructor'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .name")[3].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .name")[3].getAttribute("value"),
"name", "The fourth inner property displayed should be 'name'");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match]) > .title > .value")[3].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched]) > .title > .value")[3].getAttribute("value"),
"\"Function\"", "The fourth inner property displayed should be '\"Function\"'");
}

View File

@ -58,20 +58,20 @@ function testVariablesAndPropertiesFiltering() {
is(globalScope.expanded, true,
"The globalScope should be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 1,
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 1,
"There should be 1 variable displayed in the local scope.");
is(withScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be 0 variables displayed in the function scope.");
is(localScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(localScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the local scope.");
is(withScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(withScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the with scope.");
is(functionScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the function scope.");
is(globalScope.target.querySelectorAll(".variables-view-property:not([non-match])").length, 0,
is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0,
"There should be 0 properties displayed in the global scope.");
}
@ -79,9 +79,9 @@ function testVariablesAndPropertiesFiltering() {
typeText(gSearchBox, "*one");
testFiltered("one");
isnot(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
isnot(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be some variables displayed in the global scope.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"one", "The only inner variable displayed should be 'one'");
}
@ -104,9 +104,9 @@ function testVariablesAndPropertiesFiltering() {
typeText(gSearchBox, "*two");
testFiltered("two");
is(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length, 0,
is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0,
"There should be no variables displayed in the global scope.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"two", "The only inner variable displayed should be 'two'");
}

View File

@ -58,7 +58,7 @@ function testVariablesAndPropertiesFiltering() {
assertScopeExpansion([true, true, true, true]);
assertVariablesCountAtLeast([0, 0, 1, 0]);
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"arguments", "The arguments pseudoarray should be visible.");
is(functionScope.get("arguments").expanded, false,
"The arguments pseudoarray in functionScope should not be expanded.");
@ -69,12 +69,12 @@ function testVariablesAndPropertiesFiltering() {
assertScopeExpansion([true, true, true, true]);
assertVariablesCountAtLeast([0, 0, 1, 1]);
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"arguments", "The arguments pseudoarray should be visible.");
is(functionScope.get("arguments").expanded, false,
"The arguments pseudoarray in functionScope should not be expanded.");
is(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"EventTarget", "The EventTarget object should be visible.");
is(globalScope.get("EventTarget").expanded, false,
"The EventTarget object in globalScope should not be expanded.");
@ -85,17 +85,17 @@ function testVariablesAndPropertiesFiltering() {
assertScopeExpansion([true, true, true, true]);
assertVariablesCountAtLeast([0, 1, 3, 1]);
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"aNumber", "The aNumber param should be visible.");
is(functionScope.get("aNumber").expanded, false,
"The aNumber param in functionScope should not be expanded.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[1].getAttribute("value"),
"a", "The a variable should be visible.");
is(functionScope.get("a").expanded, false,
"The a variable in functionScope should not be expanded.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[2].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[2].getAttribute("value"),
"arguments", "The arguments pseudoarray should be visible.");
is(functionScope.get("arguments").expanded, false,
"The arguments pseudoarray in functionScope should not be expanded.");
@ -106,37 +106,37 @@ function testVariablesAndPropertiesFiltering() {
assertScopeExpansion([true, true, true, true]);
assertVariablesCountAtLeast([4, 1, 3, 1]);
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"this", "The this reference should be visible.");
is(localScope.get("this").expanded, false,
"The this reference in localScope should not be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[1].getAttribute("value"),
"one", "The one variable should be visible.");
is(localScope.get("one").expanded, false,
"The one variable in localScope should not be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[2].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[2].getAttribute("value"),
"two", "The two variable should be visible.");
is(localScope.get("two").expanded, false,
"The two variable in localScope should not be expanded.");
is(localScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[3].getAttribute("value"),
is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[3].getAttribute("value"),
"__proto__", "The __proto__ reference should be visible.");
is(localScope.get("__proto__").expanded, false,
"The __proto__ reference in localScope should not be expanded.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"),
"aNumber", "The aNumber param should be visible.");
is(functionScope.get("aNumber").expanded, false,
"The aNumber param in functionScope should not be expanded.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[1].getAttribute("value"),
"a", "The a variable should be visible.");
is(functionScope.get("a").expanded, false,
"The a variable in functionScope should not be expanded.");
is(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match]) > .title > .name")[2].getAttribute("value"),
is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[2].getAttribute("value"),
"arguments", "The arguments pseudoarray should be visible.");
is(functionScope.get("arguments").expanded, false,
"The arguments pseudoarray in functionScope should not be expanded.");
@ -162,19 +162,19 @@ function testVariablesAndPropertiesFiltering() {
}
function assertVariablesCountAtLeast(aCounts) {
ok(localScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length >= aCounts[0],
ok(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[0],
"There should be " + aCounts[0] +
" variable displayed in the local scope (" + step + ").");
ok(withScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length >= aCounts[1],
ok(withScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[1],
"There should be " + aCounts[1] +
" variable displayed in the with scope (" + step + ").");
ok(functionScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length >= aCounts[2],
ok(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[2],
"There should be " + aCounts[2] +
" variable displayed in the function scope (" + step + ").");
ok(globalScope.target.querySelectorAll(".variables-view-variable:not([non-match])").length >= aCounts[3],
ok(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[3],
"There should be " + aCounts[3] +
" variable displayed in the global scope (" + step + ").");

View File

@ -19,9 +19,9 @@ function test() {
is(tooltip.querySelectorAll(".variables-view-container").length, 1,
"There should be one variables view container added to the tooltip.");
is(tooltip.querySelectorAll(".variables-view-scope[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-scope[untitled]").length, 1,
"There should be one scope with no header displayed.");
is(tooltip.querySelectorAll(".variables-view-variable[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-variable[untitled]").length, 1,
"There should be one variable with no header displayed.");
is(tooltip.querySelectorAll(".variables-view-property").length, 2,

View File

@ -19,9 +19,9 @@ function test() {
is(tooltip.querySelectorAll(".variables-view-container").length, 1,
"There should be one variables view container added to the tooltip.");
is(tooltip.querySelectorAll(".variables-view-scope[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-scope[untitled]").length, 1,
"There should be one scope with no header displayed.");
is(tooltip.querySelectorAll(".variables-view-variable[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-variable[untitled]").length, 1,
"There should be one variable with no header displayed.");
is(tooltip.querySelectorAll(".variables-view-property").length, 7,

View File

@ -33,9 +33,9 @@ function test() {
is(tooltip.querySelectorAll(".devtools-tooltip-simple-text").length, 0,
"There should be no simple text node added to the tooltip.");
is(tooltip.querySelectorAll(".variables-view-scope[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-scope[untitled]").length, 1,
"There should be one scope with no header displayed.");
is(tooltip.querySelectorAll(".variables-view-variable[non-header]").length, 1,
is(tooltip.querySelectorAll(".variables-view-variable[untitled]").length, 1,
"There should be one variable with no header displayed.");
ok(tooltip.querySelectorAll(".variables-view-property").length >= propertyCount,

View File

@ -1476,7 +1476,7 @@ Scope.prototype = {
if (this._isHeaderVisible || !this._nameString) {
return;
}
this._target.removeAttribute("non-header");
this._target.removeAttribute("untitled");
this._isHeaderVisible = true;
},
@ -1489,7 +1489,7 @@ Scope.prototype = {
return;
}
this.expand();
this._target.setAttribute("non-header", "");
this._target.setAttribute("untitled", "");
this._isHeaderVisible = false;
},
@ -1928,10 +1928,10 @@ Scope.prototype = {
}
if (aStatus) {
this._isMatch = true;
this.target.removeAttribute("non-match");
this.target.removeAttribute("unmatched");
} else {
this._isMatch = false;
this.target.setAttribute("non-match", "");
this.target.setAttribute("unmatched", "");
}
},

View File

@ -50,9 +50,9 @@
overflow: hidden;
}
.variables-view-scope[non-header] > .title,
.variable-or-property[non-header] > .title,
.variable-or-property[non-match] > .title {
.variables-view-scope[untitled] > .title,
.variable-or-property[untitled] > .title,
.variable-or-property[unmatched] > .title {
display: none;
}

View File

@ -1,5 +1,6 @@
af
ak
an
ar
ast
be
@ -79,6 +80,7 @@ th
tr
uk
vi
xh
zh-CN
zh-TW
zu

View File

@ -308,10 +308,11 @@ var BrowserUI = {
isStartURI: function isStartURI(aURI) {
aURI = aURI || Browser.selectedBrowser.currentURI.spec;
return aURI == kStartURI;
return aURI == kStartURI || aURI == "about:home";
},
updateStartURIAttributes: function (aURI) {
let wasStart = Elements.windowState.hasAttribute("startpage");
aURI = aURI || Browser.selectedBrowser.currentURI.spec;
if (this.isStartURI(aURI)) {
ContextUI.displayNavbar();
@ -319,6 +320,13 @@ var BrowserUI = {
} else if (aURI != "about:blank") { // about:blank is loaded briefly for new tabs; ignore it
Elements.windowState.removeAttribute("startpage");
}
let isStart = Elements.windowState.hasAttribute("startpage");
if (wasStart != isStart) {
let event = document.createEvent("Events");
event.initEvent("StartUIChange", true, true);
Browser.selectedBrowser.dispatchEvent(event);
}
},
getDisplayURI: function(browser) {

View File

@ -1305,6 +1305,7 @@ Tab.prototype = {
}
browser.addEventListener("pageshow", onPageShowEvent, true);
browser.addEventListener("DOMWindowCreated", this, false);
browser.addEventListener("StartUIChange", this, false);
Elements.browsers.addEventListener("SizeChanged", this, false);
browser.messageManager.addMessageListener("Content:StateChange", this);
@ -1316,12 +1317,19 @@ Tab.prototype = {
updateViewport: function (aEvent) {
// <meta name=viewport> is not yet supported; just use the browser size.
this.browser.setWindowSize(this.browser.clientWidth, this.browser.clientHeight);
let browser = this.browser;
// On the start page we add padding to keep the browser above the navbar.
let paddingBottom = parseInt(getComputedStyle(browser).paddingBottom, 10);
let height = browser.clientHeight - paddingBottom;
browser.setWindowSize(browser.clientWidth, height);
},
handleEvent: function (aEvent) {
switch (aEvent.type) {
case "DOMWindowCreated":
case "StartUIChange":
this.updateViewport();
break;
case "SizeChanged":
@ -1354,6 +1362,7 @@ Tab.prototype = {
destroy: function destroy() {
this._browser.messageManager.removeMessageListener("Content:StateChange", this);
this._browser.removeEventListener("DOMWindowCreated", this, false);
this._browser.removeEventListener("StartUIChange", this, false);
Elements.browsers.removeEventListener("SizeChanged", this, false);
clearTimeout(this._updateThumbnailTimeout);

View File

@ -18,8 +18,7 @@ var MetroDownloadsView = {
_inited: false,
_progressAlert: null,
_lastSec: Infinity,
_notificationBox: null,
_progressNotification: null,
_progressNotificationInfo: new Map(),
_runDownloadBooleanMap: new Map(),
@ -56,11 +55,12 @@ var MetroDownloadsView = {
Services.obs.addObserver(this, "dl-run", true);
Services.obs.addObserver(this, "dl-failed", true);
this._notificationBox = Browser.getNotificationBox();
this._progress = new DownloadProgressListener(this);
this.manager.addListener(this._progress);
Elements.tabList.addEventListener("TabClose", this, false);
this._downloadProgressIndicator = document.getElementById("download-progress");
if (this.manager.activeDownloadCount) {
@ -74,10 +74,54 @@ var MetroDownloadsView = {
Services.obs.removeObserver(this, "dl-done");
Services.obs.removeObserver(this, "dl-run");
Services.obs.removeObserver(this, "dl-failed");
if (Elements && Elements.tabList)
Elements.tabList.removeEventListener("TabClose", this);
}
},
_restartWithActiveDownloads: function() {
get _notificationBox() {
return Browser.getNotificationBox(Browser.selectedBrowser);
},
get _notificationBoxes() {
let currentBox = this._notificationBox;
let boxes = [
currentBox
];
for (let { linkedBrowser } of Elements.tabList.children) {
if (linkedBrowser !== Browser.selectedBrowser) {
let notificationBox = Browser.getNotificationBox(linkedBrowser);
if (notificationBox)
boxes.push(notificationBox);
}
}
return boxes;
},
get _progressNotification() {
let notn = this._getNotificationWithValue("download-progress");
let currentBox = this._notificationBox;
// move the progress notification if attached to a different browser
if (notn && notn.parentNode !== currentBox) {
notn.parentNode.removeNotification(notn);
currentBox.insertBefore(notn, currentBox.firstChild);
}
return notn;
},
_getNotificationWithValue: function(aValue) {
let notn;
let allNotificationBoxes = this._notificationBoxes;
for(let box of allNotificationBoxes) {
notn = box.getNotificationWithValue(aValue);
if (notn) {
break;
}
}
return notn;
},
_restartWithActiveDownloads: function() {
let activeDownloads = this.manager.activeDownloads;
while (activeDownloads.hasMoreElements()) {
@ -140,9 +184,9 @@ var MetroDownloadsView = {
this._runDownloadBooleanMap.delete(aDownload.targetFile.path);
this._downloadCount--;
this._downloadsInProgress--;
if (this._downloadsInProgress <= 0) {
this._notificationBox.removeNotification(this._progressNotification);
this._progressNotification = null;
let notn = this._progressNotification;
if (notn && this._downloadsInProgress <= 0) {
this._notificationBox.removeNotification(notn);
}
} catch (ex) {
Util.dumpLn("Failed to cancel download, with id: "+aDownload.id+", download target URI spec: " + fileURI.spec);
@ -384,32 +428,35 @@ var MetroDownloadsView = {
},
onDownloadButton: function dv_onDownloadButton() {
if (this._downloadsInProgress) {
if (!this._removeNotification("download-progress")) {
this.updateInfobar();
}
} else if (this._downloadCount) {
if (!this._removeNotification("download-complete")) {
this._showDownloadCompleteNotification();
}
let progressNotification = this._getNotificationWithValue("download-progress");
let wasProgressVisible = (progressNotification &&
progressNotification.parentNode == this._notificationBox);
let completeNotification = this._getNotificationWithValue("download-complete");
let wasCompleteVisible = (completeNotification &&
completeNotification.parentNode == this._notificationBox);
this._removeNotification("download-complete");
this._removeNotification("download-progress");
if (this._downloadsInProgress && !wasProgressVisible) {
this.updateInfobar();
} else if (this._downloadCount && !wasCompleteVisible) {
this._showDownloadCompleteNotification();
}
},
_removeNotification: function (aValue) {
let notification = this._notificationBox.getNotificationWithValue(aValue);
if (!notification) {
return false;
}
this._notificationBox.removeNotification(notification);
return true;
let notification = this._getNotificationWithValue(aValue);
return notification &&
notification.parentNode.removeNotification(notification);
},
updateInfobar: function dv_updateInfobar() {
let message = this._computeDownloadProgressString();
this._updateCircularProgressMeter();
if (this._progressNotification == null ||
!this._notificationBox.getNotificationWithValue("download-progress")) {
let notn = this._progressNotification;
if (!notn) {
let cancelButtonText =
Strings.browser.GetStringFromName("downloadCancel");
@ -425,23 +472,23 @@ var MetroDownloadsView = {
}
];
this._progressNotification =
this.showNotification("download-progress", message, buttons,
this._notificationBox.PRIORITY_WARNING_LOW);
notn = this.showNotification("download-progress", message, buttons,
this._notificationBox.PRIORITY_WARNING_LOW);
ContextUI.displayNavbar();
} else {
this._progressNotification.label = message;
notn.label = message;
}
},
updateDownload: function dv_updateDownload(aDownload) {
if (this._progressNotification != null) {
this._saveDownloadData(aDownload);
this._progressNotification.label =
this._saveDownloadData(aDownload);
let notn = this._progressNotification;
if (notn) {
notn.label =
this._computeDownloadProgressString(aDownload);
this._updateCircularProgressMeter();
}
this._updateCircularProgressMeter();
},
watchDownload: function dv_watchDownload(aDownload) {
@ -486,8 +533,9 @@ var MetroDownloadsView = {
this._showDownloadCompleteToast();
this._showDownloadCompleteNotification();
}
this._notificationBox.removeNotification(this._progressNotification);
this._progressNotification = null;
let notn = this._progressNotification;
if (notn)
this._notificationBox.removeNotification(notn);
}
break;
case "dl-failed":
@ -497,6 +545,22 @@ var MetroDownloadsView = {
}
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case 'TabClose': {
let browser = aEvent.originalTarget.linkedBrowser;
dump("DownloadNotificationsView handleEvent, got TabClose event for browser: "+browser+"\n");
let notn = this._getNotificationWithValue("download-progress");
if (notn && notn.defaultView == browser.contentWindow) {
let nextTab = Browser.getNextTab(aEvent.originalTarget);
let box = Browser.getNotificationBox(nextTab.linkedBrowser);
box.insertBefore(notn, box.firstChild);
}
break;
}
}
},
QueryInterface: function (aIID) {
if (!aIID.equals(Ci.nsIObserver) &&
!aIID.equals(Ci.nsISupportsWeakReference) &&

View File

@ -467,7 +467,7 @@
cursor: text;
}
.variable-or-property:not([non-header]) > .variables-view-element-details {
.variable-or-property:not([untitled]) > .variables-view-element-details {
-moz-margin-start: 10px;
}
@ -632,7 +632,7 @@
min-height: 24px;
}
.variable-or-property[non-match] {
.variable-or-property[unmatched] {
border: none;
margin: 0;
}

View File

@ -461,7 +461,7 @@
cursor: text;
}
.variable-or-property:not([non-header]) > .variables-view-element-details {
.variable-or-property:not([untitled]) > .variables-view-element-details {
-moz-margin-start: 10px;
}
@ -626,7 +626,7 @@
min-height: 24px;
}
.variable-or-property[non-match] {
.variable-or-property[unmatched] {
border: none;
margin: 0;
}

View File

@ -488,16 +488,16 @@
color: #b6babf;
margin: 0;
padding: 0;
border-left: 1px solid #42484f;
-moz-border-start: 1px solid #42484f;
-moz-box-align: center;
}
.devtools-tab:first-child {
border-left-width: 0;
-moz-border-start-width: 0;
}
.devtools-tab:last-child {
border-right: 1px solid #5a6169;
-moz-border-end: 1px solid #42484f;
}
.devtools-tab > image {
@ -522,7 +522,7 @@
}
.devtools-tab:active > image,
.devtools-tab[selected=true] > label {
.devtools-tab[selected=true] > image {
opacity: 1;
}
@ -546,12 +546,16 @@
}
.devtools-tab[selected=true]:not(:first-child) {
padding-left: 1px;
-moz-padding-start: 1px;
}
.devtools-tab[selected=true]:last-child {
-moz-padding-end: 1px;
}
.devtools-tab[selected=true] + .devtools-tab {
border-left-width: 0;
padding-left: 1px;
-moz-border-start-width: 0;
-moz-padding-start: 1px;
}
.devtools-tab:not([selected=true]).highlighted {

View File

@ -464,7 +464,7 @@
cursor: text;
}
.variable-or-property:not([non-header]) > .variables-view-element-details {
.variable-or-property:not([untitled]) > .variables-view-element-details {
-moz-margin-start: 10px;
}
@ -629,7 +629,7 @@
min-height: 24px;
}
.variable-or-property[non-match] {
.variable-or-property[unmatched] {
border: none;
margin: 0;
}

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
28.0a1
29.0a1

View File

@ -1763,7 +1763,29 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
}
OutputMediaStream* out = mOutputStreams.AppendElement();
#ifdef DEBUG
// Estimate hints based on the type of the media element
// under the preference media.capturestream_hints for the
// debug builds only. This allows WebRTC Peer Connection
// to behave appropriately when media streams generated
// via mozCaptureStream*() are added to the Peer Connection.
// This functionality is planned to be used as part of Audio
// Quality Performance testing for WebRTC.
// Bug932845: Revisit this once hints mechanism is dealt with
// holistically.
uint8_t hints = 0;
if (Preferences::GetBool("media.capturestream_hints.enabled")) {
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
if (video && GetVideoFrameContainer()) {
hints = DOMMediaStream::HINT_CONTENTS_VIDEO | DOMMediaStream::HINT_CONTENTS_AUDIO;
} else {
hints = DOMMediaStream::HINT_CONTENTS_AUDIO;
}
}
out->mStream = DOMMediaStream::CreateTrackUnionStream(window, hints);
#else
out->mStream = DOMMediaStream::CreateTrackUnionStream(window);
#endif
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
out->mStream->CombineWithPrincipal(principal);
out->mFinishWhenEnded = aFinishWhenEnded;

View File

@ -25,7 +25,7 @@ public:
}
static BluetoothHidManager* Get();
~BluetoothHidManager();
virtual ~BluetoothHidManager();
// HID-specific functions
void HandleInputPropertyChanged(const BluetoothSignal& aSignal);

View File

@ -187,9 +187,9 @@ BluetoothProfileController::Next()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mDeviceAddress.IsEmpty());
MOZ_ASSERT(mProfilesIndex < mProfiles.Length());
MOZ_ASSERT(mProfilesIndex < (int)mProfiles.Length());
if (++mProfilesIndex < mProfiles.Length()) {
if (++mProfilesIndex < (int)mProfiles.Length()) {
BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
if (mConnect) {

View File

@ -26,6 +26,7 @@ public:
NS_DECL_NSIICCLISTENER
IccListener() { }
virtual ~IccListener() { }
bool Listen(bool aStart);
void SetOwner(BluetoothRilListener *aOwner);
@ -42,6 +43,7 @@ public:
MobileConnectionListener(uint32_t aClientId)
: mClientId(aClientId) { }
virtual ~MobileConnectionListener() { }
bool Listen(bool aStart);
@ -56,6 +58,7 @@ public:
NS_DECL_NSITELEPHONYLISTENER
TelephonyListener() { }
virtual ~TelephonyListener() { }
bool Listen(bool aStart);
};

View File

@ -172,20 +172,6 @@ public:
const BluetoothNamedValue& aValue,
BluetoothReplyRunnable* aRunnable) = 0;
/**
* Get the path of a device
*
* @param aAdapterPath Path to the Adapter that's communicating with the device
* @param aDeviceAddress Device address (XX:XX:XX:XX:XX:XX format)
* @param aDevicePath Return value of path
*
* @return True if path set correctly, false otherwise
*/
virtual bool
GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath) = 0;
virtual nsresult
CreatePairedDeviceInternal(const nsAString& aAddress,
int aTimeout,
@ -195,12 +181,6 @@ public:
RemoveDeviceInternal(const nsAString& aObjectPath,
BluetoothReplyRunnable* aRunnable) = 0;
virtual nsresult
GetScoSocket(const nsAString& aObjectPath,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer) = 0;
/**
* Get corresponding service channel of specific service on remote device.
* It's usually the very first step of establishing an outbound connection.

View File

@ -95,7 +95,7 @@ GetAddressFromObjectPath(const nsAString& aObjectPath)
nsString address(aObjectPath);
int addressHead = address.RFind("/") + 5;
MOZ_ASSERT(addressHead + BLUETOOTH_ADDRESS_LENGTH == address.Length());
MOZ_ASSERT(addressHead + BLUETOOTH_ADDRESS_LENGTH == (int)address.Length());
address.Cut(0, addressHead);
address.ReplaceChar('_', ':');

View File

@ -32,7 +32,7 @@ public:
};
static BluetoothA2dpManager* Get();
~BluetoothA2dpManager();
virtual ~BluetoothA2dpManager();
void ResetA2dp();
void ResetAvrcp();

View File

@ -84,7 +84,7 @@ public:
}
static BluetoothHfpManager* Get();
~BluetoothHfpManager();
virtual ~BluetoothHfpManager();
bool ConnectSco();
bool DisconnectSco();

View File

@ -261,7 +261,7 @@ BluetoothOppManager::ConnectInternal(const nsAString& aDeviceAddress)
}
mSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, false, true);
mSocket->Connect(aDeviceAddress, -1);
}
@ -295,7 +295,7 @@ BluetoothOppManager::Listen()
}
mServerSocket =
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
new BluetoothSocket(this, BluetoothSocketType::RFCOMM, false, true);
if (!mServerSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
BT_WARNING("[OPP] Can't listen on RFCOMM socket!");
@ -315,7 +315,7 @@ BluetoothOppManager::StartSendingNextFile()
MOZ_ASSERT(!IsConnected());
MOZ_ASSERT(!mBatches.IsEmpty());
MOZ_ASSERT(mBatches[0].mBlobs.Length() > mCurrentBlobIndex + 1);
MOZ_ASSERT((int)mBatches[0].mBlobs.Length() > mCurrentBlobIndex + 1);
mBlob = mBatches[0].mBlobs[++mCurrentBlobIndex];

View File

@ -45,7 +45,7 @@ public:
static const int DEFAULT_OPP_CHANNEL = 10;
static const int MAX_PACKET_LENGTH = 0xFFFE;
~BluetoothOppManager();
virtual ~BluetoothOppManager();
static BluetoothOppManager* Get();
void ClientDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
void ServerDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);

View File

@ -965,13 +965,6 @@ BluetoothServiceBluedroid::StopDiscoveryInternal(
return NS_OK;
}
nsresult
BluetoothServiceBluedroid::GetDevicePropertiesInternal(
const BluetoothSignal& aSignal)
{
return NS_OK;
}
nsresult
BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
const BluetoothNamedValue& aValue,
@ -1033,56 +1026,6 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
return NS_OK;
}
bool
BluetoothServiceBluedroid::GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath)
{
return true;
}
bool
BluetoothServiceBluedroid::AddServiceRecords(const char* serviceName,
unsigned long long uuidMsb,
unsigned long long uuidLsb,
int channel)
{
return true;
}
bool
BluetoothServiceBluedroid::RemoveServiceRecords(const char* serviceName,
unsigned long long uuidMsb,
unsigned long long uuidLsb,
int channel)
{
return true;
}
bool
BluetoothServiceBluedroid::AddReservedServicesInternal(
const nsTArray<uint32_t>& aServices,
nsTArray<uint32_t>& aServiceHandlesContainer)
{
return true;
}
bool
BluetoothServiceBluedroid::RemoveReservedServicesInternal(
const nsTArray<uint32_t>& aServiceHandles)
{
return true;
}
nsresult
BluetoothServiceBluedroid::GetScoSocket(
const nsAString& aObjectPath, bool aAuth, bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer)
{
return NS_OK;
}
nsresult
BluetoothServiceBluedroid::GetServiceChannel(
const nsAString& aDeviceAddress,

View File

@ -49,44 +49,11 @@ public:
virtual nsresult StartDiscoveryInternal(BluetoothReplyRunnable* aRunnable);
virtual nsresult StopDiscoveryInternal(BluetoothReplyRunnable* aRunnable);
virtual nsresult
GetDevicePropertiesInternal(const BluetoothSignal& aSignal);
virtual nsresult
SetProperty(BluetoothObjectType aType,
const BluetoothNamedValue& aValue,
BluetoothReplyRunnable* aRunnable);
virtual bool
GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath);
static bool
AddServiceRecords(const char* serviceName,
unsigned long long uuidMsb,
unsigned long long uuidLsb,
int channel);
static bool
RemoveServiceRecords(const char* serviceName,
unsigned long long uuidMsb,
unsigned long long uuidLsb,
int channel);
static bool
AddReservedServicesInternal(const nsTArray<uint32_t>& aServices,
nsTArray<uint32_t>& aServiceHandlesContainer);
static bool
RemoveReservedServicesInternal(const nsTArray<uint32_t>& aServiceHandles);
virtual nsresult
GetScoSocket(const nsAString& aObjectPath,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer);
virtual nsresult
GetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,

View File

@ -33,7 +33,7 @@ public:
};
static BluetoothA2dpManager* Get();
~BluetoothA2dpManager();
virtual ~BluetoothA2dpManager();
void ResetA2dp();
void ResetAvrcp();

View File

@ -1018,7 +1018,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
for (uint8_t i = 0; i < atCommandValues.Length(); i++) {
CINDType indicatorType = (CINDType) (i + 1);
if (indicatorType >= ArrayLength(sCINDItems)) {
if (indicatorType >= (int)ArrayLength(sCINDItems)) {
// Ignore excess parameters at the end
break;
}
@ -1802,15 +1802,8 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
if (sInShutdown) {
BT_WARNING("ConnecteSco called while in shutdown!");
return false;
}
if (!IsConnected()) {
BT_WARNING("BluetoothHfpManager is not connected");
return false;
}
NS_ENSURE_TRUE(!sInShutdown, false);
NS_ENSURE_TRUE(IsConnected(), false);
SocketConnectionStatus status = mScoSocket->GetConnectionStatus();
if (status == SocketConnectionStatus::SOCKET_CONNECTED ||
@ -1828,16 +1821,14 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
return false;
}
// Stop listening
mScoSocket->Disconnect();
mScoRunnable = aRunnable;
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, false);
nsresult rv = bs->GetScoSocket(mDeviceAddress, true, false, mScoSocket);
mScoSocket->Connect(NS_ConvertUTF16toUTF8(mDeviceAddress), -1);
mScoSocketStatus = mScoSocket->GetConnectionStatus();
return NS_SUCCEEDED(rv);
mScoRunnable = aRunnable;
return true;
}
bool

View File

@ -331,7 +331,7 @@ BluetoothOppManager::StartSendingNextFile()
MOZ_ASSERT(!IsConnected());
MOZ_ASSERT(!mBatches.IsEmpty());
MOZ_ASSERT(mBatches[0].mBlobs.Length() > mCurrentBlobIndex + 1);
MOZ_ASSERT((int)mBatches[0].mBlobs.Length() > mCurrentBlobIndex + 1);
mBlob = mBatches[0].mBlobs[++mCurrentBlobIndex];

View File

@ -45,7 +45,7 @@ public:
static const int DEFAULT_OPP_CHANNEL = 10;
static const int MAX_PACKET_LENGTH = 0xFFFE;
~BluetoothOppManager();
virtual ~BluetoothOppManager();
static BluetoothOppManager* Get();
void ClientDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
void ServerDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);

View File

@ -174,7 +174,7 @@ static const char* sBluetoothDBusSignals[] =
static nsRefPtr<RawDBusConnection> gThreadConnection;
// Only A2DP and HID are authorized.
static nsTArray<uint32_t> sAuthorizedServiceClass;
static nsTArray<BluetoothServiceClass> sAuthorizedServiceClass;
// The object path of adpater which should be updated after switching Bluetooth.
static nsString sAdapterPath;
@ -2366,7 +2366,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
return NS_OK;
}
MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
MOZ_ASSERT(aType < (int)ArrayLength(sBluetoothDBusIfaces));
MOZ_ASSERT(!sAdapterPath.IsEmpty());
const char* interface = sBluetoothDBusIfaces[aType];
@ -2439,15 +2439,6 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
return NS_OK;
}
bool
BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath)
{
aDevicePath = GetObjectPathFromAddress(aAdapterPath, aDeviceAddress);
return true;
}
nsresult
BluetoothDBusService::CreatePairedDeviceInternal(
const nsAString& aDeviceAddress,
@ -2979,32 +2970,6 @@ BluetoothDBusService::UpdateSdpRecords(const nsAString& aDeviceAddress,
DBUS_TYPE_INVALID);
}
nsresult
BluetoothDBusService::GetScoSocket(const nsAString& aAddress,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mConnection || !gThreadConnection) {
NS_ERROR("Bluetooth service not started yet!");
return NS_ERROR_FAILURE;
}
BluetoothUnixSocketConnector* c =
new BluetoothUnixSocketConnector(BluetoothSocketType::SCO, -1,
aAuth, aEncrypt);
if (!aConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(aAddress).get())) {
nsAutoString replyError;
replyError.AssignLiteral("SocketConnectionError");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
void
BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
BlobParent* aBlobParent,

View File

@ -54,21 +54,6 @@ public:
const BluetoothNamedValue& aValue,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual bool
GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath) MOZ_OVERRIDE;
static bool
AddReservedServicesInternal(const nsTArray<uint32_t>& aServices,
nsTArray<uint32_t>& aServiceHandlesContainer);
virtual nsresult
GetScoSocket(const nsAString& aObjectPath,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer) MOZ_OVERRIDE;
virtual nsresult
GetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,

View File

@ -148,25 +148,6 @@ BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType,
return NS_OK;
}
bool
BluetoothServiceChildProcess::GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath)
{
// XXXbent Right now this is adapted from BluetoothDBusService's
// GetObjectPathFromAddress. This is basically a sync call that cannot
// be forwarded to the parent process without blocking. Hopefully this
// can be reworked.
nsAutoString path(aAdapterPath);
path.AppendLiteral("/dev_");
path.Append(aDeviceAddress);
path.ReplaceChar(':', '_');
aDevicePath = path;
return true;
}
nsresult
BluetoothServiceChildProcess::CreatePairedDeviceInternal(
const nsAString& aAddress,
@ -188,16 +169,6 @@ BluetoothServiceChildProcess::RemoveDeviceInternal(
return NS_OK;
}
nsresult
BluetoothServiceChildProcess::GetScoSocket(
const nsAString& aObjectPath,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer)
{
MOZ_CRASH("This should never be called!");
}
nsresult
BluetoothServiceChildProcess::GetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,

View File

@ -66,11 +66,6 @@ public:
const BluetoothNamedValue& aValue,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual bool
GetDevicePath(const nsAString& aAdapterPath,
const nsAString& aDeviceAddress,
nsAString& aDevicePath) MOZ_OVERRIDE;
virtual nsresult
CreatePairedDeviceInternal(const nsAString& aAddress,
int aTimeout,
@ -80,12 +75,6 @@ public:
RemoveDeviceInternal(const nsAString& aObjectPath,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual nsresult
GetScoSocket(const nsAString& aObjectPath,
bool aAuth,
bool aEncrypt,
mozilla::ipc::UnixSocketConsumer* aConsumer) MOZ_OVERRIDE;
virtual nsresult
GetServiceChannel(const nsAString& aDeviceAddress,
const nsAString& aServiceUuid,

View File

@ -23,12 +23,31 @@ docShell.QueryInterface(Ci.nsIDocShellTreeItem).name = infos.name;
docShell.setFullscreenAllowed(infos.fullscreenAllowed);
if (!('BrowserElementIsPreloaded' in this)) {
try {
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
function parentDocShell(docshell) {
if (!docshell) {
return null;
}
let treeitem = docshell.QueryInterface(Ci.nsIDocShellTreeItem);
return treeitem.parent ? treeitem.parent.QueryInterface(Ci.nsIDocShell) : null;
}
function isTopBrowserElement(docShell) {
while (docShell) {
docShell = parentDocShell(docShell);
if (docShell && docShell.isBrowserOrApp) {
return false;
}
}
return true;
}
if (!('BrowserElementIsPreloaded' in this)) {
if (isTopBrowserElement(docShell) &&
Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
try {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
} catch (e) {
}
} catch (e) {
}
// Those are produc-specific files that's sometimes unavailable.
try {

View File

@ -400,7 +400,7 @@ ContactManager.prototype = {
},
_convertContacts: function(aContacts) {
let contacts = [];
let contacts = new this._window.Array();
for (let i in aContacts) {
contacts.push(this._convertContact(aContacts[i]));
}

View File

@ -9,7 +9,6 @@ this.EXPORTED_SYMBOLS = ['Keyboard'];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const kFormsFrameScript = 'chrome://global/content/forms.js';
Cu.import('resource://gre/modules/Services.jsm');
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -80,16 +79,6 @@ this.Keyboard = {
mm.addMessageListener('Forms:GetContext:Result:OK', this);
mm.addMessageListener('Forms:SetComposition:Result:OK', this);
mm.addMessageListener('Forms:EndComposition:Result:OK', this);
// When not running apps OOP, we need to load forms.js here since this
// won't happen from dom/ipc/preload.js
try {
if (Services.prefs.getBoolPref("dom.ipc.tabs.disabled") === true) {
mm.loadFrameScript(kFormsFrameScript, true);
}
} catch (e) {
dump('Error loading ' + kFormsFrameScript + ' as frame script: ' + e + '\n');
}
},
receiveMessage: function keyboardReceiveMessage(msg) {

View File

@ -26,7 +26,6 @@ XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () {
const RESIZE_SCROLL_DELAY = 20;
let HTMLDocument = Ci.nsIDOMHTMLDocument;
let HTMLElement = Ci.nsIDOMHTMLElement;
let HTMLHtmlElement = Ci.nsIDOMHTMLHtmlElement;
let HTMLBodyElement = Ci.nsIDOMHTMLBodyElement;
let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
@ -346,12 +345,6 @@ let FormAssistant = {
break;
}
// Only handle the event from our descendants
if (target instanceof HTMLElement &&
content.window != target.ownerDocument.defaultView.top) {
break;
}
if (isContentEditable(target)) {
this.showKeyboard(this.getTopLevelEditable(target));
this.updateSelection();

View File

@ -1348,17 +1348,6 @@ PreloadSlowThings()
TabChild::PreloadSlowThings();
#ifdef MOZ_NUWA_PROCESS
// After preload of slow things, start freezing threads.
if (IsNuwaProcess()) {
// Perform GC before freezing the Nuwa process to reduce memory usage.
ContentChild::GetSingleton()->RecvGarbageCollect();
MessageLoop::current()->
PostTask(FROM_HERE,
NewRunnableFunction(OnFinishNuwaPreparation));
}
#endif
}
bool
@ -1369,15 +1358,32 @@ ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
mAppInfo.buildID.Assign(buildID);
mAppInfo.name.Assign(name);
mAppInfo.UAName.Assign(UAName);
if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
return true;
}
// If we're part of the mozbrowser machinery, go ahead and start
// preloading things. We can only do this for mozbrowser because
// PreloadSlowThings() may set the docshell of the first TabChild
// inactive, and we can only safely restore it to active from
// BrowserElementChild.js.
if ((mIsForApp || mIsForBrowser) &&
Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
if ((mIsForApp || mIsForBrowser)
#ifdef MOZ_NUWA_PROCESS
&& !IsNuwaProcess()
#endif
) {
PreloadSlowThings();
}
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
ContentChild::GetSingleton()->RecvGarbageCollect();
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
}
#endif
return true;
}

View File

@ -1249,93 +1249,13 @@ ContentParent::ContentParent(mozIApplication* aApp,
Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
// Set the subprocess's priority. We do this early on because we're likely
// /lowering/ the process's CPU and memory priority, which it has inherited
// from this process.
//
// This call can cause us to send IPC messages to the child process, so it
// must come after the Open() call above.
ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
// NB: internally, this will send an IPC message to the child
// process to get it to create the CompositorChild. This
// message goes through the regular IPC queue for this
// channel, so delivery will happen-before any other messages
// we send. The CompositorChild must be created before any
// PBrowsers are created, because they rely on the Compositor
// already being around. (Creation is async, so can't happen
// on demand.)
bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
if (useOffMainThreadCompositing) {
DebugOnly<bool> opened = PCompositor::Open(this);
MOZ_ASSERT(opened);
if (Preferences::GetBool("layers.async-video.enabled",false)) {
opened = PImageBridge::Open(this);
MOZ_ASSERT(opened);
}
}
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
nsChromeRegistryChrome* chromeRegistry =
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
chromeRegistry->SendRegisteredChrome(this);
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
if (gAppData) {
nsCString version(gAppData->version);
nsCString buildID(gAppData->buildID);
nsCString name(gAppData->name);
nsCString UAName(gAppData->UAName);
// Sending all information to content process.
unused << SendAppInfo(version, buildID, name, UAName);
}
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
if (sheetService) {
// This looks like a lot of work, but in a normal browser session we just
// send two loads.
nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets();
for (uint32_t i = 0; i < agentSheets.Length(); i++) {
URIParams uri;
SerializeURI(agentSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
}
nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets();
for (uint32_t i = 0; i < userSheets.Length(); i++) {
URIParams uri;
SerializeURI(userSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
}
nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets();
for (uint32_t i = 0; i < authorSheets.Length(); i++) {
URIParams uri;
SerializeURI(authorSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
}
}
#ifdef MOZ_CONTENT_SANDBOX
// Bug 921817. We enable the sandbox in RecvSetProcessPrivileges,
// which is where a preallocated process drops unnecessary privileges,
// but a non-preallocated process will already have changed its
// uid/gid/etc immediately after forking. Thus, we send this message,
// which is otherwise a no-op, to sandbox it at an appropriate point
// during startup.
if (aOSPrivileges != base::PRIVILEGES_INHERIT) {
if (!SendSetProcessPrivileges(base::PRIVILEGES_INHERIT)) {
KillHard();
}
}
#endif
InitInternal(aInitialPriority,
true, /* Setup off-main thread compositing */
true /* Send registered chrome */);
}
#ifdef MOZ_NUWA_PROCESS
static const FileDescriptor*
static const mozilla::ipc::FileDescriptor*
FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
ProtocolId aProtoId)
{
@ -1401,8 +1321,9 @@ ContentParent::ContentParent(ContentParent* aTemplate,
priority = PROCESS_PRIORITY_FOREGROUND;
}
ProcessPriorityManager::SetProcessPriority(this, priority);
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
InitInternal(priority,
false, /* Setup Off-main thread compositing */
false /* Send registered chrome */);
}
#endif // MOZ_NUWA_PROCESS
@ -1432,6 +1353,101 @@ ContentParent::~ContentParent()
}
}
void
ContentParent::InitInternal(ProcessPriority aInitialPriority,
bool aSetupOffMainThreadCompositing,
bool aSendRegisteredChrome)
{
// Set the subprocess's priority. We do this early on because we're likely
// /lowering/ the process's CPU and memory priority, which it has inherited
// from this process.
//
// This call can cause us to send IPC messages to the child process, so it
// must come after the Open() call above.
ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
if (aSetupOffMainThreadCompositing) {
// NB: internally, this will send an IPC message to the child
// process to get it to create the CompositorChild. This
// message goes through the regular IPC queue for this
// channel, so delivery will happen-before any other messages
// we send. The CompositorChild must be created before any
// PBrowsers are created, because they rely on the Compositor
// already being around. (Creation is async, so can't happen
// on demand.)
bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
if (useOffMainThreadCompositing) {
DebugOnly<bool> opened = PCompositor::Open(this);
MOZ_ASSERT(opened);
if (Preferences::GetBool("layers.async-video.enabled",false)) {
opened = PImageBridge::Open(this);
MOZ_ASSERT(opened);
}
}
}
if (aSendRegisteredChrome) {
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
nsChromeRegistryChrome* chromeRegistry =
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
chromeRegistry->SendRegisteredChrome(this);
}
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
if (gAppData) {
nsCString version(gAppData->version);
nsCString buildID(gAppData->buildID);
nsCString name(gAppData->name);
nsCString UAName(gAppData->UAName);
// Sending all information to content process.
unused << SendAppInfo(version, buildID, name, UAName);
}
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
if (sheetService) {
// This looks like a lot of work, but in a normal browser session we just
// send two loads.
nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets();
for (uint32_t i = 0; i < agentSheets.Length(); i++) {
URIParams uri;
SerializeURI(agentSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
}
nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets();
for (uint32_t i = 0; i < userSheets.Length(); i++) {
URIParams uri;
SerializeURI(userSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
}
nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets();
for (uint32_t i = 0; i < authorSheets.Length(); i++) {
URIParams uri;
SerializeURI(authorSheets[i]->GetSheetURI(), uri);
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
}
}
#ifdef MOZ_CONTENT_SANDBOX
// Bug 921817. We enable the sandbox in RecvSetProcessPrivileges,
// which is where a preallocated process drops unnecessary privileges,
// but a non-preallocated process will already have changed its
// uid/gid/etc immediately after forking. Thus, we send this message,
// which is otherwise a no-op, to sandbox it at an appropriate point
// during startup.
if (mOSPrivileges != base::PRIVILEGES_INHERIT) {
if (!SendSetProcessPrivileges(base::PRIVILEGES_INHERIT)) {
KillHard();
}
}
#endif
}
bool
ContentParent::IsAlive()
{

View File

@ -265,6 +265,11 @@ private:
// The common initialization for the constructors.
void InitializeMembers();
// The common initialization logic shared by all constuctors.
void InitInternal(ProcessPriority aPriority,
bool aSetupOffMainThreadCompositing,
bool aSendRegisteredChrome);
virtual ~ContentParent();
void Init();

View File

@ -88,6 +88,7 @@ private:
void ObserveProcessShutdown(nsISupports* aSubject);
bool mEnabled;
bool mShutdown;
nsRefPtr<ContentParent> mPreallocatedAppProcess;
};
@ -114,6 +115,7 @@ PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
, mPreallocateAppProcessTask(nullptr)
, mIsNuwaReady(false)
#endif
, mShutdown(false)
{}
void
@ -124,6 +126,8 @@ PreallocatedProcessManagerImpl::Init()
if (os) {
os->AddObserver(this, "ipc:content-shutdown",
/* weakRef = */ false);
os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
/* weakRef = */ false);
}
RereadPrefs();
}
@ -138,6 +142,8 @@ PreallocatedProcessManagerImpl::Observe(nsISupports* aSubject,
} else if (!strcmp("nsPref:changed", aTopic)) {
// The only other observer we registered was for our prefs.
RereadPrefs();
} else if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
mShutdown = true;
} else {
MOZ_ASSERT(false);
}
@ -240,7 +246,7 @@ PreallocatedProcessManagerImpl::DelayedNuwaFork()
mPreallocateAppProcessTask = nullptr;
if (!mIsNuwaReady) {
if (!mPreallocatedAppProcess) {
if (!mPreallocatedAppProcess && !mShutdown) {
mPreallocatedAppProcess = ContentParent::RunNuwaProcess();
}
// else mPreallocatedAppProcess is starting. It will NuwaFork() when ready.
@ -281,6 +287,15 @@ PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
AutoJSContext cx;
nsCOMPtr<nsIMessageBroadcaster> ppmm =
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
nsresult rv = ppmm->BroadcastAsyncMessage(
NS_LITERAL_STRING("TEST-ONLY:nuwa-add-new-process"),
JSVAL_NULL, JSVAL_NULL, cx, 1);
}
if (!mNuwaForkWaitTasks.IsEmpty()) {
mNuwaForkWaitTasks.ElementAt(0)->Cancel();
mNuwaForkWaitTasks.RemoveElementAt(0);
@ -312,6 +327,14 @@ PreallocatedProcessManagerImpl::OnNuwaReady()
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
hal::PROCESS_PRIORITY_FOREGROUND);
mIsNuwaReady = true;
if (Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
AutoJSContext cx;
nsCOMPtr<nsIMessageBroadcaster> ppmm =
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
nsresult rv = ppmm->BroadcastAsyncMessage(
NS_LITERAL_STRING("TEST-ONLY:nuwa-ready"),
JSVAL_NULL, JSVAL_NULL, cx, 1);
}
NuwaFork();
}

View File

@ -0,0 +1,2 @@
[test_NuwaProcessCreation.html]
run-if = toolkit == 'gonk'

View File

@ -5,4 +5,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
MOCHITEST_MANIFESTS += ['mochitest.ini']

View File

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<!--
Test if Nuwa process created successfully.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
function TestLoader() {}
TestLoader.prototype = {
_waitingTask: 0,
onTestReady: null,
unlockTestReady: function() {
this._waitingTask--;
this._maybeLoadTest();
},
lockTestReady: function() {
this._waitingTask++;
},
_maybeLoadTest: function() {
if (this._waitingTask == 0) {
this.onTestReady();
}
}
}
var testLoader = new TestLoader();
testLoader.lockTestReady();
window.addEventListener('load', function() {
testLoader.unlockTestReady();
});
function setPref(pref, value) {
testLoader.lockTestReady();
if (value !== undefined && value !== null) {
SpecialPowers.pushPrefEnv({'set': [[pref, value]]}, function() { testLoader.unlockTestReady(); });
} else {
SpecialPowers.pushPrefEnv({'clear': [[pref]]}, function() { testLoader.unlockTestReady(); });
}
}
setPref('dom.ipc.processPriorityManager.testMode', true);
setPref('dom.ipc.processPriorityManager.enabled', true);
setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
function runTest()
{
// Shutdown preallocated process.
SpecialPowers.setBoolPref('dom.ipc.processPrelaunch.enabled', false);
let cpmm = SpecialPowers.Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(SpecialPowers.Ci.nsISyncMessageSender);
let seenNuwaReady = false;
let msgHandler = {
receiveMessage: function receiveMessage(msg) {
msg = SpecialPowers.wrap(msg);
if (msg.name == 'TEST-ONLY:nuwa-ready') {
ok(true, "Got nuwa-ready");
is(seenNuwaReady, false, "Already received nuwa ready");
seenNuwaReady = true;
} else if (msg.name == 'TEST-ONLY:nuwa-add-new-process') {
ok(true, "Got nuwa-add-new-process");
is(seenNuwaReady, true, "Receive nuwa-add-new-process before nuwa-ready");
testEnd();
}
}
};
let timeout = setTimeout(function() {
ok(false, "Nuwa process is not launched");
testEnd();
}, 60000);
function testEnd() {
cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
cpmm.removeMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
clearTimeout(timeout);
SimpleTest.finish();
}
cpmm.addMessageListener("TEST-ONLY:nuwa-ready", msgHandler);
cpmm.addMessageListener("TEST-ONLY:nuwa-add-new-process", msgHandler);
// Setting this pref to true should cause us to prelaunch a process.
SpecialPowers.setBoolPref('dom.ipc.processPrelaunch.enabled', true);
}
testLoader.onTestReady = runTest;
</script>
</body>
</html>

View File

@ -7,3 +7,9 @@ ifdef MOZ_WEBRTC_LEAKING_TESTS
MOCHITEST_FILES += \
$(NULL)
endif
ifdef MOZ_B2G_CAMERA
MOCHITEST_FILES += \
test_getUserMedia_permission.html \
$(NULL)
endif

View File

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=853356
-->
<head>
<meta charset="utf-8">
<title>mozGetUserMedia Permission Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=853356">Display camera/microphone permission acquisition prompt</a>
<script type="application/javascript">
var gCount = 0;
var gTests = [
{
constraints: {video: true, audio: false}
}
,
{
constraints: {video: false, audio: true}
}
,
{
constraints: {video: true, audio: true},
}
];
function gUM(data) {
var gum_success = function (stream) {
SimpleTest.info("TEST-INFO | Got succss callback for " + JSON.stringify(data.constraints));
var hasAudioTrack = stream.getAudioTracks().length > 0;
var hasVideoTrack = stream.getVideoTracks().length > 0;
is(data.constraints.audio, hasAudioTrack, "Request audio track:" +
data.constraints.audio + " contain audio track:" + hasAudioTrack);
is(data.constraints.video, hasVideoTrack, "Request video track:" +
data.constraints.video + " contain audio track:" + hasVideoTrack);
gCount++;
if (gCount < gTests.length) {
gUM(gTests[gCount]);
} else {
SimpleTest.finish();
}
}
var gum_fail = function () {
ok(false, "permission not granted for " + JSON.stringify(data.constraints));
SimpleTest.finish();
}
SimpleTest.info("TEST-INFO | Call getUserMedia for " + JSON.stringify(data.constraints));
navigator.mozGetUserMedia(data.constraints, gum_success, gum_fail);
}
SpecialPowers.pushPrefEnv({"set": [["media.navigator.permission.disabled", false]]},
function () {
SpecialPowers.addPermission('video-capture',
Ci.nsIPermissionManager.ALLOW_ACTION, document);
SpecialPowers.addPermission('audio-capture',
Ci.nsIPermissionManager.ALLOW_ACTION, document);
gUM(gTests[gCount]);
});
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -924,6 +924,7 @@ MobileMessageDatabaseService.prototype = {
// Participant store cursor iteration done.
if (!invalidParticipantIds.length) {
next();
return;
}
// Find affected thread.
@ -1619,10 +1620,14 @@ MobileMessageDatabaseService.prototype = {
function replaceShortMessageOnSave(aTransaction, aMessageStore,
aParticipantStore, aThreadStore,
aMessageRecord, aAddresses) {
let isReplaceTypePid = (aMessageRecord.pid) &&
((aMessageRecord.pid >= RIL.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_1 &&
aMessageRecord.pid <= RIL.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_7) ||
aMessageRecord.pid == RIL.PDU_PID_RETURN_CALL_MESSAGE);
if (aMessageRecord.type != "sms" ||
aMessageRecord.delivery != DELIVERY_RECEIVED ||
!(aMessageRecord.pid >= RIL.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_1 &&
aMessageRecord.pid <= RIL.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_7)) {
!isReplaceTypePid) {
this.realSaveRecord(aTransaction, aMessageStore, aParticipantStore,
aThreadStore, aMessageRecord, aAddresses);
return;

View File

@ -14,7 +14,7 @@ const SENDER_0 = "+1234567890";
const SENDER_1 = "+1234567891";
const PDU_PID_NORMAL = "00";
const PDU_PIDS = ["00", "41", "42", "43", "44", "45", "46", "47"];
const PDU_PIDS = ["00", "41", "42", "43", "44", "45", "46", "47", "5F"];
const PDU_DCS_NORMAL = "00";

View File

@ -24,7 +24,7 @@
using namespace mozilla::dom::network;
class MobileConnection::Listener : public nsIMobileConnectionListener
class MobileConnection::Listener MOZ_FINAL : public nsIMobileConnectionListener
{
MobileConnection* mMobileConnection;
@ -692,4 +692,4 @@ MobileConnection::NotifyRadioStateChanged()
}
return DispatchTrustedEvent(NS_LITERAL_STRING("radiostatechange"));
}
}

View File

@ -10,9 +10,19 @@
using namespace mozilla::dom::network;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MobileConnectionArray,
mWindow,
mMobileConnections)
NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnectionArray)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MobileConnectionArray)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
// Notify our mobile connections that we're going away.
tmp->DropConnections();
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MobileConnectionArray)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(MobileConnectionArray)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MobileConnectionArray)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MobileConnectionArray)
@ -38,6 +48,12 @@ MobileConnectionArray::MobileConnectionArray(nsPIDOMWindow* aWindow)
}
MobileConnectionArray::~MobileConnectionArray()
{
DropConnections();
}
void
MobileConnectionArray::DropConnections()
{
for (uint32_t i = 0; i < mMobileConnections.Length(); i++) {
mMobileConnections[i]->Shutdown();
@ -78,4 +94,4 @@ MobileConnectionArray::IndexedGetter(uint32_t aIndex, bool& aFound) const
aFound = aIndex < mMobileConnections.Length();
return aFound ? mMobileConnections[aIndex] : nullptr;
}
}

View File

@ -45,6 +45,8 @@ public:
private:
~MobileConnectionArray();
void DropConnections();
nsCOMPtr<nsPIDOMWindow> mWindow;
nsTArray<nsRefPtr<MobileConnection>> mMobileConnections;
};
@ -53,4 +55,4 @@ private:
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_network_MobileConnectionArray_h__
#endif // mozilla_dom_network_MobileConnectionArray_h__

View File

@ -2056,7 +2056,12 @@ RadioInterface.prototype = {
mwi.returnMessage = message.fullBody;
gMessageManager.sendVoicemailMessage("RIL:VoicemailNotification",
this.clientId, mwi);
return true;
// Dicarded MWI comes without text body.
// Hence, we discard it here after notifying the MWI status.
if (mwi.discard) {
return true;
}
}
let notifyReceived = function notifyReceived(rv, domMessage) {

View File

@ -6965,17 +6965,6 @@ let GsmPDUHelper = {
case PDU_PID_ANSI_136_R_DATA:
case PDU_PID_USIM_DATA_DOWNLOAD:
return;
case PDU_PID_RETURN_CALL_MESSAGE:
// Level 1 of message waiting indication:
// Only a return call message is provided
let mwi = msg.mwi = {};
// TODO: When should we de-activate the level 1 indicator?
mwi.active = true;
mwi.discard = false;
mwi.msgCount = GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN;
if (DEBUG) debug("TP-PID got return call message: " + msg.sender);
return;
}
break;
}

View File

@ -56,44 +56,15 @@ function isVoicemailStatus(status) {
const MWI_PDU_PREFIX = "0000";
const MWI_PDU_UDH_PREFIX = "0040";
const MWI_PID_DEFAULT = "00";
const MWI_PID_RETURN_CALL_MSG = "5F";
const MWI_DCS_DATA_MSG = "F0";
const MWI_DCS_DISCARD_INACTIVE = "C0";
const MWI_DCS_DISCARD_ACTIVE = "C8";
const MWI_TIMESTAMP = "00000000000000";
const MWI_LEVEL1_SENDER = "+15125551234";
const MWI_LEVEL1_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL1_SENDER);
const MWI_DEFAULT_BODY = "1 new voicemail";
const MWI_UD_DEFAULT = PDUBuilder.buildUserData({
body: MWI_DEFAULT_BODY
});
// Level 1 Message Waiting is just a return call message
const MWI_LEVEL1_PDU =
MWI_PDU_PREFIX +
MWI_LEVEL1_PDU_ADDRESS +
MWI_PID_RETURN_CALL_MSG +
MWI_DCS_DATA_MSG +
MWI_TIMESTAMP +
MWI_UD_DEFAULT;
function testLevel1Indicator() {
function onLevel1Indicator(event) {
let status = event.status;
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, true);
is(status.messageCount, -1);
is(status.returnNumber, MWI_LEVEL1_SENDER);
is(status.returnMessage, MWI_DEFAULT_BODY);
isVoicemailStatus(status);
}
sendIndicatorPDU(MWI_LEVEL1_PDU, onLevel1Indicator, testLevel2DiscardActive);
}
const MWI_LEVEL2_SENDER = "+15125551235";
const MWI_LEVEL2_PDU_ADDRESS = PDUBuilder.buildAddress(MWI_LEVEL2_SENDER);
const MWI_LEVEL2_DISCARD_ACTIVE_PDU =
@ -234,4 +205,4 @@ function cleanUp() {
finish();
}
testLevel1Indicator();
testLevel2DiscardActive();

View File

@ -19,7 +19,6 @@
#include "mozilla/Monitor.h"
#include "mozilla/FileUtils.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "nsTArray.h"
#include "nsXULAppAPI.h"
@ -43,13 +42,15 @@ class UnixSocketImpl : public MessageLoopForIO::Watcher
{
public:
UnixSocketImpl(UnixSocketConsumer* aConsumer, UnixSocketConnector* aConnector,
const nsACString& aAddress)
const nsACString& aAddress,
SocketConnectionStatus aConnectionStatus)
: mConsumer(aConsumer)
, mIOLoop(nullptr)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mDelayedConnectTask(nullptr)
, mConnectionStatus(aConnectionStatus)
{
}
@ -245,6 +246,12 @@ private:
* Task member for delayed connect task. Should only be access on main thread.
*/
CancelableTask* mDelayedConnectTask;
/**
* Socket connection status. Duplicate from UnixSocketConsumer. Should only
* be accessed on I/O thread.
*/
SocketConnectionStatus mConnectionStatus;
};
template<class T>
@ -525,6 +532,7 @@ UnixSocketImpl::Accept()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -562,6 +570,7 @@ UnixSocketImpl::Connect()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -578,6 +587,7 @@ UnixSocketImpl::Connect()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
@ -586,6 +596,7 @@ UnixSocketImpl::Connect()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -609,6 +620,7 @@ UnixSocketImpl::Connect()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -624,6 +636,7 @@ UnixSocketImpl::Connect()
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_CONNECTED;
SetUpIO();
}
@ -720,8 +733,7 @@ UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!mShuttingDownOnIOThread);
SocketConnectionStatus status = mConsumer->GetConnectionStatus();
if (status == SOCKET_CONNECTED) {
if (mConnectionStatus == SOCKET_CONNECTED) {
// Read all of the incoming data.
while (true) {
nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
@ -764,9 +776,7 @@ UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
}
MOZ_CRASH("We returned early");
}
if (status == SOCKET_LISTENING) {
} else if (mConnectionStatus == SOCKET_LISTENING) {
int client_fd = accept(mFd.get(), (struct sockaddr*)&mAddr, &mAddrSize);
if (client_fd < 0) {
@ -791,6 +801,7 @@ UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_CONNECTED;
SetUpIO();
}
@ -803,8 +814,7 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
MOZ_ASSERT(!mShuttingDownOnIOThread);
MOZ_ASSERT(aFd >= 0);
SocketConnectionStatus status = mConsumer->GetConnectionStatus();
if (status == SOCKET_CONNECTED) {
if (mConnectionStatus == SOCKET_CONNECTED) {
// Try to write the bytes of mCurrentRilRawData. If all were written, continue.
//
// Otherwise, save the byte position of the next byte to write
@ -845,7 +855,7 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
mOutgoingQ.RemoveElementAt(0);
delete data;
}
} else if (status == SOCKET_CONNECTING) {
} else if (mConnectionStatus == SOCKET_CONNECTING) {
int error, ret;
socklen_t len = sizeof(error);
ret = getsockopt(mFd.get(), SOL_SOCKET, SO_ERROR, &error, &len);
@ -856,6 +866,7 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -864,6 +875,7 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
@ -873,12 +885,14 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_DISCONNECTED;
return;
}
nsRefPtr<OnSocketEventTask> t =
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
NS_DispatchToMainThread(t);
mConnectionStatus = SOCKET_CONNECTED;
SetUpIO();
}
@ -935,7 +949,7 @@ UnixSocketConsumer::ConnectSocket(UnixSocketConnector* aConnector,
}
nsCString addr(aAddress);
mImpl = new UnixSocketImpl(this, connector.forget(), addr);
mImpl = new UnixSocketImpl(this, connector.forget(), addr, SOCKET_CONNECTING);
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
mConnectionStatus = SOCKET_CONNECTING;
if (aDelayMs > 0) {
@ -961,7 +975,8 @@ UnixSocketConsumer::ListenSocket(UnixSocketConnector* aConnector)
return false;
}
mImpl = new UnixSocketImpl(this, connector.forget(), EmptyCString());
mImpl = new UnixSocketImpl(this, connector.forget(), EmptyCString(),
SOCKET_LISTENING);
mConnectionStatus = SOCKET_LISTENING;
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new SocketAcceptTask(mImpl));

View File

@ -22,6 +22,7 @@
#include "nsString.h"
#include "nsAutoPtr.h"
#include "mozilla/RefPtr.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace ipc {
@ -165,6 +166,7 @@ public:
SocketConnectionStatus GetConnectionStatus() const
{
MOZ_ASSERT(NS_IsMainThread());
return mConnectionStatus;
}

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
28.0a1
29.0a1

View File

@ -661,8 +661,7 @@ def run_tests_remote(tests, prefix, options):
Test.CacheDir = posixpath.join(options.remote_test_root, '.js-cache')
dm.mkDir(Test.CacheDir)
for path in os.listdir(JS_TESTS_DIR):
dm.pushDir(os.path.join(JS_TESTS_DIR, path), posixpath.join(jit_tests_dir, 'tests', path))
dm.pushDir(JS_TESTS_DIR, posixpath.join(jit_tests_dir, 'tests'), timeout=600)
dm.pushDir(os.path.dirname(TEST_DIR), options.remote_test_root, timeout=600)
prefix[0] = os.path.join(options.remote_test_root, 'js')

View File

@ -758,9 +758,11 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk(
if (chunk.mBuffer) {
switch (chunk.mBufferFormat) {
case AUDIO_FORMAT_FLOAT32:
MOZ_MTLOG(ML_ERROR, "Can't process audio except in 16-bit PCM yet");
MOZ_ASSERT(PR_FALSE);
return;
{
const float* buf = static_cast<const float *>(chunk.mChannelData[0]);
ConvertAudioSamplesWithScale(buf, static_cast<int16_t*>(samples),
chunk.mDuration, chunk.mVolume);
}
break;
case AUDIO_FORMAT_S16:
{

View File

@ -12,6 +12,7 @@ package org.webrtc.videoengine;
import java.io.IOException;
import java.util.Locale;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.webrtc.videoengine.CaptureCapabilityAndroid;
@ -285,6 +286,12 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
Camera.Parameters parameters = camera.getParameters();
List<String> focusModeList = parameters.getSupportedFocusModes();
if (focusModeList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
parameters.setPreviewSize(currentCapability.width,
currentCapability.height);
parameters.setPreviewFormat(PIXEL_FORMAT);

View File

@ -91,10 +91,14 @@ classes.dex: proguard-jars
@echo 'DX classes.dex'
$(DX) --dex --output=classes.dex jars-proguarded $(ANDROID_COMPAT_LIB)
ifdef MOZ_DEBUG
PROGUARD_PASSES=1
ifdef MOZ_DISABLE_PROGUARD
PROGUARD_PASSES=0
else
PROGUARD_PASSES=6
ifdef MOZ_DEBUG
PROGUARD_PASSES=1
else
PROGUARD_PASSES=6
endif
endif
proguard-jars: $(ALL_JARS)

View File

@ -19,6 +19,7 @@ import org.mozilla.gecko.db.BrowserContract.Schema;
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.db.BrowserContract.URLColumns;
import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.sync.Utils;
@ -67,6 +68,8 @@ public class BrowserProvider extends ContentProvider {
private static final String LOGTAG = "GeckoBrowserProvider";
private Context mContext;
private PerProfileDatabases<BrowserDatabaseHelper> mDatabases;
static final String DATABASE_NAME = "browser.db";
static final int DATABASE_VERSION = 17;
@ -313,8 +316,6 @@ public class BrowserProvider extends ContentProvider {
SEARCH_SUGGEST_PROJECTION_MAP = Collections.unmodifiableMap(map);
}
private HashMap<String, DatabaseHelper> mDatabasePerProfile;
private interface BookmarkMigrator {
public void updateForNewTable(ContentValues bookmark);
}
@ -364,8 +365,8 @@ public class BrowserProvider extends ContentProvider {
}
}
final class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String databasePath) {
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
public BrowserDatabaseHelper(Context context, String databasePath) {
super(context, databasePath, null, DATABASE_VERSION);
}
@ -1953,63 +1954,9 @@ public class BrowserProvider extends ContentProvider {
}
}
private DatabaseHelper getDatabaseHelperForProfile(String profile, boolean isTest) {
// Each profile has a separate browser.db database. The target
// profile is provided using a URI query argument in each request
// to our content provider.
// Always fallback to default profile if none has been provided.
if (TextUtils.isEmpty(profile)) {
profile = GeckoProfile.get(mContext).getName();
}
DatabaseHelper dbHelper;
synchronized (this) {
dbHelper = mDatabasePerProfile.get(profile);
if (dbHelper != null) {
return dbHelper;
}
String databasePath = getDatabasePath(profile, isTest);
// Before bug 768532, the database was located outside if the
// profile on Android 2.2. Make sure it is moved inside the profile
// directory.
if (Build.VERSION.SDK_INT == 8) {
File oldPath = mContext.getDatabasePath("browser-" + profile + ".db");
if (oldPath.exists()) {
oldPath.renameTo(new File(databasePath));
}
}
dbHelper = new DatabaseHelper(getContext(), databasePath);
mDatabasePerProfile.put(profile, dbHelper);
DBUtils.ensureDatabaseIsNotLocked(dbHelper, databasePath);
}
debug("Created database helper for profile: " + profile);
return dbHelper;
}
@RobocopTarget
public String getDatabasePath(String profile, boolean isTest) {
trace("Getting database path for profile: " + profile);
if (isTest) {
return DATABASE_NAME;
}
File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
debug("Couldn't find directory for profile: " + profile);
return null;
}
String databasePath = new File(profileDir, DATABASE_NAME).getAbsolutePath();
debug("Successfully created database path for profile: " + databasePath);
return databasePath;
return mDatabases.getDatabasePathForProfile(profile, isTest);
}
private SQLiteDatabase getReadableDatabase(Uri uri) {
@ -2020,7 +1967,7 @@ public class BrowserProvider extends ContentProvider {
if (uri != null)
profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE);
return getDatabaseHelperForProfile(profile, isTest(uri)).getReadableDatabase();
return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getReadableDatabase();
}
private SQLiteDatabase getWritableDatabase(Uri uri) {
@ -2031,7 +1978,7 @@ public class BrowserProvider extends ContentProvider {
if (uri != null)
profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE);
return getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase();
return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase();
}
private void cleanupSomeDeletedRecords(Uri fromUri, Uri targetUri, String tableName) {
@ -2178,7 +2125,13 @@ public class BrowserProvider extends ContentProvider {
synchronized (this) {
mContext = getContext();
mDatabasePerProfile = new HashMap<String, DatabaseHelper>();
mDatabases = new PerProfileDatabases<BrowserDatabaseHelper>(
getContext(), DATABASE_NAME, new DatabaseHelperFactory<BrowserDatabaseHelper>() {
@Override
public BrowserDatabaseHelper makeDatabaseHelper(Context context, String databasePath) {
return new BrowserDatabaseHelper(context, databasePath);
}
});
}
return true;

View File

@ -0,0 +1,81 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
package org.mozilla.gecko.db;
import java.io.File;
import java.util.HashMap;
import org.mozilla.gecko.GeckoProfile;
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
/**
* Manages a set of per-profile database storage helpers.
*/
public class PerProfileDatabases<T extends SQLiteOpenHelper> {
private final HashMap<String, T> mStorages = new HashMap<String, T>();
private final Context mContext;
private final String mDatabaseName;
private final DatabaseHelperFactory<T> mHelperFactory;
public interface DatabaseHelperFactory<T> {
public T makeDatabaseHelper(Context context, String databasePath);
}
public PerProfileDatabases(final Context context, final String databaseName, final DatabaseHelperFactory<T> helperFactory) {
mContext = context;
mDatabaseName = databaseName;
mHelperFactory = helperFactory;
}
public String getDatabasePathForProfile(String profile) {
return getDatabasePathForProfile(profile, false);
}
public String getDatabasePathForProfile(String profile, boolean isTest) {
if (isTest) {
return mDatabaseName;
}
final File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
return null;
}
return new File(profileDir, mDatabaseName).getAbsolutePath();
}
public T getDatabaseHelperForProfile(String profile) {
return getDatabaseHelperForProfile(profile, false);
}
public T getDatabaseHelperForProfile(String profile, boolean isTest) {
// Always fall back to default profile if none has been provided.
if (TextUtils.isEmpty(profile)) {
profile = GeckoProfile.get(mContext).getName();
}
synchronized (this) {
if (mStorages.containsKey(profile)) {
return mStorages.get(profile);
}
final String databasePath = getDatabasePathForProfile(profile, isTest);
if (databasePath == null) {
throw new IllegalStateException("Database path is null for profile: " + profile);
}
final T helper = mHelperFactory.makeDatabaseHelper(mContext, databasePath);
DBUtils.ensureDatabaseIsNotLocked(helper, databasePath);
mStorages.put(profile, helper);
return helper;
}
}
}

View File

@ -12,6 +12,7 @@ import java.util.Map;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.db.BrowserContract.Clients;
import org.mozilla.gecko.db.BrowserContract.Tabs;
import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.content.ContentProvider;
@ -33,6 +34,8 @@ public class TabsProvider extends ContentProvider {
private static final String LOGTAG = "GeckoTabsProvider";
private Context mContext;
private PerProfileDatabases<TabsDatabaseHelper> mDatabases;
static final String DATABASE_NAME = "tabs.db";
static final int DATABASE_VERSION = 2;
@ -85,8 +88,6 @@ public class TabsProvider extends ContentProvider {
CLIENTS_PROJECTION_MAP = Collections.unmodifiableMap(map);
}
private HashMap<String, DatabaseHelper> mDatabasePerProfile;
static final String selectColumn(String table, String column) {
return table + "." + column + " = ?";
}
@ -107,8 +108,8 @@ public class TabsProvider extends ContentProvider {
}
}
final class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String databasePath) {
final class TabsDatabaseHelper extends SQLiteOpenHelper {
public TabsDatabaseHelper(Context context, String databasePath) {
super(context, databasePath, null, DATABASE_VERSION);
}
@ -207,59 +208,9 @@ public class TabsProvider extends ContentProvider {
}
}
private DatabaseHelper getDatabaseHelperForProfile(String profile) {
// Each profile has a separate tabs.db database. The target
// profile is provided using a URI query argument in each request
// to our content provider.
// Always fallback to default profile if none has been provided.
if (TextUtils.isEmpty(profile)) {
profile = GeckoProfile.get(getContext()).getName();
}
DatabaseHelper dbHelper;
synchronized (this) {
dbHelper = mDatabasePerProfile.get(profile);
if (dbHelper != null) {
return dbHelper;
}
String databasePath = getDatabasePath(profile);
// Before bug 768532, the database was located outside if the
// profile on Android 2.2. Make sure it is moved inside the profile
// directory.
if (Build.VERSION.SDK_INT == 8) {
File oldPath = mContext.getDatabasePath("tabs-" + profile + ".db");
if (oldPath.exists()) {
oldPath.renameTo(new File(databasePath));
}
}
dbHelper = new DatabaseHelper(getContext(), databasePath);
mDatabasePerProfile.put(profile, dbHelper);
DBUtils.ensureDatabaseIsNotLocked(dbHelper, databasePath);
}
debug("Created database helper for profile: " + profile);
return dbHelper;
}
@RobocopTarget
private String getDatabasePath(String profile) {
trace("Getting database path for profile: " + profile);
File profileDir = GeckoProfile.get(mContext, profile).getDir();
if (profileDir == null) {
debug("Couldn't find directory for profile: " + profile);
return null;
}
String databasePath = new File(profileDir, DATABASE_NAME).getAbsolutePath();
debug("Successfully created database path for profile: " + databasePath);
return databasePath;
return mDatabases.getDatabasePathForProfile(profile);
}
private SQLiteDatabase getReadableDatabase(Uri uri) {
@ -270,7 +221,7 @@ public class TabsProvider extends ContentProvider {
if (uri != null)
profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE);
return getDatabaseHelperForProfile(profile).getReadableDatabase();
return mDatabases.getDatabaseHelperForProfile(profile).getReadableDatabase();
}
private SQLiteDatabase getWritableDatabase(Uri uri) {
@ -281,7 +232,7 @@ public class TabsProvider extends ContentProvider {
if (uri != null)
profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE);
return getDatabaseHelperForProfile(profile).getWritableDatabase();
return mDatabases.getDatabaseHelperForProfile(profile).getWritableDatabase();
}
@Override
@ -290,7 +241,13 @@ public class TabsProvider extends ContentProvider {
synchronized (this) {
mContext = getContext();
mDatabasePerProfile = new HashMap<String, DatabaseHelper>();
mDatabases = new PerProfileDatabases<TabsDatabaseHelper>(
getContext(), DATABASE_NAME, new DatabaseHelperFactory<TabsDatabaseHelper>() {
@Override
public TabsDatabaseHelper makeDatabaseHelper(Context context, String databasePath) {
return new TabsDatabaseHelper(context, databasePath);
}
});
}
return true;

View File

@ -117,6 +117,7 @@ gbjar.sources += [
'db/LocalBrowserDB.java',
'db/PasswordsProvider.java',
'db/PerProfileContentProvider.java',
'db/PerProfileDatabases.java',
'db/TabsProvider.java',
'Distribution.java',
'DoorHanger.java',

View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=Fennec
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=28.0a1
MOZ_APP_VERSION=29.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial

View File

@ -14,6 +14,9 @@
#include "nsNetUtil.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsISystemProxySettings.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
//-----------------------------------------------------------------------------
using namespace mozilla;
@ -674,6 +677,13 @@ nsPACMan::NamePACThread()
{
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread");
PR_SetCurrentThreadName("Proxy Resolution");
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
"NuwaMarkCurrentThread is undefined!");
NuwaMarkCurrentThread(nullptr, nullptr);
}
#endif
}
nsresult

View File

@ -207,7 +207,16 @@ void RTSPSource::performPlay(int64_t playTimeUs) {
if (mState == PAUSING) {
playTimeUs = mLatestPausedUnit;
}
LOGI("performPlay : %lld", playTimeUs);
int64_t duration = 0;
getDuration(&duration);
MOZ_ASSERT(playTimeUs < duration,
"Should never receive an out of bounds play time!");
if (playTimeUs >= duration) {
return;
}
LOGI("performPlay : duration=%lld playTimeUs=%lld", duration, playTimeUs);
mState = PLAYING;
mHandler->play(playTimeUs);
}
@ -238,13 +247,22 @@ void RTSPSource::performSeek(int64_t seekTimeUs) {
if (mState != PLAYING && mState != PAUSING) {
return;
}
LOGI("performSeek: %llu", seekTimeUs);
int64_t duration = 0;
getDuration(&duration);
MOZ_ASSERT(seekTimeUs < duration,
"Should never receive an out of bounds seek time!");
if (seekTimeUs >= duration) {
return;
}
for (size_t i = 0; i < mTracks.size(); ++i) {
TrackInfo *info = &mTracks.editItemAt(i);
info->mLatestPausedUnit = 0;
mLatestPausedUnit = 0;
}
LOGI("performSeek: %llu", seekTimeUs);
mState = SEEKING;
mHandler->seek(seekTimeUs);
}

View File

@ -4,8 +4,6 @@
# 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/.
FAIL_ON_WARNINGS = True
XPIDL_SOURCES += [
'nsIWifiAccessPoint.idl',
'nsIWifiListener.idl',
@ -27,9 +25,10 @@ else:
'nsWifiMonitor.cpp',
]
# osx_corewlan.mm has warnings I don't understand.
FAIL_ON_WARNINGS = CONFIG['OS_ARCH'] != 'Darwin'
if CONFIG['OS_ARCH'] == 'Darwin':
# osx_corewlan.mm has warnings I don't understand.
FAIL_ON_WARNINGS = False
UNIFIED_SOURCES += [
'nsWifiScannerMac.cpp',
]

View File

@ -1051,14 +1051,6 @@ class RecursiveMakeBackend(CommonBackend):
if not obj.dupe_manifest:
raise
for base, pattern, dest in obj.pattern_installs:
try:
self._install_manifests['tests'].add_pattern_symlink(base,
pattern, dest)
except ValueError:
if not obj.dupe_manifest:
raise
for dest in obj.external_installs:
try:
self._install_manifests['tests'].add_optional_exists(dest)

View File

@ -24,7 +24,7 @@ from mozbuild.util import (
shell_quote,
StrictOrderingOnAppendList,
)
from .sandbox_symbols import compute_final_target
from .sandbox_symbols import FinalTargetValue
class TreeMetadata(object):
@ -361,10 +361,6 @@ class TestManifest(SandboxDerived):
# path is relative from the tests root directory.
'installs',
# A list of pattern matching installs to perform. Entries are
# (base, pattern, dest).
'pattern_installs',
# Where all files for this manifest flavor are installed in the unified
# test package directory.
'install_prefix',
@ -404,7 +400,6 @@ class TestManifest(SandboxDerived):
self.manifest_relpath = relpath
self.dupe_manifest = dupe_manifest
self.installs = {}
self.pattern_installs = []
self.tests = []
self.external_installs = set()
@ -504,6 +499,6 @@ class InstallationTarget(SandboxDerived):
"""Returns whether or not the target is not derived from the default
given xpiname and subdir."""
return compute_final_target(dict(
return FinalTargetValue(dict(
XPI_NAME=self.xpiname,
DIST_SUBDIR=self.subdir)) == self.target

View File

@ -15,6 +15,8 @@ from mach.mixin.logging import LoggingMixin
import mozpack.path as mozpath
import manifestparser
from mozpack.files import FileFinder
from .data import (
ConfigFileSubstitution,
Defines,
@ -256,6 +258,16 @@ class TreeMetadataEmitter(LoggingMixin):
l = passthru.variables.setdefault('GARBAGE', [])
l.append(f)
no_pgo = sandbox.get('NO_PGO')
sources = sandbox.get('SOURCES', [])
no_pgo_sources = [f for f in sources if sources[f].no_pgo]
if no_pgo:
if no_pgo_sources:
raise SandboxValidationError('NO_PGO and SOURCES[...].no_pgo cannot be set at the same time')
passthru.variables['NO_PROFILE_GUIDED_OPTIMIZE'] = no_pgo
if no_pgo_sources:
passthru.variables['NO_PROFILE_GUIDED_OPTIMIZE'] = no_pgo_sources
exports = sandbox.get('EXPORTS')
if exports:
yield Exports(sandbox, exports,
@ -393,6 +405,8 @@ class TreeMetadataEmitter(LoggingMixin):
out_dir = mozpath.join(install_prefix, manifest_reldir)
finder = FileFinder(base=manifest_dir, find_executables=False)
# "head" and "tail" lists.
# All manifests support support-files.
#
@ -417,9 +431,22 @@ class TreeMetadataEmitter(LoggingMixin):
for pattern in value.split():
# We only support globbing on support-files because
# the harness doesn't support * for head and tail.
#
# While we could feed everything through the finder, we
# don't because we want explicitly listed files that
# no longer exist to raise an error. The finder is also
# slower than simple lookup.
if '*' in pattern and thing == 'support-files':
obj.pattern_installs.append(
(manifest_dir, pattern, out_dir))
paths = [f[0] for f in finder.find(pattern)]
if not paths:
raise SandboxValidationError('%s support-files '
'wildcard in %s returns no results.' % (
pattern, path))
for f in paths:
full = mozpath.normpath(mozpath.join(manifest_dir, f))
obj.installs[full] = mozpath.join(out_dir, f)
else:
full = mozpath.normpath(mozpath.join(manifest_dir,
pattern))

View File

@ -185,9 +185,9 @@ class MozbuildSandbox(Sandbox):
for name, func in FUNCTIONS.items():
d[name] = getattr(self, func[0])
# Initialize the exports that we need in the global.
extra_vars = self.metadata.get('exports', dict())
self._globals.update(extra_vars)
# Initialize the exports that we need in the global.
extra_vars = self.metadata.get('exports', dict())
self._globals.update(extra_vars)
def exec_file(self, path, filesystem_absolute=False):
"""Override exec_file to normalize paths and restrict file loading.

View File

@ -34,6 +34,12 @@ from mozbuild.util import (
)
class SandboxDerivedValue(object):
"""Classes deriving from this one receive a special treatment in a
sandbox GlobalNamespace. See GlobalNamespace documentation.
"""
def alphabetical_sorted(iterable, cmp=None, key=lambda x: x.lower(),
reverse=False):
"""sorted() replacement for the sandbox, ordering alphabetically by
@ -61,10 +67,17 @@ class GlobalNamespace(dict):
When variables are read, we first try to read the existing value. If a
value is not found and it is defined in the allowed variables set, we
return the default value for it. We don't assign default values until
they are accessed because this makes debugging the end-result much
simpler. Instead of a data structure with lots of empty/default values,
you have a data structure with only the values that were read or touched.
return a new instance of the class for that variable. We don't assign
default instances until they are accessed because this makes debugging
the end-result much simpler. Instead of a data structure with lots of
empty/default values, you have a data structure with only the values
that were read or touched.
Instances of variables classes are created by invoking class_name(),
except when class_name derives from SandboxDerivedValue, in which
case class_name(instance_of_the_global_namespace) is invoked.
A value is added to those calls when instances are created during
assignment (setitem).
Instantiators of this class are given a backdoor to perform setting of
arbitrary values. e.g.
@ -111,6 +124,8 @@ class GlobalNamespace(dict):
self._allow_all_writes = False
self._allow_one_mutation = set()
def __getitem__(self, name):
try:
return dict.__getitem__(self, name)
@ -126,22 +141,37 @@ class GlobalNamespace(dict):
# If the default is specifically a lambda (or, rather, any function--but
# not a class that can be called), then it is actually a rule to
# generate the default that should be used.
default_rule = default[2]
if isinstance(default_rule, type(lambda: None)):
default_rule = default_rule(self)
default = default[0]
if issubclass(default, SandboxDerivedValue):
value = default(self)
else:
value = default()
dict.__setitem__(self, name, copy.deepcopy(default_rule))
dict.__setitem__(self, name, value)
return dict.__getitem__(self, name)
def __setitem__(self, name, value):
if self._allow_all_writes:
dict.__setitem__(self, name, value)
self._allow_one_mutation.add(name)
return
# Forbid assigning over a previously set value. Interestingly, when
# doing FOO += ['bar'], python actually does something like:
# foo = namespace.__getitem__('FOO')
# foo.__iadd__(['bar'])
# namespace.__setitem__('FOO', foo)
# This means __setitem__ is called with the value that is already
# in the dict, when doing +=, which is permitted.
if name in self._allow_one_mutation:
self._allow_one_mutation.remove(name)
elif name in self and dict.__getitem__(self, name) is not value:
raise Exception('Reassigning %s is forbidden' % name)
# We don't need to check for name.isupper() here because LocalNamespace
# only sends variables our way if isupper() is True.
stored_type, input_type, default, docs, tier = \
self._allowed_variables.get(name, (None, None, None, None, None))
stored_type, input_type, docs, tier = \
self._allowed_variables.get(name, (None, None, None, None))
# Variable is unknown.
if stored_type is None:
@ -160,7 +190,10 @@ class GlobalNamespace(dict):
value, input_type)
raise self.last_name_error
value = stored_type(value)
if issubclass(stored_type, SandboxDerivedValue):
value = stored_type(self, value)
else:
value = stored_type(value)
dict.__setitem__(self, name, value)
@ -177,6 +210,11 @@ class GlobalNamespace(dict):
yield self
self._allow_all_writes = False
# dict.update doesn't call our __setitem__, so we have to override it.
def update(self, other):
for name, value in other.items():
self.__setitem__(name, value)
class LocalNamespace(dict):
"""Represents the locals namespace in a Sandbox.
@ -382,6 +420,6 @@ class Sandbox(object):
return self._globals.get(key, default)
def get_affected_tiers(self):
tiers = (self._allowed_variables[key][4] for key in self
tiers = (self._allowed_variables[key][3] for key in self
if key in self._allowed_variables)
return set(tier for tier in tiers if tier)

View File

@ -21,26 +21,30 @@ from collections import OrderedDict
from mozbuild.util import (
HierarchicalStringList,
StrictOrderingOnAppendList,
StrictOrderingOnAppendListWithFlagsFactory,
)
from .sandbox import SandboxDerivedValue
from types import StringTypes
class FinalTargetValue(SandboxDerivedValue, unicode):
def __new__(cls, sandbox, value=""):
if not value:
value = 'dist/'
if sandbox['XPI_NAME']:
value += 'xpi-stage/' + sandbox['XPI_NAME']
else:
value += 'bin'
if sandbox['DIST_SUBDIR']:
value += '/' + sandbox['DIST_SUBDIR']
return unicode.__new__(cls, value)
def compute_final_target(variables):
"""Convert the default value for FINAL_TARGET"""
basedir = 'dist/'
if variables['XPI_NAME']:
basedir += 'xpi-stage/' + variables['XPI_NAME']
else:
basedir += 'bin'
if variables['DIST_SUBDIR']:
basedir += '/' + variables['DIST_SUBDIR']
return basedir
# This defines the set of mutable global variables.
#
# Each variable is a tuple of:
#
# (storage_type, input_types, default_value, docs, tier)
# (storage_type, input_types, docs, tier)
#
# Tier says for which specific tier the variable has an effect.
# Valid tiers are:
@ -55,7 +59,7 @@ def compute_final_target(variables):
VARIABLES = {
# Variables controlling reading of other frontend files.
'ANDROID_GENERATED_RESFILES': (StrictOrderingOnAppendList, list, [],
'ANDROID_GENERATED_RESFILES': (StrictOrderingOnAppendList, list,
"""Android resource files generated as part of the build.
This variable contains a list of files that are expected to be
@ -64,33 +68,33 @@ VARIABLES = {
file.
""", 'export'),
'ANDROID_RESFILES': (StrictOrderingOnAppendList, list, [],
'ANDROID_RESFILES': (StrictOrderingOnAppendList, list,
"""Android resource files.
This variable contains a list of files to package into a 'res'
directory and merge into an APK file.
""", 'export'),
'SOURCES': (StrictOrderingOnAppendList, list, [],
'SOURCES': (StrictOrderingOnAppendListWithFlagsFactory({'no_pgo': bool}), list,
"""Source code files.
This variable contains a list of source code files to compile.
Accepts assembler, C, C++, Objective C/C++.
""", 'compile'),
'GENERATED_SOURCES': (StrictOrderingOnAppendList, list, [],
'GENERATED_SOURCES': (StrictOrderingOnAppendList, list,
"""Generated source code files.
This variable contains a list of generated source code files to
compile. Accepts assembler, C, C++, Objective C/C++.
""", 'compile'),
'FILES_PER_UNIFIED_FILE': (int, int, None,
'FILES_PER_UNIFIED_FILE': (int, int,
"""The number of source files to compile into each unified source file.
""", 'None'),
'UNIFIED_SOURCES': (StrictOrderingOnAppendList, list, [],
'UNIFIED_SOURCES': (StrictOrderingOnAppendList, list,
"""Source code files that can be compiled together.
This variable contains a list of source code files to compile,
@ -99,7 +103,7 @@ VARIABLES = {
size.
""", 'compile'),
'GENERATED_UNIFIED_SOURCES': (StrictOrderingOnAppendList, list, [],
'GENERATED_UNIFIED_SOURCES': (StrictOrderingOnAppendList, list,
"""Generated source code files that can be compiled together.
This variable contains a list of generated source code files to
@ -108,7 +112,7 @@ VARIABLES = {
and reduce the debug info size.
""", 'compile'),
'GENERATED_FILES': (StrictOrderingOnAppendList, list, [],
'GENERATED_FILES': (StrictOrderingOnAppendList, list,
"""Generic generated files.
This variable contains a list of generate files for the build system
@ -116,7 +120,7 @@ VARIABLES = {
Makefile.in.
""", 'export'),
'DEFINES': (OrderedDict, dict, OrderedDict(),
'DEFINES': (OrderedDict, dict,
"""Dictionary of compiler defines to declare.
These are passed in to the compiler as ``-Dkey='value'`` for string
@ -144,7 +148,7 @@ VARIABLES = {
})
""", None),
'DIRS': (list, list, [],
'DIRS': (list, list,
"""Child directories to descend into looking for build frontend files.
This works similarly to the ``DIRS`` variable in make files. Each str
@ -158,18 +162,18 @@ VARIABLES = {
delimiters.
""", None),
'EXPORT_LIBRARY': (bool, bool, False,
'EXPORT_LIBRARY': (bool, bool,
"""Install the library to the static libraries folder.
""", None),
'EXTRA_COMPONENTS': (StrictOrderingOnAppendList, list, [],
'EXTRA_COMPONENTS': (StrictOrderingOnAppendList, list,
"""Additional component files to distribute.
This variable contains a list of files to copy into
``$(FINAL_TARGET)/components/``.
""", 'libs'),
'EXTRA_JS_MODULES': (StrictOrderingOnAppendList, list, [],
'EXTRA_JS_MODULES': (StrictOrderingOnAppendList, list,
"""Additional JavaScript files to distribute.
This variable contains a list of files to copy into
@ -177,7 +181,7 @@ VARIABLES = {
to ``modules`` if left undefined.
""", 'libs'),
'EXTRA_PP_JS_MODULES': (StrictOrderingOnAppendList, list, [],
'EXTRA_PP_JS_MODULES': (StrictOrderingOnAppendList, list,
"""Additional JavaScript files to distribute.
This variable contains a list of files to copy into
@ -185,14 +189,14 @@ VARIABLES = {
``JS_MODULES_PATH`` defaults to ``modules`` if left undefined.
""", 'libs'),
'EXTRA_PP_COMPONENTS': (StrictOrderingOnAppendList, list, [],
'EXTRA_PP_COMPONENTS': (StrictOrderingOnAppendList, list,
"""Javascript XPCOM files.
This variable contains a list of files to preprocess. Generated
files will be installed in the ``/components`` directory of the distribution.
""", 'libs'),
'FINAL_LIBRARY': (unicode, unicode, "",
'FINAL_LIBRARY': (unicode, unicode,
"""Library in which the objects of the current directory will be linked.
This variable contains the name of a library, defined elsewhere with
@ -200,42 +204,42 @@ VARIABLES = {
linked.
""", 'binaries'),
'CPP_UNIT_TESTS': (StrictOrderingOnAppendList, list, [],
'CPP_UNIT_TESTS': (StrictOrderingOnAppendList, list,
"""C++ source files for unit tests.
This is a list of C++ unit test sources. Entries must be files that
exist. These generally have ``.cpp`` extensions.
""", 'binaries'),
'FAIL_ON_WARNINGS': (bool, bool, False,
'FAIL_ON_WARNINGS': (bool, bool,
"""Whether to treat warnings as errors.
""", None),
'FORCE_SHARED_LIB': (bool, bool, False,
'FORCE_SHARED_LIB': (bool, bool,
"""Whether the library in this directory is a shared library.
""", None),
'FORCE_STATIC_LIB': (bool, bool, False,
'FORCE_STATIC_LIB': (bool, bool,
"""Whether the library in this directory is a static library.
""", None),
'GENERATED_INCLUDES' : (StrictOrderingOnAppendList, list, [],
'GENERATED_INCLUDES' : (StrictOrderingOnAppendList, list,
"""Directories generated by the build system to be searched for include
files by the compiler.
""", None),
'HOST_SOURCES': (StrictOrderingOnAppendList, list, [],
'HOST_SOURCES': (StrictOrderingOnAppendList, list,
"""Source code files to compile with the host compiler.
This variable contains a list of source code files to compile.
with the host compiler.
""", 'compile'),
'IS_COMPONENT': (bool, bool, False,
'IS_COMPONENT': (bool, bool,
"""Whether the library contains a binary XPCOM component manifest.
""", None),
'PARALLEL_DIRS': (list, list, [],
'PARALLEL_DIRS': (list, list,
"""A parallel version of ``DIRS``.
Ideally this variable does not exist. It is provided so a transition
@ -244,18 +248,18 @@ VARIABLES = {
likely go away.
""", None),
'HOST_LIBRARY_NAME': (unicode, unicode, "",
'HOST_LIBRARY_NAME': (unicode, unicode,
"""Name of target library generated when cross compiling.
""", 'binaries'),
'JAVA_JAR_TARGETS': (dict, dict, {},
'JAVA_JAR_TARGETS': (dict, dict,
"""Defines Java JAR targets to be built.
This variable should not be populated directly. Instead, it should
populated by calling add_java_jar().
""", 'binaries'),
'JS_MODULES_PATH': (unicode, unicode, "",
'JS_MODULES_PATH': (unicode, unicode,
"""Sub-directory of ``$(FINAL_TARGET)`` to install
``EXTRA_JS_MODULES``.
@ -265,7 +269,7 @@ VARIABLES = {
``$(FINAL_TARGET)/modules``.
""", None),
'LIBRARY_NAME': (unicode, unicode, "",
'LIBRARY_NAME': (unicode, unicode,
"""The name of the library generated for a directory.
In ``example/components/moz.build``,::
@ -276,44 +280,48 @@ VARIABLES = {
``example/components/xpcomsample.lib`` on Windows.
""", 'binaries'),
'LIBS': (StrictOrderingOnAppendList, list, [],
'LIBS': (StrictOrderingOnAppendList, list,
"""Linker libraries and flags.
A list of libraries and flags to include when linking.
""", None),
'LIBXUL_LIBRARY': (bool, bool, False,
'LIBXUL_LIBRARY': (bool, bool,
"""Whether the library in this directory is linked into libxul.
Implies ``MOZILLA_INTERNAL_API`` and ``FORCE_STATIC_LIB``.
""", None),
'LOCAL_INCLUDES': (StrictOrderingOnAppendList, list, [],
'LOCAL_INCLUDES': (StrictOrderingOnAppendList, list,
"""Additional directories to be searched for include files by the compiler.
""", None),
'MSVC_ENABLE_PGO': (bool, bool, False,
"""Whether profile-guided optimization is enabled in this directory.
'MSVC_ENABLE_PGO': (bool, bool,
"""Whether profile-guided optimization is enabled for MSVC in this directory.
""", None),
'NO_VISIBILITY_FLAGS': (bool, bool, False,
'NO_PGO': (bool, bool,
"""Whether profile-guided optimization is disable in this directory.
""", None),
'NO_VISIBILITY_FLAGS': (bool, bool,
"""Build sources listed in this file without VISIBILITY_FLAGS.
""", None),
'OS_LIBS': (list, list, [],
'OS_LIBS': (list, list,
"""System link libraries.
This variable contains a list of system libaries to link against.
""", None),
'SDK_LIBRARY': (StrictOrderingOnAppendList, list, [],
'SDK_LIBRARY': (StrictOrderingOnAppendList, list,
"""Elements of the distributed SDK.
Files on this list will be copied into ``SDK_LIB_DIR``
(``$DIST/sdk/lib``).
""", None),
'SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list, [],
'SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list,
"""Compile a list of executable names.
Each name in this variable corresponds to an executable built from the
@ -324,7 +332,7 @@ VARIABLES = {
``BIN_SUFFIX``, the name will remain unchanged.
""", 'binaries'),
'HOST_SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list, [],
'HOST_SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list,
"""Compile a list of host executable names.
Each name in this variable corresponds to a hosst executable built
@ -335,7 +343,7 @@ VARIABLES = {
``HOST_BIN_SUFFIX``, the name will remain unchanged.
""", 'binaries'),
'TOOL_DIRS': (list, list, [],
'TOOL_DIRS': (list, list,
"""Like DIRS but for tools.
Tools are for pieces of the build system that aren't required to
@ -343,7 +351,7 @@ VARIABLES = {
code and utilities.
""", None),
'TEST_DIRS': (list, list, [],
'TEST_DIRS': (list, list,
"""Like DIRS but only for directories that contain test-only code.
If tests are not enabled, this variable will be ignored.
@ -352,12 +360,12 @@ VARIABLES = {
complete.
""", None),
'TEST_TOOL_DIRS': (list, list, [],
'TEST_TOOL_DIRS': (list, list,
"""TOOL_DIRS that is only executed if tests are enabled.
""", None),
'TIERS': (OrderedDict, dict, OrderedDict(),
'TIERS': (OrderedDict, dict,
"""Defines directories constituting the tier traversal mechanism.
The recursive make backend iteration is organized into tiers. There are
@ -375,7 +383,7 @@ VARIABLES = {
populated by calling add_tier_dir().
""", None),
'EXTERNAL_MAKE_DIRS': (list, list, [],
'EXTERNAL_MAKE_DIRS': (list, list,
"""Directories that build with make but don't use moz.build files.
This is like ``DIRS`` except it implies that ``make`` is used to build the
@ -383,11 +391,11 @@ VARIABLES = {
files.
""", None),
'PARALLEL_EXTERNAL_MAKE_DIRS': (list, list, [],
'PARALLEL_EXTERNAL_MAKE_DIRS': (list, list,
"""Parallel version of ``EXTERNAL_MAKE_DIRS``.
""", None),
'CONFIGURE_SUBST_FILES': (StrictOrderingOnAppendList, list, [],
'CONFIGURE_SUBST_FILES': (StrictOrderingOnAppendList, list,
"""Output files that will be generated using configure-like substitution.
This is a substitute for ``AC_OUTPUT`` in autoconf. For each path in this
@ -397,7 +405,7 @@ VARIABLES = {
``AC_SUBST`` variables declared during configure.
""", None),
'CONFIGURE_DEFINE_FILES': (StrictOrderingOnAppendList, list, [],
'CONFIGURE_DEFINE_FILES': (StrictOrderingOnAppendList, list,
"""Output files generated from configure/config.status.
This is a substitute for ``AC_CONFIG_HEADER`` in autoconf. This is very
@ -405,7 +413,7 @@ VARIABLES = {
into account the values of ``AC_DEFINE`` instead of ``AC_SUBST``.
""", None),
'EXPORTS': (HierarchicalStringList, list, HierarchicalStringList(),
'EXPORTS': (HierarchicalStringList, list,
"""List of files to be exported, and in which subdirectories.
``EXPORTS`` is generally used to list the include files to be exported to
@ -420,7 +428,7 @@ VARIABLES = {
EXPORTS.mozilla.dom += ['bar.h']
""", None),
'PROGRAM' : (unicode, unicode, "",
'PROGRAM' : (unicode, unicode,
"""Compiled executable name.
If the configuration token ``BIN_SUFFIX`` is set, its value will be
@ -428,7 +436,7 @@ VARIABLES = {
``BIN_SUFFIX``, ``PROGRAM`` will remain unchanged.
""", 'binaries'),
'HOST_PROGRAM' : (unicode, unicode, "",
'HOST_PROGRAM' : (unicode, unicode,
"""Compiled host executable name.
If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will be
@ -436,7 +444,7 @@ VARIABLES = {
ends with ``HOST_BIN_SUFFIX``, ``HOST_PROGRAM`` will remain unchanged.
""", 'binaries'),
'NO_DIST_INSTALL': (bool, bool, False,
'NO_DIST_INSTALL': (bool, bool,
"""Disable installing certain files into the distribution directory.
If present, some files defined by other variables won't be
@ -444,7 +452,7 @@ VARIABLES = {
""", None),
# IDL Generation.
'XPIDL_SOURCES': (StrictOrderingOnAppendList, list, [],
'XPIDL_SOURCES': (StrictOrderingOnAppendList, list,
"""XPCOM Interface Definition Files (xpidl).
This is a list of files that define XPCOM interface definitions.
@ -452,7 +460,7 @@ VARIABLES = {
files.
""", 'libs'),
'XPIDL_MODULE': (unicode, unicode, "",
'XPIDL_MODULE': (unicode, unicode,
"""XPCOM Interface Definition Module Name.
This is the name of the ``.xpt`` file that is created by linking
@ -460,93 +468,93 @@ VARIABLES = {
as ``MODULE``.
""", None),
'IPDL_SOURCES': (StrictOrderingOnAppendList, list, [],
'IPDL_SOURCES': (StrictOrderingOnAppendList, list,
"""IPDL source files.
These are ``.ipdl`` files that will be parsed and converted to
``.cpp`` files.
""", 'export'),
'WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""WebIDL source files.
These will be parsed and converted to ``.cpp`` and ``.h`` files.
""", 'export'),
'GENERATED_EVENTS_WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'GENERATED_EVENTS_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""WebIDL source files for generated events.
These will be parsed and converted to ``.cpp`` and ``.h`` files.
""", 'export'),
'TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""Test WebIDL source files.
These will be parsed and converted to ``.cpp`` and ``.h`` files
if tests are enabled.
""", 'export'),
'GENERATED_WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'GENERATED_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""Generated WebIDL source files.
These will be generated from some other files.
""", 'export'),
'PREPROCESSED_TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'PREPROCESSED_TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""Preprocessed test WebIDL source files.
These will be preprocessed, then parsed and converted to .cpp
and ``.h`` files if tests are enabled.
""", 'export'),
'PREPROCESSED_WEBIDL_FILES': (StrictOrderingOnAppendList, list, [],
'PREPROCESSED_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
"""Preprocessed WebIDL source files.
These will be preprocessed before being parsed and converted.
""", 'export'),
# Test declaration.
'A11Y_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'A11Y_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining a11y tests.
""", None),
'BROWSER_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'BROWSER_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining browser chrome tests.
""", None),
'METRO_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'METRO_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining metro browser chrome tests.
""", None),
'MOCHITEST_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'MOCHITEST_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining mochitest chrome tests.
""", None),
'MOCHITEST_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'MOCHITEST_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining mochitest tests.
""", None),
'MOCHITEST_WEBAPPRT_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'MOCHITEST_WEBAPPRT_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining webapprt mochitest chrome tests.
""", None),
'WEBRTC_SIGNALLING_TEST_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'WEBRTC_SIGNALLING_TEST_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining WebRTC signalling tests.
""", None),
'XPCSHELL_TESTS_MANIFESTS': (StrictOrderingOnAppendList, list, [],
'XPCSHELL_TESTS_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining xpcshell tests.
""", None),
# The following variables are used to control the target of installed files.
'XPI_NAME': (unicode, unicode, "",
'XPI_NAME': (unicode, unicode,
"""The name of an extension XPI to generate.
When this variable is present, the results of this directory will end up
being packaged into an extension instead of the main dist/bin results.
""", 'libs'),
'DIST_SUBDIR': (unicode, unicode, "",
'DIST_SUBDIR': (unicode, unicode,
"""The name of an alternate directory to install files to.
When this variable is present, the results of this directory will end up
@ -554,7 +562,7 @@ VARIABLES = {
otherwise be placed.
""", 'libs'),
'FINAL_TARGET': (unicode, unicode, compute_final_target,
'FINAL_TARGET': (FinalTargetValue, unicode,
"""The name of the directory to install targets to.
The directory is relative to the top of the object directory. The

View File

@ -49,7 +49,7 @@ def function_reference(f, attr, args, doc):
return lines
def variable_reference(v, st_type, in_type, default, doc, tier):
def variable_reference(v, st_type, in_type, doc, tier):
lines = [
v,
'-' * len(v),
@ -66,7 +66,6 @@ def variable_reference(v, st_type, in_type, default, doc, tier):
lines.extend([
':Storage Type: ``%s``' % st_type.__name__,
':Input Type: ``%s``' % in_type.__name__,
':Default Value: %s' % default,
'',
])

View File

@ -1,4 +1,3 @@
[DEFAULT]
support-files = support/**
[xpcshell.js]

View File

@ -382,18 +382,6 @@ class TestRecursiveMakeBackend(BackendTester):
self.assertEqual(len(o['xpcshell.js']), 1)
def test_test_manifest_pattern_matches_recorded(self):
"""Pattern matches in test manifests' support-files should be recorded."""
env = self._consume('test-manifests-written', RecursiveMakeBackend)
m = InstallManifest(path=os.path.join(env.topobjdir,
'_build_manifests', 'install', 'tests'))
# This is not the most robust test in the world, but it gets the job
# done.
entries = [e for e in m._dests.keys() if '**' in e]
self.assertEqual(len(entries), 1)
self.assertIn('support/**', entries[0])
def test_xpidl_generation(self):
"""Ensure xpidl files and directories are written out."""
env = self._consume('xpidl', RecursiveMakeBackend)

View File

@ -3,5 +3,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# 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/.
XPIDL_MODULE = 'bazbar'

View File

@ -248,8 +248,10 @@ class TestEmitterBasic(unittest.TestCase):
'installs': {
'a11y.ini',
'test_a11y.js',
# From ** wildcard.
'a11y-support/foo',
'a11y-support/dir1/bar',
},
'pattern-installs': 1,
},
'browser.ini': {
'flavor': 'browser-chrome',
@ -317,9 +319,6 @@ class TestEmitterBasic(unittest.TestCase):
self.assertIn(path, m['installs'])
if 'pattern-installs' in m:
self.assertEqual(len(o.pattern_installs), m['pattern-installs'])
def test_test_manifest_unmatched_generated(self):
reader = self.reader('test-manifest-unmatched-generated')

View File

@ -76,10 +76,23 @@ class TestGlobalNamespace(unittest.TestCase):
self.assertTrue(d['foo'])
with self.assertRaises(KeyError) as ke:
ns['foo'] = False
ns['bar'] = False
self.assertEqual(ke.exception.args[1], 'set_unknown')
ns['DIRS'] = []
with self.assertRaisesRegexp(Exception, 'Reassigning .* is forbidden') as ke:
ns['DIRS'] = []
with ns.allow_all_writes() as d:
d['DIST_SUBDIR'] = 'foo'
self.assertEqual(ns['DIST_SUBDIR'], 'foo')
ns['DIST_SUBDIR'] = 'bar'
self.assertEqual(ns['DIST_SUBDIR'], 'bar')
with self.assertRaisesRegexp(Exception, 'Reassigning .* is forbidden') as ke:
ns['DIST_SUBDIR'] = 'baz'
self.assertTrue(d['foo'])
def test_key_checking(self):

View File

@ -262,7 +262,7 @@ class TestBuildReader(unittest.TestCase):
self.assertEqual([sandbox['RELATIVEDIR'] for sandbox in sandboxes],
['', 'foo', 'foo/baz', 'bar'])
self.assertEqual([sandbox['XPIDL_MODULE'] for sandbox in sandboxes],
['foobar', 'foobar', 'foobar', 'bazbar'])
['foobar', 'foobar', 'foobar', 'foobar'])
if __name__ == '__main__':
main()

View File

@ -146,9 +146,9 @@ class TestSandbox(unittest.TestCase):
sandbox = self.sandbox()
sandbox.exec_source('DIRS = ["foo"]', 'foo.py')
sandbox.exec_source('DIRS = ["bar"]', 'foo.py')
sandbox.exec_source('DIRS += ["bar"]', 'foo.py')
self.assertEqual(sandbox['DIRS'], ['bar'])
self.assertEqual(sandbox['DIRS'], ['foo', 'bar'])
def test_exec_source_illegal_key_set(self):
sandbox = self.sandbox()

View File

@ -36,7 +36,7 @@ class TestSymbols(unittest.TestCase):
self.assertEqual(lines[-1].strip(), '')
def test_documentation_formatting(self):
for typ, inp, default, doc, tier in VARIABLES.values():
for typ, inp, doc, tier in VARIABLES.values():
self._verify_doc(doc)
for attr, args, doc in FUNCTIONS.values():

View File

@ -22,6 +22,7 @@ from mozbuild.util import (
MozbuildDeletionError,
HierarchicalStringList,
StrictOrderingOnAppendList,
StrictOrderingOnAppendListWithFlagsFactory,
UnsortedError,
)
@ -285,5 +286,39 @@ class TestStrictOrderingOnAppendList(unittest.TestCase):
self.assertEqual(len(l), 2)
class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
def test_strict_ordering_on_append_list_with_flags_factory(self):
cls = StrictOrderingOnAppendListWithFlagsFactory({
'foo': bool,
'bar': int,
})
l = cls()
l += ['a', 'b']
with self.assertRaises(Exception):
l['a'] = 'foo'
with self.assertRaises(Exception):
c = l['c']
self.assertEqual(l['a'].foo, False)
l['a'].foo = True
self.assertEqual(l['a'].foo, True)
with self.assertRaises(TypeError):
l['a'].bar = 'bar'
self.assertEqual(l['a'].bar, 0)
l['a'].bar = 42
self.assertEqual(l['a'].bar, 42)
l['b'].foo = True
self.assertEqual(l['b'].foo, True)
with self.assertRaises(AttributeError):
l['b'].baz = False
if __name__ == '__main__':
main()

View File

@ -301,6 +301,74 @@ class StrictOrderingOnAppendList(list):
class MozbuildDeletionError(Exception):
pass
def StrictOrderingOnAppendListWithFlagsFactory(flags):
"""Returns a StrictOrderingOnAppendList-like object, with optional
flags on each item.
The flags are defined in the dict given as argument, where keys are
the flag names, and values the type used for the value of that flag.
Example:
FooList = StrictOrderingOnAppendListWithFlagsFactory({
'foo': bool, 'bar': unicode
})
foo = FooList(['a', 'b', 'c'])
foo['a'].foo = True
foo['b'].bar = 'bar'
"""
assert isinstance(flags, dict)
assert all(isinstance(v, type) for v in flags.values())
class Flags(object):
__slots__ = flags.keys()
_flags = flags
def __getattr__(self, name):
if name not in self.__slots__:
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
try:
return object.__getattr__(self, name)
except AttributeError:
value = self._flags[name]()
self.__setattr__(name, value)
return value
def __setattr__(self, name, value):
if name not in self.__slots__:
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
if not isinstance(value, self._flags[name]):
raise TypeError("'%s' attribute of class '%s' must be '%s'" %
(name, self.__class__.__name__,
self._flags[name].__name__))
return object.__setattr__(self, name, value)
def __delattr__(self, name):
raise MozbuildDeletionError('Unable to delete attributes for this object')
class StrictOrderingOnAppendListWithFlags(StrictOrderingOnAppendList):
def __init__(self, iterable=[]):
StrictOrderingOnAppendList.__init__(self, iterable)
self._flags_type = Flags
self._flags = dict()
def __getitem__(self, name):
if name not in self._flags:
if name not in self:
raise KeyError("'%s'" % name)
self._flags[name] = self._flags_type()
return self._flags[name]
def __setitem__(self, name, value):
raise TypeError("'%s' object does not support item assignment" %
self.__class__.__name__)
return StrictOrderingOnAppendListWithFlags
class HierarchicalStringList(object):
"""A hierarchy of lists of strings.

View File

@ -6,11 +6,11 @@ from __future__ import unicode_literals
from contextlib import contextmanager
from .copier import FilePurger
from .files import (
AbsoluteSymlinkFile,
ExistingFile,
File,
FileFinder,
)
import mozpack.path as mozpath
@ -63,15 +63,8 @@ class InstallManifest(object):
the FileCopier. No error is raised if the destination path does not
exist.
patternsymlink -- Paths matched by the expression in the source path
will be symlinked to the destination directory.
patterncopy -- Similar to patternsymlink except files are copied, not
symlinked.
Version 1 of the manifest was the initial version.
Version 2 added optional path support
Version 3 added support for pattern entries.
Versions 1 and 2 of the manifest format are similar. Version 2 added
optional path support.
"""
FIELD_SEPARATOR = '\x1f'
@ -79,8 +72,6 @@ class InstallManifest(object):
COPY = 2
REQUIRED_EXISTS = 3
OPTIONAL_EXISTS = 4
PATTERN_SYMLINK = 5
PATTERN_COPY = 6
def __init__(self, path=None, fileobj=None):
"""Create a new InstallManifest entry.
@ -103,7 +94,7 @@ class InstallManifest(object):
def _load_from_fileobj(self, fileobj):
version = fileobj.readline().rstrip()
if version not in ('1', '2', '3'):
if version not in ('1', '2'):
raise UnreadableInstallManifest('Unknown manifest version: ' %
version)
@ -115,7 +106,7 @@ class InstallManifest(object):
record_type = int(fields[0])
if record_type == self.SYMLINK:
dest, source = fields[1:]
dest, source= fields[1:]
self.add_symlink(source, dest)
continue
@ -134,16 +125,6 @@ class InstallManifest(object):
self.add_optional_exists(path)
continue
if record_type == self.PATTERN_SYMLINK:
_, base, pattern, dest = fields[1:]
self.add_pattern_symlink(base, pattern, dest)
continue
if record_type == self.PATTERN_COPY:
_, base, pattern, dest = fields[1:]
self.add_pattern_copy(base, pattern, dest)
continue
raise UnreadableInstallManifest('Unknown record type: %d' %
record_type)
@ -177,7 +158,7 @@ class InstallManifest(object):
It is an error if both are specified.
"""
with _auto_fileobj(path, fileobj, 'wb') as fh:
fh.write('3\n')
fh.write('2\n')
for dest in sorted(self._dests):
entry = self._dests[dest]
@ -217,29 +198,6 @@ class InstallManifest(object):
"""
self._add_entry(dest, (self.OPTIONAL_EXISTS,))
def add_pattern_symlink(self, base, pattern, dest):
"""Add a pattern match that results in symlinks being created.
A ``FileFinder`` will be created with its base set to ``base``
and ``FileFinder.find()`` will be called with ``pattern`` to discover
source files. Each source file will be symlinked under ``dest``.
Filenames under ``dest`` are constructed by taking the path fragment
after ``base`` and concatenating it with ``dest``. e.g.
<base>/foo/bar.h -> <dest>/foo/bar.h
"""
self._add_entry(mozpath.join(base, pattern, dest),
(self.PATTERN_SYMLINK, base, pattern, dest))
def add_pattern_copy(self, base, pattern, dest):
"""Add a pattern match that results in copies.
See ``add_pattern_symlink()`` for usage.
"""
self._add_entry(mozpath.join(base, pattern, dest),
(self.PATTERN_COPY, base, pattern, dest))
def _add_entry(self, dest, entry):
if dest in self._dests:
raise ValueError('Item already in manifest: %s' % dest)
@ -273,21 +231,5 @@ class InstallManifest(object):
registry.add(dest, ExistingFile(required=False))
continue
if install_type in (self.PATTERN_SYMLINK, self.PATTERN_COPY):
_, base, pattern, dest = entry
finder = FileFinder(base, find_executables=False)
paths = [f[0] for f in finder.find(pattern)]
if install_type == self.PATTERN_SYMLINK:
cls = AbsoluteSymlinkFile
else:
cls = File
for path in paths:
source = mozpath.join(base, path)
registry.add(mozpath.join(dest, path), cls(source))
continue
raise Exception('Unknown install type defined in manifest: %d' %
install_type)

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