Merge m-c to f-t

This commit is contained in:
Phil Ringnalda 2013-12-08 08:31:41 -08:00
commit 00256f9b9b
98 changed files with 1651 additions and 1423 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 937317 required a clobber on Windows landing, backout probably will too
Bug 908695 required a clobber on Windows because bug 928195

View File

@ -1310,7 +1310,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULLabelAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:textbox")) {
accessible = new XULTextFieldAccessible(aContent, aDoc);
accessible = new EnumRoleAccessible(aContent, aDoc, roles::SECTION);
} else if (role.EqualsLiteral("xul:thumb")) {
accessible = new XULThumbAccessible(aContent, aDoc);

View File

@ -1052,56 +1052,37 @@ Accessible::TakeFocus()
return NS_OK;
}
ENameValueFlag
Accessible::GetHTMLName(nsString& aLabel)
void
Accessible::XULElmName(DocAccessible* aDocument,
nsIContent* aElm, nsString& aName)
{
Accessible* labelAcc = nullptr;
HTMLLabelIterator iter(Document(), this);
while ((labelAcc = iter.Next())) {
nsTextEquivUtils::AppendTextEquivFromContent(this, labelAcc->GetContent(),
&aLabel);
aLabel.CompressWhitespace();
}
/**
* 3 main cases for XUL Controls to be labeled
* 1 - control contains label="foo"
* 2 - control has, as a child, a label element
* - label has either value="foo" or children
* 3 - non-child label contains control="controlID"
* - label has either value="foo" or children
* Once a label is found, the search is discontinued, so a control
* that has a label child as well as having a label external to
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
if (!aLabel.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
return aLabel.IsEmpty() ? eNameOK : eNameFromSubtree;
}
/**
* 3 main cases for XUL Controls to be labeled
* 1 - control contains label="foo"
* 2 - control has, as a child, a label element
* - label has either value="foo" or children
* 3 - non-child label contains control="controlID"
* - label has either value="foo" or children
* Once a label is found, the search is discontinued, so a control
* that has a label child as well as having a label external to
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
ENameValueFlag
Accessible::GetXULName(nsString& aName)
{
// CASE #1 (via label attribute) -- great majority of the cases
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl = do_QueryInterface(aElm);
if (labeledEl) {
labeledEl->GetLabel(aName);
} else {
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm);
if (itemEl) {
itemEl->GetLabel(aName);
} else {
nsCOMPtr<nsIDOMXULSelectControlElement> select =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm);
// Use label if this is not a select control element which
// uses label attribute to indicate which option is selected
if (!select) {
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mContent));
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm));
if (xulEl)
xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
}
@ -1111,7 +1092,7 @@ Accessible::GetXULName(nsString& aName)
// CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
if (aName.IsEmpty()) {
Accessible* labelAcc = nullptr;
XULLabelIterator iter(Document(), mContent);
XULLabelIterator iter(aDocument, aElm);
while ((labelAcc = iter.Next())) {
nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
do_QueryInterface(labelAcc->GetContent());
@ -1120,30 +1101,27 @@ Accessible::GetXULName(nsString& aName)
// If no value attribute, a non-empty label must contain
// children that define its text -- possibly using HTML
nsTextEquivUtils::
AppendTextEquivFromContent(this, labelAcc->GetContent(), &aName);
AppendTextEquivFromContent(labelAcc, labelAcc->GetContent(), &aName);
}
}
}
aName.CompressWhitespace();
if (!aName.IsEmpty())
return eNameOK;
return;
// Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
nsIContent *bindingParent = mContent->GetBindingParent();
nsIContent *parent = bindingParent? bindingParent->GetParent() :
mContent->GetParent();
nsIContent *bindingParent = aElm->GetBindingParent();
nsIContent* parent =
bindingParent? bindingParent->GetParent() : aElm->GetParent();
while (parent) {
if (parent->Tag() == nsGkAtoms::toolbaritem &&
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
aName.CompressWhitespace();
return eNameOK;
return;
}
parent = parent->GetParent();
}
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
nsresult
@ -2478,11 +2456,30 @@ Accessible::ARIAName(nsString& aName)
ENameValueFlag
Accessible::NativeName(nsString& aName)
{
if (mContent->IsHTML())
return GetHTMLName(aName);
if (mContent->IsHTML()) {
Accessible* label = nullptr;
HTMLLabelIterator iter(Document(), this);
while ((label = iter.Next())) {
nsTextEquivUtils::AppendTextEquivFromContent(this, label->GetContent(),
&aName);
aName.CompressWhitespace();
}
if (mContent->IsXUL())
return GetXULName(aName);
if (!aName.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
if (mContent->IsXUL()) {
XULElmName(mDoc, mContent, aName);
if (!aName.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
if (mContent->IsSVG()) {
// If user agents need to choose among multiple desc or title elements

View File

@ -879,10 +879,10 @@ protected:
void ARIAName(nsString& aName);
/**
* Compute the name of HTML/XUL node.
* Return the name for XUL element.
*/
mozilla::a11y::ENameValueFlag GetHTMLName(nsString& aName);
mozilla::a11y::ENameValueFlag GetXULName(nsString& aName);
static void XULElmName(DocAccessible* aDocument,
nsIContent* aElm, nsString& aName);
// helper method to verify frames
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);

View File

@ -328,16 +328,10 @@ HTMLTextFieldAccessible::NativeName(nsString& aName)
if (!aName.IsEmpty())
return nameFlag;
if (mContent->GetBindingParent()) {
// XXX: bug 459640
// There's a binding parent.
// This means we're part of another control, so use parent accessible for name.
// This ensures that a textbox inside of a XUL widget gets
// an accessible name.
Accessible* parent = Parent();
if (parent)
parent->GetName(aName);
}
// If part of compound of XUL widget then grab a name from XUL widget element.
nsIContent* widgetElm = XULWidgetElm();
if (widgetElm)
XULElmName(mDoc, widgetElm, aName);
if (!aName.IsEmpty())
return eNameOK;
@ -369,8 +363,13 @@ void
HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
{
HyperTextAccessibleWrap::ApplyARIAState(aState);
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
// If part of compound of XUL widget then pick up ARIA stuff from XUL widget
// element.
nsIContent* widgetElm = XULWidgetElm();
if (widgetElm)
aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
}
uint64_t
@ -408,9 +407,8 @@ HTMLTextFieldAccessible::NativeState()
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
// No parent can mean a fake widget created for XUL textbox. If accessible
// is unattached from tree then we don't care.
if (mParent && Preferences::GetBool("browser.formfill.enable")) {
// Ordinal XUL textboxes don't support autocomplete.
if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
// Check to see if autocompletion is allowed on this input. We don't expose
// it for password fields even though the entire password can be remembered
// for a page if the user asks it to be. However, the kind of autocomplete

View File

@ -143,6 +143,11 @@ public:
protected:
// Accessible
virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
/**
* Return a XUL widget element this input is part of.
*/
nsIContent* XULWidgetElm() const { return mContent->GetBindingParent(); }
};

View File

@ -636,192 +636,3 @@ XULToolbarSeparatorAccessible::NativeState()
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible
////////////////////////////////////////////////////////////////////////////////
XULTextFieldAccessible::
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HyperTextAccessibleWrap(aContent, aDoc)
{
}
NS_IMPL_ISUPPORTS_INHERITED2(XULTextFieldAccessible,
Accessible,
nsIAccessibleText,
nsIAccessibleEditableText)
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: nsIAccessible
void
XULTextFieldAccessible::Value(nsString& aValue)
{
aValue.Truncate();
if (NativeRole() == roles::PASSWORD_TEXT) // Don't return password text!
return;
nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mContent));
if (textBox) {
textBox->GetValue(aValue);
return;
}
nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
if (menuList)
menuList->GetLabel(aValue);
}
void
XULTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
{
HyperTextAccessibleWrap::ApplyARIAState(aState);
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
}
uint64_t
XULTextFieldAccessible::NativeState()
{
uint64_t state = HyperTextAccessibleWrap::NativeState();
nsCOMPtr<nsIContent> inputField(GetInputField());
NS_ENSURE_TRUE(inputField, state);
// Create a temporary accessible from the HTML text field to get
// the accessible state from. Doesn't add to cache into document cache.
nsRefPtr<HTMLTextFieldAccessible> tempAccessible =
new HTMLTextFieldAccessible(inputField, mDoc);
if (tempAccessible)
return state | tempAccessible->NativeState();
return state;
}
role
XULTextFieldAccessible::NativeRole()
{
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::password, eIgnoreCase))
return roles::PASSWORD_TEXT;
return roles::ENTRY;
}
/**
* Only one actions available
*/
uint8_t
XULTextFieldAccessible::ActionCount()
{
return 1;
}
/**
* Return the name of our only action
*/
NS_IMETHODIMP
XULTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
{
if (aIndex == eAction_Click) {
aName.AssignLiteral("activate");
return NS_OK;
}
return NS_ERROR_INVALID_ARG;
}
/**
* Tell the button to do its action
*/
NS_IMETHODIMP
XULTextFieldAccessible::DoAction(uint8_t index)
{
if (index == 0) {
nsCOMPtr<nsIDOMXULElement> element(do_QueryInterface(mContent));
if (element)
{
element->Focus();
return NS_OK;
}
return NS_ERROR_FAILURE;
}
return NS_ERROR_INVALID_ARG;
}
bool
XULTextFieldAccessible::CanHaveAnonChildren()
{
return false;
}
bool
XULTextFieldAccessible::IsAcceptableChild(Accessible* aPossibleChild) const
{
// XXX: entry shouldn't contain anything but text leafs. Currently it may
// contain a trailing fake HTML br element added for layout needs. We don't
// need to expose it since it'd be confusing for AT.
return aPossibleChild->IsTextLeaf();
}
already_AddRefed<nsIEditor>
XULTextFieldAccessible::GetEditor() const
{
nsCOMPtr<nsIContent> inputField = GetInputField();
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
if (!editableElt)
return nullptr;
nsCOMPtr<nsIEditor> editor;
editableElt->GetEditor(getter_AddRefs(editor));
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: Accessible protected
void
XULTextFieldAccessible::CacheChildren()
{
NS_ENSURE_TRUE_VOID(mDoc);
// Create child accessibles for native anonymous content of underlying HTML
// input element.
nsCOMPtr<nsIContent> inputContent(GetInputField());
if (!inputContent)
return;
TreeWalker walker(this, inputContent);
while (Accessible* child = walker.NextChild())
AppendChild(child);
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: HyperTextAccessible protected
already_AddRefed<nsFrameSelection>
XULTextFieldAccessible::FrameSelection() const
{
nsCOMPtr<nsIContent> inputContent(GetInputField());
NS_ASSERTION(inputContent, "No input content");
if (!inputContent)
return nullptr;
nsIFrame* frame = inputContent->GetPrimaryFrame();
return frame ? frame->GetFrameSelection() : nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible protected
already_AddRefed<nsIContent>
XULTextFieldAccessible::GetInputField() const
{
nsCOMPtr<nsIDOMNode> inputFieldDOMNode;
nsCOMPtr<nsIDOMXULTextBoxElement> textBox = do_QueryInterface(mContent);
if (textBox)
textBox->GetInputField(getter_AddRefs(inputFieldDOMNode));
NS_ASSERTION(inputFieldDOMNode, "No input field for XULTextFieldAccessible");
nsCOMPtr<nsIContent> inputField = do_QueryInterface(inputFieldDOMNode);
return inputField.forget();
}

View File

@ -215,47 +215,6 @@ public:
virtual uint64_t NativeState();
};
/**
* Used for XUL textbox element.
*/
class XULTextFieldAccessible : public HyperTextAccessibleWrap
{
public:
enum { eAction_Click = 0 };
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc);
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
NS_IMETHOD DoAction(uint8_t index);
// HyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// Accessible
virtual void Value(nsString& aValue);
virtual void ApplyARIAState(uint64_t* aState) const;
virtual mozilla::a11y::role NativeRole();
virtual uint64_t NativeState();
virtual bool CanHaveAnonChildren();
virtual bool IsAcceptableChild(Accessible* aPossibleChild) const MOZ_OVERRIDE;
// ActionAccessible
virtual uint8_t ActionCount();
protected:
// Accessible
virtual void CacheChildren();
// HyperTextAccessible
virtual already_AddRefed<nsFrameSelection> FrameSelection() const;
// nsXULTextFieldAccessible
already_AddRefed<nsIContent> GetInputField() const;
};
} // namespace a11y
} // namespace mozilla

View File

@ -635,7 +635,7 @@ XULListitemAccessible::NativeName(nsString& aName)
}
}
return GetXULName(aName);
return Accessible::NativeName(aName);
}
role

View File

@ -21,7 +21,6 @@ support-files =
states.js
table.js
value.js
testTextboxes.js
text.js
treeview.css
treeview.js
@ -32,5 +31,3 @@ support-files =
[test_nsIAccessibleDocument.html]
[test_nsIAccessibleImage.html]
[test_OuterDocAccessible.html]
[test_textboxes.html]
[test_textboxes.xul]

View File

@ -91,6 +91,23 @@ function testActions(aArray)
gActionsQueue.invoke();
}
/**
* Test action names and descriptions.
*/
function testActionNames(aID, aActions)
{
var actions = (typeof aActions == "string") ?
[ aActions ] : (aActions || []);
var acc = getAccessible(aID);
is(acc.actionCount, actions.length, "Wong number of actions.");
for (var i = 0; i < actions.length; i++ ) {
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
is(acc.getActionDescription(0), gActionDescrMap[actions[i]],
"Wrong action description at " + i + "index.");
}
}
////////////////////////////////////////////////////////////////////////////////
// Private
@ -151,3 +168,20 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj)
aActionObj.checkOnClickEvent(aEvent);
}
}
var gActionDescrMap =
{
jump: "Jump",
press: "Press",
check: "Check",
uncheck: "Uncheck",
select: "Select",
open: "Open",
close: "Close",
switch: "Switch",
click: "Click",
collapse: "Collapse",
expand: "Expand",
activate: "Activate",
cycle: "Cycle"
};

View File

@ -328,6 +328,14 @@ function getApplicationAccessible()
QueryInterface(nsIAccessibleApplication);
}
/**
* A version of accessible tree testing, doesn't fail if tree is not complete.
*/
function testElm(aID, aTreeObj)
{
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
}
/**
* Flags used for testAccessibleTree
*/
@ -370,11 +378,7 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
switch (prop) {
case "actions": {
var actions = (typeof accTree.actions == "string") ?
[ accTree.actions ] : (accTree.actions || []);
is(acc.actionCount, actions.length, "Wong number of actions.");
for (var i = 0; i < actions.length; i++ )
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
testActionNames(acc, accTree.actions);
break;
}

View File

@ -10,6 +10,8 @@
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../actions.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
@ -22,11 +24,6 @@
src="../name.js"></script>
<script type="application/javascript">
function testElm(aID, aTreeObj)
{
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
}
function doTest()
{
//////////////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,6 @@
function doTests()
{
if (MAC) {
todo(false, "Make these tests pass on OSX (bug 650294)");
SimpleTest.finish();
@ -38,10 +37,11 @@
gQueue = new eventQueue(EVENT_TEXT_CARET_MOVED);
var id = "textbox";
gQueue.push(new synthFocus(id, new caretMoveChecker(5, id)));
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, id)));
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, id)));
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, id)));
var input = getNode(id).inputField;
gQueue.push(new synthFocus(id, new caretMoveChecker(5, input)));
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, input)));
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, input)));
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, input)));
gQueue.invoke(); // Will call SimpleTest.finish();
}

View File

@ -38,8 +38,10 @@
// Test focus events.
gQueue = new eventQueue();
gQueue.push(new synthFocus("textbox"));
gQueue.push(new synthFocus("textbox_multiline"));
gQueue.push(new synthFocus("textbox",
new focusChecker(getNode("textbox").inputField)));
gQueue.push(new synthFocus("textbox_multiline",
new focusChecker(getNode("textbox_multiline").inputField)));
gQueue.push(new synthFocus("scale"));
gQueue.push(new synthFocusOnFrame("editabledoc"));
gQueue.push(new synthFocus("radioclothes",

View File

@ -22,7 +22,7 @@
<script type="application/javascript">
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true; // debug stuff
gA11yEventDumpToConsole = true; // debug stuff
var gQueue = null;
function doTests()

View File

@ -36,10 +36,11 @@
// Test focus events.
gQueue = new eventQueue();
var textbox = getNode("textbox").inputField;
gQueue.push(new synthClick("tab1", new focusChecker("tab1")));
gQueue.push(new synthTab("tab1", new focusChecker("checkbox1")));
gQueue.push(new synthKey("tab1", "VK_TAB", { ctrlKey: true },
new focusChecker("textbox")));
new focusChecker(textbox)));
gQueue.push(new synthKey("tab2", "VK_TAB", { ctrlKey: true },
new focusChecker("tab3")));
gQueue.push(new synthKey("tab3", "VK_TAB", { ctrlKey: true },

View File

@ -33,7 +33,7 @@
//////////////////////////////////////////////////////////////////////////
// aria-labelledby
// Single relation. The value of 'aria-labelledby' contains the ID of
// an element. Gets the name from text node of that element.
testName("btn_labelledby_text", "text");

View File

@ -18,11 +18,16 @@
<script type="application/javascript">
<![CDATA[
function getInput(aID)
{
return getNode(aID).inputField;
}
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// Ordinary textbox
testStates("textbox",
testStates(getInput("textbox"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -31,7 +36,7 @@
//////////////////////////////////////////////////////////////////////////
// Password textbox
testStates("password",
testStates(getInput("password"),
STATE_FOCUSABLE | STATE_PROTECTED,
EXT_STATE_EDITABLE,
STATE_UNAVAILABLE,
@ -40,7 +45,7 @@
//////////////////////////////////////////////////////////////////////////
// Textarea
testStates("textarea",
testStates(getInput("textarea"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -49,7 +54,7 @@
//////////////////////////////////////////////////////////////////////////
// Readonly textbox
testStates("readonly_textbox",
testStates(getInput("readonly_textbox"),
STATE_FOCUSABLE | STATE_READONLY,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -58,7 +63,7 @@
//////////////////////////////////////////////////////////////////////////
// Disabled textbox
testStates("disabled_textbox",
testStates(getInput("disabled_textbox"),
STATE_UNAVAILABLE,
EXT_STATE_EDITABLE,
STATE_FOCUSABLE | STATE_PROTECTED,
@ -67,7 +72,7 @@
//////////////////////////////////////////////////////////////////////////
// Readonly textarea
testStates("readonly_textarea",
testStates(getInput("readonly_textarea"),
STATE_FOCUSABLE | STATE_READONLY,
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -76,7 +81,7 @@
//////////////////////////////////////////////////////////////////////////
// Disabled textarea
testStates("disabled_textarea",
testStates(getInput("disabled_textarea"),
STATE_UNAVAILABLE,
EXT_STATE_EDITABLE| EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_FOCUSABLE,
@ -86,7 +91,7 @@
//////////////////////////////////////////////////////////////////////////
// Search textbox without search button, searches as you type and filters
// a separate control.
testStates("searchbox",
testStates(getInput("searchbox"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE | EXT_STATE_SUPPORTS_AUTOCOMPLETION,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -95,7 +100,7 @@
//////////////////////////////////////////////////////////////////////////
// Search textbox with search button, does not support autoCompletion.
testStates("searchfield",
testStates(getInput("searchfield"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,

View File

@ -1,33 +0,0 @@
function testValue(aID, aAcc, aValue, aRole)
{
is(aAcc.value, aValue, "Wrong value for " + aID + "!");
}
function testAction(aID, aAcc, aActionCount, aActionName, aActionDescription)
{
var actionCount = aAcc.actionCount;
is(actionCount, aActionCount, "Wrong number of actions for " + aID + "!");
if (actionCount != 0) {
// Test first action. Normally only 1 should be present.
is(aAcc.getActionName(0), aActionName,
"Wrong name of action for " + aID + "!");
is(aAcc.getActionDescription(0), aActionDescription,
"Wrong description of action for " + aID + "!");
}
}
function testThis(aID, aName, aValue, aDescription, aRole,
aActionCount, aActionName, aActionDescription)
{
var acc = getAccessible(aID);
if (!acc)
return;
is(acc.name, aName, "Wrong name for " + aID + "!");
testValue(aID, acc, aValue, aRole);
is(acc.description, aDescription, "Wrong description for " + aID + "!");
testRole(aID, aRole);
testAction(aID, acc, aActionCount, aActionName, aActionDescription);
}

View File

@ -1,164 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=442648
-->
<head>
<title>nsIAccessible textboxes chrome tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
<script type="application/javascript"
src="role.js"></script>
<script type="application/javascript"
src="states.js"></script>
<script type="application/javascript"
src="testTextboxes.js"></script>
<script type="application/javascript">
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with no proper label
testThis("unlabelled_Textbox", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with a proper label
testThis("labelled_textbox", // ID
"Second textbox:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox with content and with a proper label
testThis("prefilled_textbox", // ID
"Textbox with predefined value:", // name
"I have some text", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// password textbox with a proper label
testThis("password_textbox", // ID
"Enter some password here:", // name
"", // value
"", // description
ROLE_PASSWORD_TEXT, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and label
testThis("unlabelled_Textarea", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and with proper label
testThis("labelled_textarea", // ID
"Labelled textarea:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea with content and with proper label
testThis("prefilled_textarea", // ID
"Pre-filled textarea:", // name
" I also have some text.\n ", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textbox with content and with proper label
testThis("readonly_textbox", // ID
"The following is a read-only textbox:", // name
"You cannot change me.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textarea with content and with proper label
testThis("readonly_textarea", // ID
"This textarea is readonly, too:", // name
" You cannot change me, either.\n ", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=442648">Mozilla Bug 442648</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<form action="test.php" method="post">
Text before input without labelling it:
<input type="text" name="unlabelled_Textbox" id="unlabelled_Textbox" size="50"/>
<br><label for="labelled_textbox">Second textbox:</label>
<input type="text" name="labelled_Textbox" id="labelled_textbox"/>
<br><label for="prefilled_textbox">Textbox with predefined value:</label>
<input type="text" name="prefilled_Textbox" id="prefilled_textbox" value="I have some text" size="80"/>
<br><label for="password_textbox">Enter some password here:</label>
<input type="password" name="password_Textbox" id="password_textbox"/>
<br>Textarea without label:<br>
<textarea id="unlabelled_Textarea" name="unlabelled_Textarea" cols="80" rows="5"></textarea>
<br><label for="labelled_textarea">Labelled textarea:</label><br>
<textarea id="labelled_textarea" name="labelled_Textarea" cols="80" rows="5"></textarea>
<br><label for="prefilled_textarea">Pre-filled textarea:</label><br>
<textarea id="prefilled_textarea" name="prefilled_Textarea" cols="80" rows="5">
I also have some text.
</textarea>
<br><label for="readonly_textbox">The following is a read-only textbox:</label>
<input type="text" readonly="true" name="readonly_Textbox" id="readonly_textbox" value="You cannot change me."/>
<br><label for="readonly_textarea">This textarea is readonly, too:</label><br>
<textarea name="readonly_Textarea" id="readonly_textarea" readonly="true" cols="80" rows="5">
You cannot change me, either.
</textarea>
</form>
</body>
</html>

View File

@ -1,217 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="nsIAccessible XUL textboxes chrome tests">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="common.js" />
<script type="application/javascript"
src="role.js" />
<script type="application/javascript"
src="states.js" />
<script type="application/javascript"
src="testTextboxes.js" />
<script type="application/javascript">
<![CDATA[
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with no proper label
testThis("unlabelled_Textbox", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with a proper label
testThis("labelled_textbox", // ID
"Second textbox:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox with content and with a proper label
testThis("prefilled_textbox", // ID
"Textbox with predefined value:", // name
"I have some text", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// password textbox with a proper label
testThis("password_textbox", // ID
"Enter some password here:", // name
"", // value
"", // description
ROLE_PASSWORD_TEXT, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and label
testThis("unlabelled_Textarea", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and with proper label
testThis("labelled_textarea", // ID
"Labelled textarea:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea with content and with proper label
testThis("prefilled_textarea", // ID
"Pre-filled textarea:", // name
"I also have some text.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textbox with content and with proper label
testThis("readonly_textbox", // ID
"The following is a read-only textbox:", // name
"You cannot change me.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textarea with content and with proper label
testThis("readonly_textarea", // ID
"This textarea is readonly, too:", // name
"You cannot change me, either.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// Search textbox without search button, searches as you type and filters
// a separate control.
testThis("search-box", // ID
"Search History:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// Search textbox with search button, does not support autoCompletion.
testThis("searchfield", // ID
"Search all add-ons", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
testStates("searchfield", 0, 0, 0, EXT_STATE_SUPPORTS_AUTOCOMPLETION);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=442648">
Mozilla Bug 442648
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
<vbox>
<hbox>
<label value="Text before input without labelling it:"/>
<textbox id="unlabelled_Textbox" size="50"/>
</hbox>
<hbox>
<label control="labelled_textbox">Second textbox:</label>
<textbox id="labelled_textbox"/>
</hbox>
<hbox>
<label control="prefilled_textbox">Textbox with predefined value:</label>
<textbox id="prefilled_textbox" value="I have some text" size="80"/>
</hbox>
<hbox>
<label control="password_textbox">Enter some password here:</label>
<textbox type="password" id="password_textbox"/>
</hbox>
<vbox>
<label value="Textarea without label:"/>
<textbox multiline="true" id="unlabelled_Textarea" cols="80" rows="5"/>
</vbox>
<vbox>
<label control="labelled_textarea">Labelled textarea:</label>
<textbox multiline="true" id="labelled_textarea" cols="80" rows="5"/>
</vbox>
<vbox>
<label control="prefilled_textarea">Pre-filled textarea:</label>
<textbox multiline="true" id="prefilled_textarea" cols="80" rows="5"
value="I also have some text."/>
</vbox>
<hbox>
<label control="readonly_textbox">The following is a read-only textbox:</label>
<textbox readonly="true" id="readonly_textbox"
value="You cannot change me."/>
</hbox>
<vbox>
<label control="readonly_textarea">This textarea is readonly, too:</label>
<textbox multiline="true" id="readonly_textarea" readonly="true" cols="80"
rows="5" value="You cannot change me, either."/>
</vbox>
<hbox>
<label value="Search History:" accesskey="S"
control="search-box"/>
<textbox id="search-box" flex="1" type="search"
results="historyTree"/>
</hbox>
<textbox id="searchfield" placeholder="Search all add-ons"
type="search" searchbutton="true"/>
</vbox>
</window>

View File

@ -43,7 +43,7 @@
//////////////////////////////////////////////////////////////////////////
// XUL textbox
testTextAtOffset([ "tbox1" ], BOUNDARY_LINE_START,
testTextAtOffset([ getNode("tbox1").inputField ], BOUNDARY_LINE_START,
[ [ 0, 4, "test", 0, 4 ] ]);
SimpleTest.finish();

View File

@ -23,64 +23,68 @@
function doTest()
{
////////////////////
// textbox
////////////////////
var accTree = {
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
//////////////////////////////////////////////////////////////////////////
// textboxes
var accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
// default textbox
testAccessibleTree("txc1", accTree);
testAccessibleTree("txc", accTree);
// number textbox
testAccessibleTree("txc2", accTree);
// multiline
testAccessibleTree("txc_multiline", accTree);
//////////////////////////////////////////////////////////////////////////
// search textbox
testAccessibleTree("txc3", accTree);
// timed textbox
testAccessibleTree("txc4_deprecated", accTree);
if (MAC) {
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
} else {
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ PUSHBUTTON: [] },
{ MENUPOPUP: [] }
] };
}
////////////////////
testAccessibleTree("txc_search", accTree);
//////////////////////////////////////////////////////////////////////////
// number textbox
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] },
{ PUSHBUTTON: [] },
{ PUSHBUTTON: [] }
] };
testAccessibleTree("txc_number", accTree);
//////////////////////////////////////////////////////////////////////////
// password textbox
////////////////////
accTree = {
role: ROLE_PASSWORD_TEXT,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
testAccessibleTree("txc5", accTree);
accTree =
{ SECTION: [
{ PASSWORD_TEXT: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
////////////////////
// multiline textbox
////////////////////
accTree = {
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
testAccessibleTree("txc_password", accTree);
testAccessibleTree("txc6", accTree);
////////////////////
//////////////////////////////////////////////////////////////////////////
// autocomplete textbox
////////////////////
accTree = {
// textbox
role: ROLE_AUTOCOMPLETE,
@ -104,14 +108,14 @@
]
};
function test_txc7() {
testAccessibleTree("txc7", accTree);
function test_AutocompleteControl() {
testAccessibleTree("txc_autocomplete", accTree);
SimpleTest.finish();
}
// XPFE and Toolkit autocomplete widgets differ.
var txc7 = document.getElementById("txc7");
if ("clearResults" in txc7) {
var txc = document.getElementById("txc_autocomplete");
if ("clearResults" in txc) {
SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget.");
// Popup is always created. (See code below.)
@ -141,14 +145,14 @@
]
}
);
test_txc7();
test_AutocompleteControl();
} else {
SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
// Dumb access to trigger popup lazy creation.
waitForEvent(EVENT_REORDER, txc7, test_txc7);
txc7.popup;
waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
txc.popup;
accTree.children.push(
{
@ -189,15 +193,12 @@
</body>
<vbox flex="1">
<textbox id="txc1" value="hello"/>
<textbox id="txc2" type="number" value="44"/>
<textbox id="txc3" type="search" value="hello"/>
<!-- This textbox triggers "Warning: Timed textboxes are deprecated. Consider using type="search" instead.".
Yet let's test it too as long as it's (still) supported. -->
<textbox id="txc4_deprecated" type="timed" value="hello"/>
<textbox id="txc5" type="password" value="hello"/>
<textbox id="txc6" multiline="true" value="hello"/>
<textbox id="txc7" type="autocomplete" value="hello"/>
<textbox id="txc" value="hello"/>
<textbox id="txc_search" type="search" value="hello"/>
<textbox id="txc_number" type="number" value="44"/>
<textbox id="txc_password" type="password" value="hello"/>
<textbox id="txc_multiline" multiline="true" value="hello"/>
<textbox id="txc_autocomplete" type="autocomplete" value="hello"/>
</vbox>
</hbox>

View File

@ -5,7 +5,7 @@
"use strict"
function debug(str) {
//dump("-*- ContentPermissionPrompt: " + s + "\n");
//dump("-*- ContentPermissionPrompt: " + str + "\n");
}
const Ci = Components.interfaces;
@ -13,11 +13,14 @@ const Cr = Components.results;
const Cu = Components.utils;
const Cc = Components.classes;
const PROMPT_FOR_UNKNOWN = ["geolocation", "desktop-notification",
"audio-capture"];
const PROMPT_FOR_UNKNOWN = ["audio-capture",
"desktop-notification",
"geolocation",
"video-capture"];
// Due to privary issue, permission requests like GetUserMedia should prompt
// every time instead of providing session persistence.
const PERMISSION_NO_SESSION = ["audio-capture"];
const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -41,7 +44,21 @@ XPCOMUtils.defineLazyServiceGetter(this,
"@mozilla.org/telephony/audiomanager;1",
"nsIAudioManager");
function rememberPermission(aPermission, aPrincipal, aSession)
/**
* aTypesInfo is an array of {permission, access, action, deny} which keeps
* the information of each permission. This arrary is initialized in
* ContentPermissionPrompt.prompt and used among functions.
*
* aTypesInfo[].permission : permission name
* aTypesInfo[].access : permission name + request.access
* aTypesInfo[].action : the default action of this permission
* aTypesInfo[].deny : true if security manager denied this app's origin
* principal.
* Note:
* aTypesInfo[].permission will be sent to prompt only when
* aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false.
*/
function rememberPermission(aTypesInfo, aPrincipal, aSession)
{
function convertPermToAllow(aPerm, aPrincipal)
{
@ -49,12 +66,13 @@ function rememberPermission(aPermission, aPrincipal, aSession)
permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm);
if (type == Ci.nsIPermissionManager.PROMPT_ACTION ||
(type == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) {
PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) {
debug("add " + aPerm + " to permission manager with ALLOW_ACTION");
if (!aSession) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION);
} else if (PERMISSION_NO_SESSION.indexOf(aPermission) < 0) {
} else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION,
@ -63,14 +81,18 @@ function rememberPermission(aPermission, aPrincipal, aSession)
}
}
// Expand the permission to see if we have multiple access properties to convert
let access = PermissionsTable[aPermission].access;
if (access) {
for (let idx in access) {
convertPermToAllow(aPermission + "-" + access[idx], aPrincipal);
for (let i in aTypesInfo) {
// Expand the permission to see if we have multiple access properties
// to convert
let perm = aTypesInfo[i].permission;
let access = PermissionsTable[perm].access;
if (access) {
for (let idx in access) {
convertPermToAllow(perm + "-" + access[idx], aPrincipal);
}
} else {
convertPermToAllow(perm, aPrincipal);
}
} else {
convertPermToAllow(aPermission, aPrincipal);
}
}
@ -78,23 +100,66 @@ function ContentPermissionPrompt() {}
ContentPermissionPrompt.prototype = {
handleExistingPermission: function handleExistingPermission(request) {
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, access);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
handleExistingPermission: function handleExistingPermission(request,
typesInfo) {
typesInfo.forEach(function(type) {
type.action =
Services.perms.testExactPermissionFromPrincipal(request.principal,
type.access);
if (type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(type.access) >= 0) {
type.action = Ci.nsIPermissionManager.PROMPT_ACTION;
}
});
// If all permissions are allowed already, call allow() without prompting.
let checkAllowPermission = function(type) {
if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) {
return true;
}
return false;
}
if (typesInfo.every(checkAllowPermission)) {
debug("all permission requests are allowed");
request.allow();
return true;
}
if (result == Ci.nsIPermissionManager.DENY_ACTION ||
result == Ci.nsIPermissionManager.UNKNOWN_ACTION && PROMPT_FOR_UNKNOWN.indexOf(access) < 0) {
// If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel()
// without prompting.
let checkDenyPermission = function(type) {
if (type.action == Ci.nsIPermissionManager.DENY_ACTION ||
type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
return true;
}
return false;
}
if (typesInfo.every(checkDenyPermission)) {
debug("all permission requests are denied");
request.cancel();
return true;
}
return false;
},
handledByApp: function handledByApp(request) {
// multiple requests should be audio and video
checkMultipleRequest: function checkMultipleRequest(typesInfo) {
if (typesInfo.length == 1) {
return true;
} else if (typesInfo.length > 1) {
let checkIfAllowMultiRequest = function(type) {
return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
}
if (typesInfo.every(checkIfAllowMultiRequest)) {
debug("legal multiple requests");
return true;
}
}
return false;
},
handledByApp: function handledByApp(request, typesInfo) {
if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
// This should not really happen
@ -106,49 +171,94 @@ ContentPermissionPrompt.prototype = {
.getService(Ci.nsIAppsService);
let app = appsService.getAppByLocalId(request.principal.appId);
let url = Services.io.newURI(app.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(url, request.principal.appId,
/*mozbrowser*/false);
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let result = Services.perms.testExactPermissionFromPrincipal(principal, access);
// Check each permission if it's denied by permission manager with app's
// URL.
let notDenyAppPrincipal = function(type) {
let url = Services.io.newURI(app.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(url,
request.principal.appId,
/*mozbrowser*/false);
let result = Services.perms.testExactPermissionFromPrincipal(principal,
type.access);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
return false;
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
type.deny = false;
}
return !type.deny;
}
if (typesInfo.filter(notDenyAppPrincipal).length === 0) {
request.cancel();
return true;
}
request.cancel();
return true;
return false;
},
handledByPermissionType: function handledByPermissionType(request) {
return permissionSpecificChecker.hasOwnProperty(request.type)
? permissionSpecificChecker[request.type](request)
: false;
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
for (let i in typesInfo) {
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
permissionSpecificChecker[typesInfo[i].permission](request)) {
return true;
}
}
return false;
},
_id: 0,
prompt: function(request) {
if (secMan.isSystemPrincipal(request.principal)) {
request.allow();
return true;
return;
}
if (this.handledByApp(request) ||
this.handledByPermissionType(request)) {
// Initialize the typesInfo and set the default value.
let typesInfo = [];
let perms = request.types.QueryInterface(Ci.nsIArray);
for (let idx = 0; idx < perms.length; idx++) {
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
let tmp = {
permission: perm.type,
access: (perm.access && perm.access !== "unused") ?
perm.type + "-" + perm.access : perm.type,
deny: true,
action: Ci.nsIPermissionManager.UNKNOWN_ACTION
};
typesInfo.push(tmp);
}
if (typesInfo.length == 0) {
request.cancel();
return;
}
if(!this.checkMultipleRequest(typesInfo)) {
request.cancel();
return;
}
if (this.handledByApp(request, typesInfo) ||
this.handledByPermissionType(request, typesInfo)) {
return;
}
// returns true if the request was handled
if (this.handleExistingPermission(request))
if (this.handleExistingPermission(request, typesInfo)) {
return;
}
// prompt PROMPT_ACTION request only.
typesInfo.forEach(function(aType, aIndex) {
if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) {
typesInfo.splice(aIndex);
}
});
let frame = request.element;
let requestId = this._id++;
if (!frame) {
this.delegatePrompt(request, requestId);
this.delegatePrompt(request, requestId, typesInfo);
return;
}
@ -163,7 +273,7 @@ ContentPermissionPrompt.prototype = {
if (evt.detail.visible === true)
return;
self.cancelPrompt(request, requestId);
self.cancelPrompt(request, requestId, typesInfo);
cancelRequest();
}
@ -180,7 +290,7 @@ ContentPermissionPrompt.prototype = {
// away but the request is still here.
frame.addEventListener("mozbrowservisibilitychange", onVisibilityChange);
self.delegatePrompt(request, requestId, function onCallback() {
self.delegatePrompt(request, requestId, typesInfo, function onCallback() {
frame.removeEventListener("mozbrowservisibilitychange", onVisibilityChange);
});
};
@ -191,22 +301,17 @@ ContentPermissionPrompt.prototype = {
}
},
cancelPrompt: function(request, requestId) {
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId);
cancelPrompt: function(request, requestId, typesInfo) {
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId,
typesInfo);
},
delegatePrompt: function(request, requestId, callback) {
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let principal = request.principal;
delegatePrompt: function(request, requestId, typesInfo, callback) {
this._permission = access;
this._uri = principal.URI.spec;
this._origin = principal.origin;
this.sendToBrowserWindow("permission-prompt", request, requestId, function(type, remember) {
this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo,
function(type, remember) {
if (type == "permission-allow") {
rememberPermission(request.type, principal, !remember);
rememberPermission(typesInfo, request.principal, !remember);
if (callback) {
callback();
}
@ -214,14 +319,20 @@ ContentPermissionPrompt.prototype = {
return;
}
if (remember) {
Services.perms.addFromPrincipal(principal, access,
Ci.nsIPermissionManager.DENY_ACTION);
} else {
Services.perms.addFromPrincipal(principal, access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
let addDenyPermission = function(type) {
debug("add " + type.permission +
" to permission manager with DENY_ACTION");
if (remember) {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION);
} else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION,
0);
}
}
typesInfo.forEach(addDenyPermission);
if (callback) {
callback();
@ -230,7 +341,7 @@ ContentPermissionPrompt.prototype = {
});
},
sendToBrowserWindow: function(type, request, requestId, callback) {
sendToBrowserWindow: function(type, request, requestId, typesInfo, callback) {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
let content = browser.getContentWindow();
if (!content)
@ -253,10 +364,15 @@ ContentPermissionPrompt.prototype = {
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let permissions = {};
for (let i in typesInfo) {
debug("prompt " + typesInfo[i].permission);
permissions[typesInfo[i].permission] = [];
}
let details = {
type: type,
permission: request.type,
permissions: permissions,
id: requestId,
origin: principal.origin,
isApp: isApp,
@ -289,6 +405,5 @@ ContentPermissionPrompt.prototype = {
};
})();
//module initialization
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);

View File

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

View File

@ -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

@ -2030,13 +2030,21 @@ ContentPermissionPrompt.prototype = {
prompt: function CPP_prompt(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
const kFeatureKeys = { "geolocation" : "geo",
"desktop-notification" : "desktop-notification",
"pointerLock" : "pointerLock",
};
// Make sure that we support the request.
if (!(request.type in kFeatureKeys)) {
if (!(perm.type in kFeatureKeys)) {
return;
}
@ -2048,7 +2056,7 @@ ContentPermissionPrompt.prototype = {
return;
var autoAllow = false;
var permissionKey = kFeatureKeys[request.type];
var permissionKey = kFeatureKeys[perm.type];
var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey);
if (result == Ci.nsIPermissionManager.DENY_ACTION) {
@ -2059,7 +2067,7 @@ ContentPermissionPrompt.prototype = {
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
autoAllow = true;
// For pointerLock, we still want to show a warning prompt.
if (request.type != "pointerLock") {
if (perm.type != "pointerLock") {
request.allow();
return;
}
@ -2073,7 +2081,7 @@ ContentPermissionPrompt.prototype = {
return;
// Show the prompt.
switch (request.type) {
switch (perm.type) {
case "geolocation":
this._promptGeo(request);
break;

View File

@ -44,6 +44,8 @@ let IndexedDB = {
}
let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt);
let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
types.appendElement({type: type, access: "unused"}, false);
// If the user waits a long time before responding, we default to UNKNOWN_ACTION.
let timeoutId = setTimeout(function() {
@ -60,7 +62,7 @@ let IndexedDB = {
}
prompt.prompt({
type: type,
types: types,
uri: Services.io.newURI(payload.location, null, null),
window: null,
element: aMessage.target,

View File

@ -56,8 +56,8 @@ ContentPermissionPrompt.prototype = {
return chromeWin.Browser.getNotificationBox(request.element);
},
handleExistingPermission: function handleExistingPermission(request) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
handleExistingPermission: function handleExistingPermission(request, type) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
@ -70,20 +70,28 @@ ContentPermissionPrompt.prototype = {
},
prompt: function(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// returns true if the request was handled
if (this.handleExistingPermission(request))
if (this.handleExistingPermission(request, perm.type))
return;
let pm = Services.perms;
let notificationBox = this.getNotificationBoxForRequest(request);
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let notification = notificationBox.getNotificationWithValue(request.type);
let notification = notificationBox.getNotificationWithValue(perm.type);
if (notification)
return;
let entityName = kEntities[request.type];
let icon = kIcons[request.type] || "";
let entityName = kEntities[perm.type];
let icon = kIcons[perm.type] || "";
let buttons = [{
label: browserBundle.GetStringFromName(entityName + ".allow"),
@ -96,7 +104,7 @@ ContentPermissionPrompt.prototype = {
label: browserBundle.GetStringFromName("contentPermissions.alwaysForSite"),
accessKey: "",
callback: function(notification) {
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
request.allow();
}
},
@ -104,7 +112,7 @@ ContentPermissionPrompt.prototype = {
label: browserBundle.GetStringFromName("contentPermissions.neverForSite"),
accessKey: "",
callback: function(notification) {
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
request.cancel();
}
}];
@ -112,12 +120,12 @@ ContentPermissionPrompt.prototype = {
let message = browserBundle.formatStringFromName(entityName + ".wantsTo",
[request.principal.URI.host], 1);
let newBar = notificationBox.appendNotification(message,
request.type,
perm.type,
icon,
notificationBox.PRIORITY_WARNING_MEDIUM,
buttons);
if (request.type == "geolocation") {
if (perm.type == "geolocation") {
// Add the "learn more" link.
let link = newBar.ownerDocument.createElement("label");
link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore"));

View File

@ -217,6 +217,8 @@
#include "mozilla/dom/XPathEvaluator.h"
#include "nsIDocumentEncoder.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -10729,17 +10731,11 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest,
nsIContentPermissionRequest)
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetType(nsACString& aType)
nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
{
aType = "pointerLock";
return NS_OK;
}
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess)
{
aAccess = "unused";
return NS_OK;
return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
NS_LITERAL_CSTRING("unused"),
aTypes);
}
NS_IMETHODIMP

View File

@ -5,6 +5,7 @@
#ifndef MEDIAENGINE_H_
#define MEDIAENGINE_H_
#include "mozilla/RefPtr.h"
#include "nsIDOMFile.h"
#include "DOMMediaStream.h"
#include "MediaStreamGraph.h"
@ -35,7 +36,7 @@ enum {
kAudioTrack = 2
};
class MediaEngine
class MediaEngine : public RefCounted<MediaEngine>
{
public:
virtual ~MediaEngine() {}

View File

@ -101,7 +101,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
// We've already seen this device, just append.
aVSources->AppendElement(vSource.get());
} else {
vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i, mWindowId);
vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i);
mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
aVSources->AppendElement(vSource);
}

View File

@ -52,6 +52,7 @@
#include "ImageContainer.h"
#include "nsGlobalWindow.h"
#include "prprf.h"
#include "nsProxyRelease.h"
#endif
#include "NullTransport.h"
@ -73,7 +74,7 @@ class GetCameraNameRunnable;
* mSources, mImageContainer, mSources, mState, mImage, mLastCapture
*
* MainThread:
* mDOMCameraControl, mCaptureIndex, mCameraThread, mWindowId, mCameraManager,
* mDOMCameraControl, mCaptureIndex, mCameraThread, mCameraManager,
* mNativeCameraControl, mPreviewStream, mState, mLastCapture, mWidth, mHeight
*
* Where mWidth, mHeight, mImage are protected by mMonitor
@ -96,11 +97,10 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource
public:
#ifdef MOZ_B2G_CAMERA
MediaEngineWebRTCVideoSource(nsDOMCameraManager* aCameraManager,
int aIndex, uint64_t aWindowId)
int aIndex)
: mCameraManager(aCameraManager)
, mNativeCameraControl(nullptr)
, mPreviewStream(nullptr)
, mWindowId(aWindowId)
, mCallbackMonitor("WebRTCCamera.CallbackMonitor")
, mCaptureIndex(aIndex)
, mMonitor("WebRTCCamera.Monitor")
@ -223,7 +223,6 @@ private:
nsRefPtr<nsDOMCameraControl> mDOMCameraControl;
nsRefPtr<nsGonkCameraControl> mNativeCameraControl;
nsRefPtr<DOMCameraPreview> mPreviewStream;
uint64_t mWindowId;
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
nsRefPtr<nsIThread> mCameraThread;
nsRefPtr<nsIDOMFile> mLastCapture;
@ -352,15 +351,14 @@ class MediaEngineWebRTC : public MediaEngine
{
public:
#ifdef MOZ_B2G_CAMERA
MediaEngineWebRTC(nsDOMCameraManager* aCameraManager, uint64_t aWindowId)
MediaEngineWebRTC(nsDOMCameraManager* aCameraManager)
: mMutex("mozilla::MediaEngineWebRTC")
, mVideoEngine(nullptr)
, mVoiceEngine(nullptr)
, mVideoEngineInit(false)
, mAudioEngineInit(false)
, mCameraManager(aCameraManager)
, mWindowId(aWindowId)
, mHasTabVideoSource(false)
, mCameraManager(aCameraManager)
{
AsyncLatencyLogger::Get(true)->AddRef();
mLoadMonitor = new LoadMonitor();
@ -401,6 +399,8 @@ private:
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
#ifdef MOZ_B2G_CAMERA
// XXX Should use nsMainThreadPtrHandle/etc
// MediaEngine hold this DOM object, and the MediaEngine is hold by Navigator
// Their life time is always much longer than this object. Use a raw-pointer
// here should be safe.
@ -409,7 +409,6 @@ private:
// avoid any bad thing do to addref/release DOM-object on other thread, we use
// raw-pointer for now.
nsDOMCameraManager* mCameraManager;
uint64_t mWindowId;
#endif
nsRefPtr<LoadMonitor> mLoadMonitor;

View File

@ -312,7 +312,6 @@ nsresult
MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
{
LOG((__FUNCTION__));
int error = 0;
if (!mInitDone || !aStream) {
return NS_ERROR_FAILURE;
}
@ -341,7 +340,7 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
}
#else
mState = kStarted;
error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
int error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
if (error == -1) {
return NS_ERROR_FAILURE;
}
@ -492,12 +491,9 @@ void
MediaEngineWebRTCVideoSource::AllocImpl() {
MOZ_ASSERT(NS_IsMainThread());
mDOMCameraControl = new nsDOMCameraControl(mCaptureIndex,
mCameraThread,
this,
this,
nsGlobalWindow::GetInnerWindowWithId(mWindowId));
mCameraManager->Register(mDOMCameraControl);
ErrorResult rv;
mDOMCameraControl = mCameraManager->GetCameraControl(mCaptureIndex,
this, this, rv);
}
void
@ -506,6 +502,7 @@ MediaEngineWebRTCVideoSource::DeallocImpl() {
mNativeCameraControl->ReleaseHardware(this, this);
mNativeCameraControl = nullptr;
mDOMCameraControl = nullptr;
}
void

View File

@ -323,6 +323,11 @@ this.PermissionsTable = { geolocation: {
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"video-capture": {
app: PROMPT_ACTION,
privileged: PROMPT_ACTION,
certified: PROMPT_ACTION
},
};
/**

View File

@ -6,20 +6,156 @@
#include "GonkPermission.h"
#include "mozilla/dom/ContentParent.h"
#endif // MOZ_WIDGET_GONK
#include "nsContentPermissionHelper.h"
#include "nsIContentPermissionPrompt.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIPrincipal.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PContentPermission.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/unused.h"
#include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
using mozilla::unused; // <snicker>
using namespace mozilla::dom;
using namespace mozilla;
namespace mozilla {
namespace dom {
class ContentPermissionRequestParent : public PContentPermissionRequestParent
{
public:
ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal);
virtual ~ContentPermissionRequestParent();
bool IsBeingDestroyed();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<Element> mElement;
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
nsTArray<PermissionRequest> mRequests;
private:
virtual bool Recvprompt();
virtual void ActorDestroy(ActorDestroyReason why);
};
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* aElement,
const IPC::Principal& aPrincipal)
{
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
mPrincipal = aPrincipal;
mElement = aElement;
mRequests = aRequests;
}
ContentPermissionRequestParent::~ContentPermissionRequestParent()
{
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
bool
ContentPermissionRequestParent::Recvprompt()
{
mProxy = new nsContentPermissionRequestProxy();
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
if (NS_FAILED(mProxy->Init(mRequests, this))) {
mProxy->Cancel();
}
return true;
}
void
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
{
if (mProxy) {
mProxy->OnParentDestroyed();
}
}
bool
ContentPermissionRequestParent::IsBeingDestroyed()
{
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
// to send out any message now.
TabParent* tabParent = static_cast<TabParent*>(Manager());
return tabParent->IsDestroyed();
}
NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType)
ContentPermissionType::ContentPermissionType(const nsACString& aType,
const nsACString& aAccess)
{
mType = aType;
mAccess = aAccess;
}
ContentPermissionType::~ContentPermissionType()
{
}
NS_IMETHODIMP
ContentPermissionType::GetType(nsACString& aType)
{
aType = mType;
return NS_OK;
}
NS_IMETHODIMP
ContentPermissionType::GetAccess(nsACString& aAccess)
{
aAccess = mAccess;
return NS_OK;
}
uint32_t
ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray)
{
uint32_t len = aSrcArray.Length();
for (uint32_t i = 0; i < len; i++) {
nsRefPtr<ContentPermissionType> cpt =
new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access());
aDesArray->AppendElement(cpt, false);
}
return len;
}
nsresult
CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
nsIArray** aTypesArray)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
aAccess);
types->AppendElement(permType, false);
types.forget(aTypesArray);
return NS_OK;
}
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal)
{
return new ContentPermissionRequestParent(aRequests, element, principal);
}
} // namespace dom
} // namespace mozilla
nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
{
MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
@ -31,14 +167,12 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
}
nsresult
nsContentPermissionRequestProxy::Init(const nsACString & type,
const nsACString & access,
nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
ContentPermissionRequestParent* parent)
{
NS_ASSERTION(parent, "null parent");
mParent = parent;
mType = type;
mAccess = access;
mPermissionRequests = requests;
nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
if (!prompt) {
@ -58,17 +192,14 @@ nsContentPermissionRequestProxy::OnParentDestroyed()
NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
NS_IMETHODIMP
nsContentPermissionRequestProxy::GetType(nsACString & aType)
nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
{
aType = mType;
return NS_OK;
}
NS_IMETHODIMP
nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess)
{
aAccess = mAccess;
return NS_OK;
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
types.forget(aTypes);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
@ -136,10 +267,18 @@ nsContentPermissionRequestProxy::Allow()
}
#ifdef MOZ_WIDGET_GONK
if (mType.Equals("audio-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.RECORD_AUDIO",
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
uint32_t len = mPermissionRequests.Length();
for (uint32_t i = 0; i < len; i++) {
if (mPermissionRequests[i].type().Equals("audio-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.RECORD_AUDIO",
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
}
if (mPermissionRequests[i].type().Equals("video-capture")) {
GonkPermissionService::GetInstance()->addGrantInfo(
"android.permission.CAMERA",
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
}
}
#endif
@ -147,55 +286,3 @@ nsContentPermissionRequestProxy::Allow()
mParent = nullptr;
return NS_OK;
}
namespace mozilla {
namespace dom {
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType,
const nsACString& aAccess,
Element* aElement,
const IPC::Principal& aPrincipal)
{
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
mPrincipal = aPrincipal;
mElement = aElement;
mType = aType;
mAccess = aAccess;
}
ContentPermissionRequestParent::~ContentPermissionRequestParent()
{
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
bool
ContentPermissionRequestParent::Recvprompt()
{
mProxy = new nsContentPermissionRequestProxy();
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
if (NS_FAILED(mProxy->Init(mType, mAccess, this))) {
mProxy->Cancel();
}
return true;
}
void
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
{
if (mProxy) {
mProxy->OnParentDestroyed();
}
}
bool
ContentPermissionRequestParent::IsBeingDestroyed()
{
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
// to send out any message now.
TabParent* tabParent = static_cast<TabParent*>(Manager());
return tabParent->IsDestroyed();
}
} // namespace dom
} // namespace mozilla

View File

@ -6,60 +6,75 @@
#define nsContentPermissionHelper_h
#include "nsIContentPermissionPrompt.h"
#include "nsString.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "nsTArray.h"
#include "nsIMutableArray.h"
class nsContentPermissionRequestProxy;
// Forward declare IPC::Principal here which is defined in
// PermissionMessageUtils.h. Include this file will transitively includes
// "windows.h" and it defines
// #define CreateEvent CreateEventW
// #define LoadImage LoadImageW
// That will mess up windows build.
namespace IPC {
class Principal;
}
namespace mozilla {
namespace dom {
class Element;
class PermissionRequest;
class ContentPermissionRequestParent;
class PContentPermissionRequestParent;
class ContentPermissionRequestParent : public PContentPermissionRequestParent
class ContentPermissionType : public nsIContentPermissionType
{
public:
ContentPermissionRequestParent(const nsACString& type,
const nsACString& access,
Element* element,
const IPC::Principal& principal);
virtual ~ContentPermissionRequestParent();
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONTYPE
bool IsBeingDestroyed();
ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
virtual ~ContentPermissionType();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<Element> mElement;
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
protected:
nsCString mType;
nsCString mAccess;
private:
virtual bool Recvprompt();
virtual void ActorDestroy(ActorDestroyReason why);
};
uint32_t ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray);
nsresult CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
nsIArray** aTypesArray);
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal);
} // namespace dom
} // namespace mozilla
class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
nsContentPermissionRequestProxy();
virtual ~nsContentPermissionRequestProxy();
nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent);
nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
mozilla::dom::ContentPermissionRequestParent* parent);
void OnParentDestroyed();
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
private:
// Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
mozilla::dom::ContentPermissionRequestParent* mParent;
nsCString mType;
nsCString mAccess;
nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
};
#endif // nsContentPermissionHelper_h
#endif // nsContentPermissionHelper_h

View File

@ -105,6 +105,31 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
return cameraManager.forget();
}
nsDOMCameraControl*
nsDOMCameraManager::GetCameraControl(uint32_t aDeviceNum,
nsICameraGetCameraCallback* onSuccess,
nsICameraErrorCallback* onError,
ErrorResult& aRv)
{
aRv = NS_OK;
// reuse the same camera thread to conserve resources
if (!mCameraThread) {
aRv = NS_NewThread(getter_AddRefs(mCameraThread));
if (aRv.Failed()) {
return nullptr;
}
}
// Creating this object will trigger the onSuccess handler
nsDOMCameraControl* cameraControl = new nsDOMCameraControl(aDeviceNum, mCameraThread,
onSuccess, onError, mWindow);
if (cameraControl) {
Register(cameraControl);
}
return cameraControl;
}
void
nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
nsICameraGetCameraCallback* onSuccess,
@ -116,22 +141,10 @@ nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
cameraId = 1;
}
// reuse the same camera thread to conserve resources
if (!mCameraThread) {
aRv = NS_NewThread(getter_AddRefs(mCameraThread));
if (aRv.Failed()) {
return;
}
}
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
// Creating this object will trigger the onSuccess handler
nsRefPtr<nsDOMCameraControl> cameraControl =
new nsDOMCameraControl(cameraId, mCameraThread,
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow);
Register(cameraControl);
GetCameraControl(cameraId, onSuccess, onError.WasPassed() ? onError.Value() : nullptr, aRv);
}
void

View File

@ -49,6 +49,11 @@ public:
CreateInstance(nsPIDOMWindow* aWindow);
static bool IsWindowStillActive(uint64_t aWindowId);
// Build us an nsDOMCameraControl
mozilla::nsDOMCameraControl* GetCameraControl(uint32_t aDeviceNum,
nsICameraGetCameraCallback* onSuccess,
nsICameraErrorCallback* onError,
mozilla::ErrorResult& aRv);
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
void OnNavigation(uint64_t aWindowId);

View File

@ -49,6 +49,7 @@
#include "nsIStringBundle.h"
#include "nsIDocument.h"
#include <algorithm>
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/DeviceStorageBinding.h"
@ -1733,17 +1734,14 @@ nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType)
}
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetType(nsACString & aType)
nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes)
{
return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
aType);
}
nsCString type;
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
NS_ENSURE_SUCCESS(rv, rv);
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess)
{
aAccess = NS_LITERAL_CSTRING("read");
return NS_OK;
return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes);
}
NS_IMETHODIMP
@ -2251,8 +2249,10 @@ public:
if (NS_FAILED(rv)) {
return rv;
}
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(type, access));
child->SendPContentPermissionRequestConstructor(
this, type, access, IPC::Principal(mPrincipal));
this, permArray, IPC::Principal(mPrincipal));
Sendprompt();
return NS_OK;
@ -2266,26 +2266,23 @@ public:
return NS_OK;
}
NS_IMETHOD GetType(nsACString & aType)
NS_IMETHODIMP GetTypes(nsIArray** aTypes)
{
nsCString type;
nsresult rv
= DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
aType);
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
NS_IMETHOD GetAccess(nsACString & aAccess)
{
nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), aAccess);
nsCString access;
rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), access);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
return CreatePermissionArray(type, access, aTypes);
}
NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
@ -3299,8 +3296,10 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath,
if (aRv.Failed()) {
return nullptr;
}
child->SendPContentPermissionRequestConstructor(r, type,
NS_LITERAL_CSTRING("read"),
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read")));
child->SendPContentPermissionRequestConstructor(r,
permArray,
IPC::Principal(mPrincipal));
r->Sendprompt();

View File

@ -7,15 +7,13 @@
interface nsIPrincipal;
interface nsIDOMWindow;
interface nsIDOMElement;
interface nsIArray;
/**
* Interface allows access to a content to request
* permission to perform a privileged operation such as
* geolocation.
* Interface provides the request type and its access.
*/
[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)]
interface nsIContentPermissionRequest : nsISupports {
[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
interface nsIContentPermissionType : nsISupports {
/**
* The type of the permission request, such as
* "geolocation".
@ -27,8 +25,22 @@ interface nsIContentPermissionRequest : nsISupports {
* "read".
*/
readonly attribute ACString access;
};
/**
* Interface allows access to a content to request
* permission to perform a privileged operation such as
* geolocation.
*/
[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)]
interface nsIContentPermissionRequest : nsISupports {
/**
* The array will include the request types. Elements of this array are
* nsIContentPermissionType object.
*/
readonly attribute nsIArray types;
/*
* The principal of the permission request.
*/
readonly attribute nsIPrincipal principal;

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

@ -16,6 +16,7 @@ include protocol PIndexedDB;
include DOMTypes;
include JavaScriptTypes;
include URIParams;
include PContentPermission;
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
@ -206,10 +207,8 @@ parent:
* Initiates an asynchronous request for permission for the
* provided principal.
*
* @param aType
* The type of permission to request.
* @param aAccess
* Access type. "read" for example.
* @param aRequests
* The array of permissions to request.
* @param aPrincipal
* The principal of the request.
*
@ -217,7 +216,7 @@ parent:
* principals that can live in the content process should
* provided.
*/
PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal);
PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
int32_t[] aIntParams, nsString[] aStringParams);

View File

@ -0,0 +1,14 @@
/* 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/. */
namespace mozilla {
namespace dom {
struct PermissionRequest {
nsCString type;
nsCString access;
};
} // namespace dom
} // namespace mozilla

View File

@ -281,6 +281,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 +321,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

@ -1157,12 +1157,11 @@ TabChild::ArraysToParams(const InfallibleTArray<int>& aIntParams,
#ifdef DEBUG
PContentPermissionRequestChild*
TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
const nsCString& aType,
const nsCString& aAccess,
const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal)
{
PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal);
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal);
child->mIPCOpen = true;
return request;
}
@ -2014,7 +2013,8 @@ TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog)
}
PContentPermissionRequestChild*
TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&)
TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal)
{
NS_RUNTIMEABORT("unused");
return nullptr;

View File

@ -278,13 +278,11 @@ public:
#ifdef DEBUG
virtual PContentPermissionRequestChild*
SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
const nsCString& aType,
const nsCString& aAccess,
const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal);
#endif /* DEBUG */
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType,
const nsCString& aAccess,
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal);
virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor);

View File

@ -15,6 +15,7 @@
#include "mozilla/BrowserElementParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/layers/CompositorParent.h"
@ -579,9 +580,10 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
}
PContentPermissionRequestParent*
TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal)
TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal)
{
return new ContentPermissionRequestParent(type, access, mFrameElement, principal);
return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal);
}
bool

View File

@ -225,7 +225,8 @@ public:
virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor);
virtual PContentPermissionRequestParent*
AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal);
AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal);
virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor);
virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent(

View File

@ -68,6 +68,7 @@ IPDL_SOURCES += [
'PBrowser.ipdl',
'PContent.ipdl',
'PContentDialog.ipdl',
'PContentPermission.ipdlh',
'PContentPermissionRequest.ipdl',
'PCrashReporter.ipdl',
'PDocumentRenderer.ipdl',

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

@ -41,7 +41,7 @@
#include "MediaEngineWebRTC.h"
#endif
#ifdef MOZ_WIDGET_GONK
#ifdef MOZ_B2G
#include "MediaPermissionGonk.h"
#endif
@ -756,7 +756,7 @@ public:
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(false)
, mBackend(nullptr)
, mManager(MediaManager::GetInstance())
{}
@ -778,15 +778,11 @@ public:
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(true)
, mBackend(aBackend)
, mManager(MediaManager::GetInstance())
{}
~GetUserMediaRunnable() {
if (mBackendChosen) {
delete mBackend;
}
}
NS_IMETHOD
@ -794,14 +790,15 @@ public:
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
MediaEngine* backend = mBackend;
// Was a backend provided?
if (!mBackendChosen) {
mBackend = mManager->GetBackend(mWindowID);
if (!backend) {
backend = mManager->GetBackend(mWindowID);
}
// Was a device provided?
if (!mDeviceChosen) {
nsresult rv = SelectDevice();
nsresult rv = SelectDevice(backend);
if (rv != NS_OK) {
return rv;
}
@ -873,10 +870,10 @@ public:
}
nsresult
SelectDevice()
SelectDevice(MediaEngine* backend)
{
if (mConstraints.mPicture || mConstraints.mVideo) {
ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
ScopedDeletePtr<SourceSet> sources (GetSources(backend,
mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices));
if (!sources->Length()) {
@ -890,7 +887,7 @@ public:
}
if (mConstraints.mAudio) {
ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
ScopedDeletePtr<SourceSet> sources (GetSources(backend,
mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices));
if (!sources->Length()) {
@ -984,9 +981,8 @@ private:
MediaEnginePrefs mPrefs;
bool mDeviceChosen;
bool mBackendChosen;
MediaEngine* mBackend;
RefPtr<MediaEngine> mBackend;
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
};
@ -1266,10 +1262,10 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
// Force MediaManager to startup before we try to access it from other threads
// Hack: should init singleton earlier unless it's expensive (mem or CPU)
(void) MediaManager::Get();
#ifdef MOZ_WIDGET_GONK
#ifdef MOZ_B2G
// Initialize MediaPermissionManager before send out any permission request.
(void) MediaPermissionManager::GetInstance();
#endif //MOZ_WIDGET_GONK
#endif //MOZ_B2G
}
// Store the WindowID in a hash table and mark as active. The entry is removed
@ -1415,11 +1411,11 @@ MediaManager::GetBackend(uint64_t aWindowId)
MutexAutoLock lock(mMutex);
if (!mBackend) {
#if defined(MOZ_WEBRTC)
#ifndef MOZ_B2G_CAMERA
#ifndef MOZ_B2G_CAMERA
mBackend = new MediaEngineWebRTC(mPrefs);
#else
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
#endif
#else
mBackend = new MediaEngineWebRTC(mCameraManager);
#endif
#else
mBackend = new MediaEngineDefault();
#endif

View File

@ -513,9 +513,7 @@ private:
// Make private because we want only one instance of this class
MediaManager();
~MediaManager() {
delete mBackend;
}
~MediaManager() {}
nsresult MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo,
bool* aAudio);
@ -530,11 +528,11 @@ private:
Mutex mMutex;
// protected with mMutex:
MediaEngine* mBackend;
RefPtr<MediaEngine> mBackend;
static StaticRefPtr<MediaManager> sSingleton;
#ifdef MOZ_WIDGET_GONK
#ifdef MOZ_B2G_CAMERA
nsRefPtr<nsDOMCameraManager> mCameraManager;
#endif
};

View File

@ -20,14 +20,36 @@
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#define AUDIO_PERMISSION_NAME "audio-capture"
#define VIDEO_PERMISSION_NAME "video-capture"
using namespace mozilla::dom;
namespace mozilla {
static MediaPermissionManager *gMediaPermMgr = nullptr;
static uint32_t
ConvertArrayToPermissionRequest(nsIArray* aSrcArray,
nsTArray<PermissionRequest>& aDesArray)
{
uint32_t len = 0;
aSrcArray->GetLength(&len);
for (uint32_t i = 0; i < len; i++) {
nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
nsAutoCString type;
nsAutoCString access;
cpt->GetType(type);
cpt->GetAccess(access);
aDesArray.AppendElement(PermissionRequest(type, access));
}
return len;
}
// Helper function for notifying permission granted
static nsresult
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
@ -93,6 +115,7 @@ public:
private:
bool mAudio; // Request for audio permission
bool mVideo; // Request for video permission
nsRefPtr<dom::GetUserMediaRequest> mRequest;
nsTArray<nsCOMPtr<nsIMediaDevice> > mDevices; // candiate device list
};
@ -108,6 +131,7 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
mRequest->GetConstraints(constraints);
mAudio = constraints.mAudio;
mVideo = constraints.mVideo;
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
@ -116,10 +140,34 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
if (mAudio && deviceType.EqualsLiteral("audio")) {
mDevices.AppendElement(device);
}
if (mVideo && deviceType.EqualsLiteral("video")) {
mDevices.AppendElement(device);
}
}
}
// nsIContentPermissionRequest methods
NS_IMETHODIMP
MediaPermissionRequest::GetTypes(nsIArray** aTypes)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (mAudio) {
nsCOMPtr<ContentPermissionType> AudioType =
new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"));
types->AppendElement(AudioType, false);
}
if (mVideo) {
nsCOMPtr<ContentPermissionType> VideoType =
new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"));
types->AppendElement(VideoType, false);
}
NS_IF_ADDREF(*aTypes = types);
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
{
@ -135,24 +183,6 @@ MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetType(nsACString &aType)
{
if (mAudio) {
aType = AUDIO_PERMISSION_NAME;
return NS_OK;
}
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetAccess(nsACString &aAccess)
{
aAccess = "unused";
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
{
@ -278,13 +308,12 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell());
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
nsAutoCString type;
rv = req->GetType(type);
nsCOMPtr<nsIArray> typeArray;
rv = req->GetTypes(getter_AddRefs(typeArray));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString access;
rv = req->GetAccess(access);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<PermissionRequest> permArray;
ConvertArrayToPermissionRequest(typeArray, permArray);
nsCOMPtr<nsIPrincipal> principal;
rv = req->GetPrincipal(getter_AddRefs(principal));
@ -292,8 +321,7 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
req->AddRef();
child->SendPContentPermissionRequestConstructor(req,
type,
access,
permArray,
IPC::Principal(principal));
req->Sendprompt();

View File

@ -14,6 +14,7 @@
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsCxPusher.h"
#include "nsIDocument.h"
#include "nsIObserverService.h"
@ -385,17 +386,11 @@ nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
}
NS_IMETHODIMP
nsGeolocationRequest::GetType(nsACString & aType)
nsGeolocationRequest::GetTypes(nsIArray** aTypes)
{
aType = "geolocation";
return NS_OK;
}
NS_IMETHODIMP
nsGeolocationRequest::GetAccess(nsACString & aAccess)
{
aAccess = "unused";
return NS_OK;
return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused"),
aTypes);
}
NS_IMETHODIMP
@ -1452,12 +1447,15 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
return false;
}
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused")));
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
request->AddRef();
child->SendPContentPermissionRequestConstructor(request,
NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused"),
permArray,
IPC::Principal(mPrincipal));
request->Sendprompt();

View File

@ -15,6 +15,7 @@
#include "PCOMContentPermissionRequestChild.h"
#include "nsIScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
#include "PermissionMessageUtils.h"
namespace mozilla {
namespace dom {
@ -179,9 +180,12 @@ DesktopNotification::Init()
// Corresponding release occurs in DeallocPContentPermissionRequest.
nsRefPtr<DesktopNotificationRequest> copy = request;
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused")));
child->SendPContentPermissionRequestConstructor(copy.forget().get(),
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
permArray,
IPC::Principal(mPrincipal));
request->Sendprompt();
@ -353,17 +357,11 @@ DesktopNotificationRequest::Allow()
}
NS_IMETHODIMP
DesktopNotificationRequest::GetType(nsACString & aType)
DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
{
aType = "desktop-notification";
return NS_OK;
}
NS_IMETHODIMP
DesktopNotificationRequest::GetAccess(nsACString & aAccess)
{
aAccess = "unused";
return NS_OK;
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
aTypes);
}
} // namespace dom

View File

@ -24,6 +24,7 @@
#include "nsDOMJSUtils.h"
#include "nsIScriptSecurityManager.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "nsContentPermissionHelper.h"
#ifdef MOZ_B2G
#include "nsIDOMDesktopNotification.h"
#endif
@ -267,9 +268,11 @@ NotificationPermissionRequest::Run()
// Corresponding release occurs in DeallocPContentPermissionRequest.
AddRef();
NS_NAMED_LITERAL_CSTRING(type, "desktop-notification");
NS_NAMED_LITERAL_CSTRING(access, "unused");
child->SendPContentPermissionRequestConstructor(this, type, access,
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused")));
child->SendPContentPermissionRequestConstructor(this, permArray,
IPC::Principal(mPrincipal));
Sendprompt();
@ -342,17 +345,11 @@ NotificationPermissionRequest::CallCallback()
}
NS_IMETHODIMP
NotificationPermissionRequest::GetAccess(nsACString& aAccess)
NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
{
aAccess.AssignLiteral("unused");
return NS_OK;
}
NS_IMETHODIMP
NotificationPermissionRequest::GetType(nsACString& aType)
{
aType.AssignLiteral("desktop-notification");
return NS_OK;
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
aTypes);
}
bool

View File

@ -27,7 +27,7 @@ dictionary RTCStats {
dictionary RTCRTPStreamStats : RTCStats {
DOMString ssrc;
DOMString remoteId;
boolean isRemote;
boolean isRemote = false;
DOMString mediaTrackId;
DOMString transportId;
DOMString codecId;
@ -124,7 +124,7 @@ callback RTCStatsReportCallback = void (RTCStatsReport obj);
// to be received from c++
dictionary RTCStatsReportInternal {
DOMString pcid;
DOMString pcid = "";
sequence<RTCRTPStreamStats> rtpStreamStats;
sequence<RTCInboundRTPStreamStats> inboundRTPStreamStats;
sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;

View File

@ -0,0 +1,7 @@
function f(y) {
return (y > 0) == y;
}
assertEq(f(0), true);
assertEq(f(0), true);
assertEq(f(null), false);
assertEq(f(null), false);

View File

@ -0,0 +1,6 @@
function f() {
return Math.abs(~(Math.tan()));
}
for (var i=0; i<1000; i++)
assertEq(f(i), 1);

View File

@ -226,8 +226,20 @@ BaselineInspector::expectedCompareType(jsbytecode *pc)
if (!first && !dimorphicStub(pc, &first, &second))
return MCompare::Compare_Unknown;
if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind())))
if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
ICCompare_Int32WithBoolean *coerce =
first->isCompare_Int32WithBoolean()
? first->toCompare_Int32WithBoolean()
: ((second && second->isCompare_Int32WithBoolean())
? second->toCompare_Int32WithBoolean()
: nullptr);
if (coerce) {
return coerce->lhsIsInt32()
? MCompare::Compare_Int32MaybeCoerceRHS
: MCompare::Compare_Int32MaybeCoerceLHS;
}
return MCompare::Compare_Int32;
}
if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
ICCompare_NumberWithUndefined *coerce =

View File

@ -201,7 +201,8 @@ CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
masm.bind(oolDouble->rejoin());
} else {
masm.convertValueToInt32(operand, input, temp, output, &fails,
lir->mirNormal()->canBeNegativeZero());
lir->mirNormal()->canBeNegativeZero(),
lir->mirNormal()->conversion());
}
return bailoutFrom(&fails, lir->snapshot());
@ -3839,7 +3840,7 @@ CodeGenerator::visitAbsI(LAbsI *ins)
JS_ASSERT(input == ToRegister(ins->output()));
masm.test32(input, input);
masm.j(Assembler::GreaterThanOrEqual, &positive);
masm.j(Assembler::NotSigned, &positive);
masm.neg32(input);
if (ins->snapshot() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
return false;

View File

@ -1449,7 +1449,7 @@ jit::ExtractLinearInequality(MTest *test, BranchDirection direction,
MDefinition *rhs = compare->getOperand(1);
// TODO: optimize Compare_UInt32
if (compare->compareType() != MCompare::Compare_Int32)
if (!compare->isInt32Comparison())
return false;
JS_ASSERT(lhs->type() == MIRType_Int32);

View File

@ -1563,7 +1563,8 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
Label *handleStringEntry, Label *handleStringRejoin,
Label *truncateDoubleSlow,
Register stringReg, FloatRegister temp, Register output,
Label *fail, IntConversionBehavior behavior)
Label *fail, IntConversionBehavior behavior,
IntConversionInputKind conversion)
{
Register tag = splitTagForTest(value);
bool handleStrings = (behavior == IntConversion_Truncate ||
@ -1572,29 +1573,36 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
handleStringRejoin;
bool zeroObjects = behavior == IntConversion_ClampToUint8;
JS_ASSERT_IF(handleStrings || zeroObjects, conversion == IntConversion_Any);
Label done, isInt32, isBool, isDouble, isNull, isString;
branchEqualTypeIfNeeded(MIRType_Int32, maybeInput, tag, &isInt32);
branchEqualTypeIfNeeded(MIRType_Boolean, maybeInput, tag, &isBool);
if (conversion == IntConversion_Any)
branchEqualTypeIfNeeded(MIRType_Boolean, maybeInput, tag, &isBool);
branchEqualTypeIfNeeded(MIRType_Double, maybeInput, tag, &isDouble);
// If we are not truncating, we fail for anything that's not
// null. Otherwise we might be able to handle strings and objects.
switch (behavior) {
case IntConversion_Normal:
case IntConversion_NegativeZeroCheck:
branchTestNull(Assembler::NotEqual, tag, fail);
break;
if (conversion == IntConversion_Any) {
// If we are not truncating, we fail for anything that's not
// null. Otherwise we might be able to handle strings and objects.
switch (behavior) {
case IntConversion_Normal:
case IntConversion_NegativeZeroCheck:
branchTestNull(Assembler::NotEqual, tag, fail);
break;
case IntConversion_Truncate:
case IntConversion_ClampToUint8:
branchEqualTypeIfNeeded(MIRType_Null, maybeInput, tag, &isNull);
if (handleStrings)
branchEqualTypeIfNeeded(MIRType_String, maybeInput, tag, &isString);
if (zeroObjects)
branchEqualTypeIfNeeded(MIRType_Object, maybeInput, tag, &isNull);
branchTestUndefined(Assembler::NotEqual, tag, fail);
break;
case IntConversion_Truncate:
case IntConversion_ClampToUint8:
branchEqualTypeIfNeeded(MIRType_Null, maybeInput, tag, &isNull);
if (handleStrings)
branchEqualTypeIfNeeded(MIRType_String, maybeInput, tag, &isString);
if (zeroObjects)
branchEqualTypeIfNeeded(MIRType_Object, maybeInput, tag, &isNull);
branchTestUndefined(Assembler::NotEqual, tag, fail);
break;
}
} else {
jump(fail);
}
// The value is null or undefined in truncation contexts - just emit 0.

View File

@ -1174,6 +1174,11 @@ class MacroAssembler : public MacroAssemblerSpecific
IntConversion_ClampToUint8,
};
enum IntConversionInputKind {
IntConversion_NumbersOnly,
IntConversion_Any
};
//
// Functions for converting values to int.
//
@ -1188,7 +1193,8 @@ class MacroAssembler : public MacroAssemblerSpecific
Label *handleStringEntry, Label *handleStringRejoin,
Label *truncateDoubleSlow,
Register stringReg, FloatRegister temp, Register output,
Label *fail, IntConversionBehavior behavior);
Label *fail, IntConversionBehavior behavior,
IntConversionInputKind conversion = IntConversion_Any);
void convertValueToInt(ValueOperand value, FloatRegister temp, Register output, Label *fail,
IntConversionBehavior behavior)
{
@ -1214,12 +1220,13 @@ class MacroAssembler : public MacroAssemblerSpecific
}
void convertValueToInt32(ValueOperand value, MDefinition *input,
FloatRegister temp, Register output, Label *fail,
bool negativeZeroCheck)
bool negativeZeroCheck, IntConversionInputKind conversion = IntConversion_Any)
{
convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
negativeZeroCheck
? IntConversion_NegativeZeroCheck
: IntConversion_Normal);
: IntConversion_Normal,
conversion);
}
bool convertValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail,
bool negativeZeroCheck)

View File

@ -769,20 +769,17 @@ LIRGenerator::visitTest(MTest *test)
}
// Compare and branch Int32 or Object pointers.
if (comp->compareType() == MCompare::Compare_Int32 ||
if (comp->isInt32Comparison() ||
comp->compareType() == MCompare::Compare_UInt32 ||
comp->compareType() == MCompare::Compare_Object)
{
JSOp op = ReorderComparison(comp->jsop(), &left, &right);
LAllocation lhs = useRegister(left);
LAllocation rhs;
if (comp->compareType() == MCompare::Compare_Int32 ||
comp->compareType() == MCompare::Compare_UInt32)
{
if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32)
rhs = useAnyOrConstant(right);
} else {
else
rhs = useRegister(right);
}
LCompareAndBranch *lir = new(alloc()) LCompareAndBranch(op, lhs, rhs, ifTrue, ifFalse);
return add(lir, comp);
}
@ -958,14 +955,14 @@ LIRGenerator::visitCompare(MCompare *comp)
}
// Compare Int32 or Object pointers.
if (comp->compareType() == MCompare::Compare_Int32 ||
if (comp->isInt32Comparison() ||
comp->compareType() == MCompare::Compare_UInt32 ||
comp->compareType() == MCompare::Compare_Object)
{
JSOp op = ReorderComparison(comp->jsop(), &left, &right);
LAllocation lhs = useRegister(left);
LAllocation rhs;
if (comp->compareType() == MCompare::Compare_Int32 ||
if (comp->isInt32Comparison() ||
comp->compareType() == MCompare::Compare_UInt32)
{
rhs = useAnyOrConstant(right);

View File

@ -1723,6 +1723,9 @@ MCompare::inputType()
return MIRType_Boolean;
case Compare_UInt32:
case Compare_Int32:
case Compare_Int32MaybeCoerceBoth:
case Compare_Int32MaybeCoerceLHS:
case Compare_Int32MaybeCoerceRHS:
return MIRType_Int32;
case Compare_Double:
case Compare_DoubleMaybeCoerceLHS:
@ -1809,7 +1812,7 @@ MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
if ((lhs == MIRType_Int32 && rhs == MIRType_Int32) ||
(lhs == MIRType_Boolean && rhs == MIRType_Boolean))
{
compareType_ = Compare_Int32;
compareType_ = Compare_Int32MaybeCoerceBoth;
return;
}
@ -1818,7 +1821,7 @@ MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
(lhs == MIRType_Int32 || lhs == MIRType_Boolean) &&
(rhs == MIRType_Int32 || rhs == MIRType_Boolean))
{
compareType_ = Compare_Int32;
compareType_ = Compare_Int32MaybeCoerceBoth;
return;
}

View File

@ -2192,6 +2192,9 @@ class MCompare
// Int32 compared to Int32
// Boolean compared to Boolean
Compare_Int32,
Compare_Int32MaybeCoerceBoth,
Compare_Int32MaybeCoerceLHS,
Compare_Int32MaybeCoerceRHS,
// Int32 compared as unsigneds
Compare_UInt32,
@ -2258,6 +2261,12 @@ class MCompare
CompareType compareType() const {
return compareType_;
}
bool isInt32Comparison() const {
return compareType() == Compare_Int32 ||
compareType() == Compare_Int32MaybeCoerceBoth ||
compareType() == Compare_Int32MaybeCoerceLHS ||
compareType() == Compare_Int32MaybeCoerceRHS;
}
bool isDoubleComparison() const {
return compareType() == Compare_Double ||
compareType() == Compare_DoubleMaybeCoerceLHS ||
@ -3041,10 +3050,12 @@ class MToInt32
public ToInt32Policy
{
bool canBeNegativeZero_;
MacroAssembler::IntConversionInputKind conversion_;
MToInt32(MDefinition *def)
MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion)
: MUnaryInstruction(def),
canBeNegativeZero_(true)
canBeNegativeZero_(true),
conversion_(conversion)
{
setResultType(MIRType_Int32);
setMovable();
@ -3052,9 +3063,11 @@ class MToInt32
public:
INSTRUCTION_HEADER(ToInt32)
static MToInt32 *New(TempAllocator &alloc, MDefinition *def)
static MToInt32 *New(TempAllocator &alloc, MDefinition *def,
MacroAssembler::IntConversionInputKind conversion =
MacroAssembler::IntConversion_Any)
{
return new(alloc) MToInt32(def);
return new(alloc) MToInt32(def, conversion);
}
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
@ -3073,6 +3086,10 @@ class MToInt32
return this;
}
MacroAssembler::IntConversionInputKind conversion() const {
return conversion_;
}
bool congruentTo(MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}

View File

@ -141,7 +141,7 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
if (compare->compareType() == MCompare::Compare_Boolean &&
def->getOperand(0)->type() == MIRType_Boolean)
{
compare->setCompareType(MCompare::Compare_Int32);
compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
}
// Compare_Boolean specialization is done for "Anything === Bool"
@ -242,9 +242,28 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
replace = MToFloat32::New(alloc, in, convert);
break;
}
case MIRType_Int32:
replace = MToInt32::New(alloc, in);
case MIRType_Int32: {
MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly;
if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) ||
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1))
{
convert = MacroAssembler::IntConversion_Any;
}
if (convert == MacroAssembler::IntConversion_NumbersOnly) {
if (in->type() != MIRType_Int32 && in->type() != MIRType_Value)
in = boxAt(alloc, def, in);
} else {
if (in->type() == MIRType_Undefined ||
in->type() == MIRType_String ||
in->type() == MIRType_Object)
{
in = boxAt(alloc, def, in);
}
}
replace = MToInt32::New(alloc, in, convert);
break;
}
case MIRType_Object:
replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible);
break;

View File

@ -1160,7 +1160,7 @@ class Assembler
LessThanOrEqual = LE,
Overflow = VS,
Signed = MI,
Unsigned = PL,
NotSigned = PL,
Zero = EQ,
NonZero = NE,
Always = AL,

View File

@ -1124,9 +1124,9 @@ CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &ind
int32_t cases = mir->numCases();
// Lower value with low value
masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::Unsigned);
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::NotSigned);
AutoForbidPools afp(&masm);
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::Unsigned);
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::NotSigned);
masm.ma_b(defaultcase);
// To fill in the CodeLabels for the case entries, we need to first

View File

@ -958,7 +958,7 @@ MacroAssemblerARM::ma_mod_mask(Register src, Register dest, Register hold, int32
// Do a trial subtraction, this is the same operation as cmp, but we store the dest
ma_sub(dest, Imm32(mask), secondScratchReg_, SetCond);
// If (sum - C) > 0, store sum - C back into sum, thus performing a modulus.
ma_mov(secondScratchReg_, dest, NoSetCond, Unsigned);
ma_mov(secondScratchReg_, dest, NoSetCond, NotSigned);
// Get rid of the bits that we extracted before, and set the condition codes
as_mov(ScratchRegister, lsr(ScratchRegister, shift), SetCond);
// If the shift produced zero, finish, otherwise, continue in the loop.
@ -3884,7 +3884,7 @@ MacroAssemblerARMCompat::floor(FloatRegister input, Register output, Label *bail
// the int range, and special handling is required.
// zero is also caught by this case, but floor of a negative number
// should never be zero.
ma_b(bail, Unsigned);
ma_b(bail, NotSigned);
bind(&fin);
}
@ -3936,7 +3936,7 @@ MacroAssemblerARMCompat::floorf(FloatRegister input, Register output, Label *bai
// the int range, and special handling is required.
// zero is also caught by this case, but floor of a negative number
// should never be zero.
ma_b(bail, Unsigned);
ma_b(bail, NotSigned);
bind(&fin);
}
@ -4023,7 +4023,7 @@ MacroAssemblerARMCompat::round(FloatRegister input, Register output, Label *bail
// If the result looks non-negative, then this value didn't actually fit into
// the int range, and special handling is required, or it was zero, which means
// the result is actually -0.0 which also requires special handling.
ma_b(bail, Unsigned);
ma_b(bail, NotSigned);
bind(&fin);
}

View File

@ -455,7 +455,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
masm.ma_sub(r8, Imm32(1), r8, SetCond);
masm.ma_b(&copyLoopTop, Assembler::Unsigned);
masm.ma_b(&copyLoopTop, Assembler::NotSigned);
}
// translate the framesize from values into bytes

View File

@ -1949,8 +1949,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// Update minY/maxY for frames that we just placed. Do not factor
// text into the equation.
if (pfd->mVerticalAlign == VALIGN_OTHER) {
// Text frames do not contribute to the min/max Y values for the
// line (instead their parent frame's font-size contributes).
// Text frames and bullets do not contribute to the min/max Y values for
// the line (instead their parent frame's font-size contributes).
// XXXrbs -- relax this restriction because it causes text frames
// to jam together when 'font-size-adjust' is enabled
// and layout is using dynamic font heights (bug 20394)
@ -1961,17 +1961,15 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
// For example in quirks mode, avoiding empty text frames prevents
// "tall" lines around elements like <hr> since the rules of <hr>
// in quirks.css have pseudo text contents with LF in them.
#if 0
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
#else
// Only consider non empty text frames when line-height=normal
bool canUpdate = !pfd->GetFlag(PFD_ISTEXTFRAME);
if (!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
if ((!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) ||
(canUpdate && (pfd->GetFlag(PFD_ISBULLET) ||
nsGkAtoms::bulletFrame == frame->GetType()))) {
// Only consider bullet / non-empty text frames when line-height:normal.
canUpdate =
frame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
}
if (canUpdate) {
#endif
nscoord yTop, yBottom;
if (frameSpan) {
// For spans that were are now placing, use their position

View File

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Bug 942017</title>
<style type="text/css">
@font-face {
font-family: DejaVuSansMono;
src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
}
html,body {
color:black; background-color:white; font-size:24px; font-family:DejaVuSansMono; padding:20px; margin:0;
}
div {
float: left;
padding: 1em 2em;
outline: 2px solid black;
background: black;
}
div.a { line-height: 0.5em; }
div.b { line-height: 2em; }
div.i l { margin-left:2.84ch; }
l { display:block; outline:1px solid green; width:1ch; direction:rtl; white-space:nowrap; }
x { display:inline-block; width:2.84ch; height:1px; vertical-align:top; }
</style>
</head>
<body>
<div class="a">
<l>X<x></x></l>
<l>X<x></x></l>
</div>
<br clear="all">
<div class="b">
<l>X<x></x></l>
<l>X<x></x></l>
</div>
<br clear="all">
<div class="a i">
<l>X<x></x></l>
<l>X<x></x></l>
</div>
<br clear="all">
<div class="b i">
<l>X<x></x></l>
<l>X<x></x></l>
</div>
</body>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Bug 942017</title>
<style type="text/css">
@font-face {
font-family: DejaVuSansMono;
src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
}
html,body {
color:black; background-color:white; font-size:24px; font-family:DejaVuSansMono; padding:20px; margin:0;
}
div {
float: left;
padding: 1em 2em;
outline: 2px solid black;
background: black;
list-style-type: decimal;
}
div.a { line-height: 0.5em; }
div.b { line-height: 2em; }
div.i { list-style-position: inside; }
li { outline:1px solid green; padding:0; margin:0; letter-spacing:0; }
</style>
</head>
<body>
<div class="a">
<li>X</li>
<li>X</li>
</div>
<br clear="all">
<div class="b">
<li>X</li>
<li>X</li>
</div>
<br clear="all">
<div class="a i">
<li>X</li>
<li>X</li>
</div>
<br clear="all">
<div class="b i">
<li>X</li>
<li>X</li>
</div>
</body>
</html>

View File

@ -1785,4 +1785,5 @@ fuzzy-if(cocoaWidget,1,40) == 928607-1.html 928607-1-ref.html
== 931853-quirks.html 931853-quirks-ref.html
== 936670-1.svg 936670-1-ref.svg
== 941940-1.html 941940-1-ref.html
== 942017.html 942017-ref.html
fails-if(winWidget&&!d2d) == 942672-1.html 942672-1-ref.html

View File

@ -436,15 +436,21 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
return(_status);
}
static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
/* Is it worth actually looking through the check lists? Probably not. */
pctx=STAILQ_NEXT(pctx,entry);
}
return pctx != NULL;
}
/*
Compare this newly initialized candidate against the other initialized
candidates and discard the lower-priority one if they are redundant.
This algorithm combined with the other algorithms, favors
host > srflx > relay
This actually won't prune relayed in the very rare
case that relayed is the same. Not relevant in practice.
*/
int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
{
@ -463,12 +469,13 @@ int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *co
(c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
/*
These are redundant. Remove the lower pri one.
These are redundant. Remove the lower pri one, or if pairing has
already occurred, remove the newest one.
Since this algorithmis run whenever a new candidate
is initialized, there should at most one duplicate.
*/
if (c1->priority < c2->priority) {
if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
tmp = c1;
*was_pruned = 1;
}

View File

@ -336,6 +336,10 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
ABORT(R_FAILED);
}
/* Set this first; if we fail partway through, we do not want to end
* up in UNPAIRED after creating some pairs. */
pctx->state = NR_ICE_PEER_STATE_PAIRED;
stream=STAILQ_FIRST(&pctx->peer_streams);
while(stream){
if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
@ -345,7 +349,6 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
stream=STAILQ_NEXT(stream,entry);
}
pctx->state = NR_ICE_PEER_STATE_PAIRED;
_status=0;
abort:

View File

@ -380,6 +380,28 @@ nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
nr_turn_client_cancel(ctx);
RFREE(ctx->username);
ctx->username = 0;
r_data_destroy(&ctx->password);
RFREE(ctx->nonce);
ctx->nonce = 0;
RFREE(ctx->realm);
ctx->realm = 0;
/* Destroy the STUN client ctxs */
while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
nr_turn_stun_ctx_destroy(&stun);
}
/* Destroy the permissions */
while (!STAILQ_EMPTY(&ctx->permissions)) {
nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
nr_turn_permission_destroy(&perm);
}
RFREE(ctx);
return(0);
@ -457,6 +479,8 @@ abort:
int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
{
nr_turn_stun_ctx *stun = 0;
if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
ctx->state == NR_TURN_CLIENT_STATE_FAILED)
return 0;
@ -482,29 +506,11 @@ int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
}
}
/* Setting these values to 0 isn't strictly necessary, but
it protects us in case we double cancel and for
some reason bungle the states above in future.*/
RFREE(ctx->username);
ctx->username = 0;
r_data_destroy(&ctx->password);
RFREE(ctx->nonce);
ctx->nonce = 0;
RFREE(ctx->realm);
ctx->realm = 0;
/* Destroy the STUN client ctxs */
while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
nr_turn_stun_ctx_destroy(&stun);
}
/* Destroy the permissions */
while (!STAILQ_EMPTY(&ctx->permissions)) {
nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
nr_turn_permission_destroy(&perm);
/* Cancel the STUN client ctxs */
stun = STAILQ_FIRST(&ctx->stun_ctxs);
while (stun) {
nr_stun_client_cancel(stun->stun);
stun = STAILQ_NEXT(stun, entry);
}
/* Cancel the timers, if not already cancelled */

View File

@ -329,14 +329,16 @@ nsresult MediaPipeline::SendPacket(TransportFlow *flow, const void *data,
return NS_OK;
}
void MediaPipeline::increment_rtp_packets_sent() {
void MediaPipeline::increment_rtp_packets_sent(int32_t bytes) {
++rtp_packets_sent_;
rtp_bytes_sent_ += bytes;
if (!(rtp_packets_sent_ % 100)) {
MOZ_MTLOG(ML_INFO, "RTP sent packet count for " << description_
<< " Pipeline " << static_cast<void *>(this)
<< " Flow : " << static_cast<void *>(rtp_transport_)
<< ": " << rtp_packets_sent_);
<< ": " << rtp_packets_sent_
<< " (" << rtp_bytes_sent_ << " bytes)");
}
}
@ -350,13 +352,15 @@ void MediaPipeline::increment_rtcp_packets_sent() {
}
}
void MediaPipeline::increment_rtp_packets_received() {
void MediaPipeline::increment_rtp_packets_received(int32_t bytes) {
++rtp_packets_received_;
rtp_bytes_received_ += bytes;
if (!(rtp_packets_received_ % 100)) {
MOZ_MTLOG(ML_INFO, "RTP received packet count for " << description_
<< " Pipeline " << static_cast<void *>(this)
<< " Flow : " << static_cast<void *>(rtp_transport_)
<< ": " << rtp_packets_received_);
<< ": " << rtp_packets_received_
<< " (" << rtp_bytes_received_ << " bytes)");
}
}
@ -403,13 +407,12 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
// TODO(ekr@rtfm.com): filter for DTLS here and in RtcpPacketReceived
// TODO(ekr@rtfm.com): filter on SSRC for bundle
increment_rtp_packets_received();
// Make a copy rather than cast away constness
ScopedDeletePtr<unsigned char> inner_data(
new unsigned char[len]);
memcpy(inner_data, data, len);
int out_len;
int out_len = 0;
nsresult res = rtp_recv_srtp_->UnprotectRtp(inner_data,
len, len, &out_len);
if (!NS_SUCCEEDED(res)) {
@ -426,6 +429,8 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
return;
}
increment_rtp_packets_received(out_len);
(void)conduit_->ReceivedRTPPacket(inner_data, out_len); // Ignore error codes
}
@ -612,7 +617,7 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
if (!NS_SUCCEEDED(res))
return res;
pipeline_->increment_rtp_packets_sent();
pipeline_->increment_rtp_packets_sent(out_len);
return pipeline_->SendPacket(pipeline_->rtp_transport_, inner_data,
out_len);
}

View File

@ -92,6 +92,8 @@ class MediaPipeline : public sigslot::has_slots<> {
rtcp_packets_sent_(0),
rtp_packets_received_(0),
rtcp_packets_received_(0),
rtp_bytes_sent_(0),
rtp_bytes_received_(0),
pc_(pc),
description_() {
// To indicate rtcp-mux rtcp_transport should be nullptr.
@ -123,17 +125,20 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual nsresult Init();
virtual Direction direction() const { return direction_; }
virtual TrackID trackid() const { return track_id_; }
bool IsDoingRtcpMux() const {
return (rtp_transport_ == rtcp_transport_);
}
int rtp_packets_sent() const { return rtp_packets_sent_; }
int rtcp_packets_sent() const { return rtcp_packets_sent_; }
int rtp_packets_received() const { return rtp_packets_received_; }
int rtcp_packets_received() const { return rtcp_packets_received_; }
int32_t rtp_packets_sent() const { return rtp_packets_sent_; }
int64_t rtp_bytes_sent() const { return rtp_bytes_sent_; }
int32_t rtcp_packets_sent() const { return rtcp_packets_sent_; }
int32_t rtp_packets_received() const { return rtp_packets_received_; }
int64_t rtp_bytes_received() const { return rtp_bytes_received_; }
int32_t rtcp_packets_received() const { return rtcp_packets_received_; }
MediaSessionConduit *Conduit() { return conduit_; }
MediaSessionConduit *Conduit() const { return conduit_; }
// Thread counting
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline)
@ -167,9 +172,9 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual nsresult TransportFailed_s(TransportFlow *flow); // The transport is down
virtual nsresult TransportReady_s(TransportFlow *flow); // The transport is ready
void increment_rtp_packets_sent();
void increment_rtp_packets_sent(int bytes);
void increment_rtcp_packets_sent();
void increment_rtp_packets_received();
void increment_rtp_packets_received(int bytes);
void increment_rtcp_packets_received();
virtual nsresult SendPacket(TransportFlow *flow, const void* data, int len);
@ -216,10 +221,12 @@ class MediaPipeline : public sigslot::has_slots<> {
// Written only on STS thread. May be read on other
// threads but since there is no mutex, the values
// will only be approximate.
int rtp_packets_sent_;
int rtcp_packets_sent_;
int rtp_packets_received_;
int rtcp_packets_received_;
int32_t rtp_packets_sent_;
int32_t rtcp_packets_sent_;
int32_t rtp_packets_received_;
int32_t rtcp_packets_received_;
int64_t rtp_bytes_sent_;
int64_t rtp_bytes_received_;
// Written on Init. Read on STS thread.
std::string pc_;

View File

@ -63,6 +63,8 @@
#include "mozilla/dom/DataChannelBinding.h"
#include "MediaStreamList.h"
#include "MediaStreamTrack.h"
#include "AudioStreamTrack.h"
#include "VideoStreamTrack.h"
#include "nsIScriptGlobalObject.h"
#include "DOMMediaStream.h"
#include "rlogringbuffer.h"
@ -1796,26 +1798,51 @@ PeerConnectionImpl::IceGatheringStateChange_m(PCImplIceGatheringState aState)
}
#ifdef MOZILLA_INTERNAL_API
void PeerConnectionImpl::GetStats_s(
uint32_t trackId,
bool internalStats,
DOMHighResTimeStamp now) {
nsresult result = NS_OK;
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternal);
if (!report) {
result = NS_ERROR_FAILURE;
class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
public:
RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
mPcid = pcid;
mInboundRTPStreamStats.Construct();
mOutboundRTPStreamStats.Construct();
mMediaStreamTrackStats.Construct();
mMediaStreamStats.Construct();
mTransportStats.Construct();
mIceComponentStats.Construct();
mIceCandidatePairStats.Construct();
mIceCandidateStats.Construct();
mCodecStats.Construct();
}
};
report->mPcid.Construct(NS_ConvertASCIItoUTF16(mHandle.c_str()));
nsresult PeerConnectionImpl::GetStatsImpl_s(
TrackID trackId,
bool internalStats,
DOMHighResTimeStamp now,
RTCStatsReportInternal *report) {
if (mMedia) {
RefPtr<NrIceMediaStream> mediaStream(
mMedia->ice_media_stream(trackId));
nsresult rv;
// Gather stats from media pipeline (can't touch stream itself on STS)
for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
rv = mMedia->GetLocalStream(i)->GetPipelineStats(now, trackId,
&report->mInboundRTPStreamStats.Value(),
&report->mOutboundRTPStreamStats.Value());
NS_ENSURE_SUCCESS(rv, rv);
}
for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) {
rv = mMedia->GetRemoteStream(i)->GetPipelineStats(now, trackId,
&report->mInboundRTPStreamStats.Value(),
&report->mOutboundRTPStreamStats.Value());
NS_ENSURE_SUCCESS(rv, rv);
}
// Gather stats from ICE
RefPtr<NrIceMediaStream> mediaStream(mMedia->ice_media_stream(trackId));
if (mediaStream) {
std::vector<NrIceCandidatePair> candPairs;
mediaStream->GetCandidatePairs(&candPairs);
report->mIceCandidatePairStats.Construct();
report->mIceCandidateStats.Construct();
NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
@ -1869,19 +1896,32 @@ void PeerConnectionImpl::GetStats_s(
}
}
}
return NS_OK;
}
void PeerConnectionImpl::GetStats_s(
TrackID trackId,
bool internalStats,
DOMHighResTimeStamp now) {
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternalConstruct(
NS_ConvertASCIItoUTF16(mHandle.c_str()), now));
nsresult rv = report ? GetStatsImpl_s(trackId, internalStats, now, report)
: NS_ERROR_UNEXPECTED;
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread,
WrapRunnable(pc,
&PeerConnectionImpl::OnStatsReport_m,
trackId,
result,
rv,
report),
NS_DISPATCH_NORMAL);
}
void PeerConnectionImpl::OnStatsReport_m(
uint32_t trackId,
TrackID trackId,
nsresult result,
nsAutoPtr<RTCStatsReportInternal> report) {
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);

View File

@ -25,6 +25,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
#include "StreamBuffer.h"
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/TimeStamp.h"
@ -528,12 +529,17 @@ private:
#ifdef MOZILLA_INTERNAL_API
// Fills in an RTCStatsReportInternal. Must be run on STS.
void GetStats_s(uint32_t trackId,
void GetStats_s(mozilla::TrackID trackId,
bool internalStats,
DOMHighResTimeStamp now);
nsresult GetStatsImpl_s(mozilla::TrackID trackId,
bool internalStats,
DOMHighResTimeStamp now,
mozilla::dom::RTCStatsReportInternal *report);
// Sends an RTCStatsReport to JS. Must run on main thread.
void OnStatsReport_m(uint32_t trackId,
void OnStatsReport_m(mozilla::TrackID trackId,
nsresult result,
nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report);

View File

@ -20,9 +20,11 @@
#include "MediaStreamList.h"
#include "nsIScriptGlobalObject.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
namespace sipcc {
@ -465,6 +467,58 @@ SourceStreamInfo::GetPipeline(int aTrack) {
return it->second;
}
// This methods gathers statistics for the getStats API.
// aTrack == 0 means gather stats for all tracks.
nsresult
SourceStreamInfo::GetPipelineStats(DOMHighResTimeStamp now, int aTrack,
Sequence<RTCInboundRTPStreamStats > *inbound,
Sequence<RTCOutboundRTPStreamStats > *outbound)
{
#ifdef MOZILLA_INTERNAL_API
ASSERT_ON_THREAD(mParent->GetSTSThread());
// walk through all the MediaPipelines and gather stats
for (std::map<int, RefPtr<MediaPipeline> >::iterator it = mPipelines.begin();
it != mPipelines.end();
++it) {
if (!aTrack || aTrack == it->first) {
const MediaPipeline &mp = *it->second;
nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ?
NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
idstr.AppendInt(mp.trackid());
switch (mp.direction()) {
case MediaPipeline::TRANSMIT: {
RTCOutboundRTPStreamStats s;
s.mTimestamp.Construct(now);
s.mId.Construct(NS_LITERAL_STRING("outbound_rtp_") + idstr);
s.mType.Construct(RTCStatsType::Outboundrtp);
// TODO: Get SSRC
// int channel = mp.Conduit()->GetChannel();
s.mSsrc.Construct(NS_LITERAL_STRING("123457"));
s.mPacketsSent.Construct(mp.rtp_packets_sent());
s.mBytesSent.Construct(mp.rtp_bytes_sent());
outbound->AppendElement(s);
break;
}
case MediaPipeline::RECEIVE: {
RTCInboundRTPStreamStats s;
s.mTimestamp.Construct(now);
s.mId.Construct(NS_LITERAL_STRING("inbound_rtp_") + idstr);
s.mType.Construct(RTCStatsType::Inboundrtp);
s.mSsrc.Construct(NS_LITERAL_STRING("123457"));
s.mPacketsReceived.Construct(mp.rtp_packets_received());
s.mBytesReceived.Construct(mp.rtp_bytes_received());
inbound->AppendElement(s);
break;
}
}
}
}
#endif
return NS_OK;
}
void
LocalSourceStreamInfo::StorePipeline(int aTrack,
mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)

View File

@ -29,12 +29,16 @@
#include "VideoUtils.h"
#include "ImageLayers.h"
#include "VideoSegment.h"
#else
namespace mozilla {
class DataChannel;
}
#endif
namespace mozilla {
class DataChannel;
namespace dom {
class RTCInboundRTPStreamStats;
class RTCOutboundRTPStreamStats;
}
}
#include "nricectx.h"
#include "nriceresolver.h"
#include "nricemediastream.h"
@ -181,7 +185,9 @@ public:
}
mozilla::RefPtr<mozilla::MediaPipeline> GetPipeline(int aTrack);
nsresult GetPipelineStats(DOMHighResTimeStamp now, int aTrack,
mozilla::dom::Sequence<mozilla::dom::RTCInboundRTPStreamStats > *inbound,
mozilla::dom::Sequence<mozilla::dom::RTCOutboundRTPStreamStats > *outbound);
protected:
std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> > mPipelines;
nsRefPtr<DOMMediaStream> mMediaStream;

View File

@ -325,7 +325,8 @@ class MediaPipelineTest : public ::testing::Test {
PR_Sleep(10000);
ASSERT_GE(p1_.GetAudioRtpCount(), 40);
ASSERT_GE(p2_.GetAudioRtpCount(), 40);
// TODO: Fix to not fail or crash (Bug 947663)
// ASSERT_GE(p2_.GetAudioRtpCount(), 40);
ASSERT_GE(p1_.GetAudioRtcpCount(), 1);
ASSERT_GE(p2_.GetAudioRtcpCount(), 1);

View File

@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
handleExistingPermission: function handleExistingPermission(request, isApp) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
handleExistingPermission: function handleExistingPermission(request, type, isApp) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = {
return true;
}
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) {
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
request.cancel();
return true;
}
@ -62,8 +62,16 @@ ContentPermissionPrompt.prototype = {
prompt: function(request) {
let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID;
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Returns true if the request was handled
if (this.handleExistingPermission(request, isApp))
if (this.handleExistingPermission(request, perm.type, isApp))
return;
let chromeWin = this.getChromeForRequest(request);
@ -72,17 +80,17 @@ ContentPermissionPrompt.prototype = {
return;
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let entityName = kEntities[request.type];
let entityName = kEntities[perm.type];
let buttons = [{
label: browserBundle.GetStringFromName(entityName + ".allow"),
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked) {
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
} else if (isApp || entityName == "desktopNotification") {
// Otherwise allow the permission for the current session (if the request comes from an app or if it's a desktop-notification request)
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
}
request.allow();
@ -93,7 +101,7 @@ ContentPermissionPrompt.prototype = {
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked)
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
request.cancel();
}

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

@ -34,9 +34,18 @@ this.MockPermissionPrompt = {
init: function() {
this.reset();
if (!registrar.isCIDRegistered(newClassID)) {
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
registrar.unregisterFactory(oldClassID, oldFactory);
try {
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
} catch (ex) {
oldClassID = "";
oldFactory = null;
dump("TEST-INFO | can't get permission prompt registered component, " +
"assuming there is none");
}
if (oldFactory) {
registrar.unregisterFactory(oldClassID, oldFactory);
}
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
}
},
@ -61,14 +70,17 @@ MockPermissionPromptInstance.prototype = {
prompt: function(request) {
this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal,
request.type);
if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
}
else {
request.cancel();
let perms = request.types.QueryInterface(Ci.nsIArray);
for (let idx = 0; idx < perms.length; idx++) {
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
if (Services.perms.testExactPermissionFromPrincipal(
request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
request.cancel();
return;
}
}
request.allow();
}
};

View File

@ -30,17 +30,25 @@ ContentPermission.prototype = {
},
prompt: function(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Reuse any remembered permission preferences
let result =
Services.perms.testExactPermissionFromPrincipal(request.principal,
request.type);
perm.type);
// We used to use the name "geo" for the geolocation permission, now we're
// using "geolocation". We need to check both to support existing
// installations.
if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
request.type == "geolocation") {
perm.type == "geolocation") {
let geoResult = Services.perms.testExactPermission(request.principal.URI,
"geo");
// We override the result only if the "geo" permission was allowed or
@ -56,7 +64,7 @@ ContentPermission.prototype = {
return;
} else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
(result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
UNKNOWN_FAIL.indexOf(request.type) >= 0)) {
UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
request.cancel();
return;
}
@ -71,16 +79,16 @@ ContentPermission.prototype = {
let remember = {value: false};
let choice = Services.prompt.confirmEx(
chromeWin,
bundle.formatStringFromName(request.type + ".title", [name], 1),
bundle.GetStringFromName(request.type + ".description"),
bundle.formatStringFromName(perm.type + ".title", [name], 1),
bundle.GetStringFromName(perm.type + ".description"),
// Set both buttons to strings with the cancel button being default
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
bundle.GetStringFromName(request.type + ".allow"),
bundle.GetStringFromName(request.type + ".deny"),
bundle.GetStringFromName(perm.type + ".allow"),
bundle.GetStringFromName(perm.type + ".deny"),
null,
bundle.GetStringFromName(request.type + ".remember"),
bundle.GetStringFromName(perm.type + ".remember"),
remember);
let action = Ci.nsIPermissionManager.ALLOW_ACTION;
@ -90,10 +98,10 @@ ContentPermission.prototype = {
if (remember.value) {
// Persist the choice if the user wants to remember
Services.perms.addFromPrincipal(request.principal, request.type, action);
Services.perms.addFromPrincipal(request.principal, perm.type, action);
} else {
// Otherwise allow the permission for the current session
Services.perms.addFromPrincipal(request.principal, request.type, action,
Services.perms.addFromPrincipal(request.principal, perm.type, action,
Ci.nsIPermissionManager.EXPIRE_SESSION);
}

View File

@ -58,6 +58,8 @@ public:
typedef typename KeyClass::KeyType KeyType;
typedef nsBaseHashtableET<KeyClass,DataType> EntryType;
using nsTHashtable<EntryType>::Contains;
nsBaseHashtable()
{
}

View File

@ -11,6 +11,9 @@
#include "mozilla/Telemetry.h"
#include "mozilla/ThreadHangStats.h"
#include "mozilla/ThreadLocal.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#include "prinrval.h"
#include "prthread.h"
@ -31,6 +34,15 @@ private:
static void MonitorThread(void* aData)
{
PR_SetCurrentThreadName("BgHangManager");
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
"NuwaMarkCurrentThread is undefined!");
NuwaMarkCurrentThread(nullptr, nullptr);
}
#endif
/* We do not hold a reference to BackgroundHangManager here
because the monitor thread only exists as long as the
BackgroundHangManager instance exists. We stop the monitor