This commit is contained in:
Phil Ringnalda 2013-12-08 08:31:41 -08:00
Родитель a20f27b394 58d1429d0f
Коммит 4c3aca9987
98 изменённых файлов: 1651 добавлений и 1423 удалений

Просмотреть файл

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/ # 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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -636,192 +636,3 @@ XULToolbarSeparatorAccessible::NativeState()
{ {
return 0; 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();
}

Просмотреть файл

@ -215,47 +215,6 @@ public:
virtual uint64_t NativeState(); 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 a11y
} // namespace mozilla } // namespace mozilla

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -91,6 +91,23 @@ function testActions(aArray)
gActionsQueue.invoke(); 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 // Private
@ -151,3 +168,20 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj)
aActionObj.checkOnClickEvent(aEvent); 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"
};

Просмотреть файл

@ -328,6 +328,14 @@ function getApplicationAccessible()
QueryInterface(nsIAccessibleApplication); 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 * Flags used for testAccessibleTree
*/ */
@ -370,11 +378,7 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
switch (prop) { switch (prop) {
case "actions": { case "actions": {
var actions = (typeof accTree.actions == "string") ? testActionNames(acc, accTree.actions);
[ 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.");
break; break;
} }

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -38,8 +38,10 @@
// Test focus events. // Test focus events.
gQueue = new eventQueue(); gQueue = new eventQueue();
gQueue.push(new synthFocus("textbox")); gQueue.push(new synthFocus("textbox",
gQueue.push(new synthFocus("textbox_multiline")); 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 synthFocus("scale"));
gQueue.push(new synthFocusOnFrame("editabledoc")); gQueue.push(new synthFocusOnFrame("editabledoc"));
gQueue.push(new synthFocus("radioclothes", gQueue.push(new synthFocus("radioclothes",

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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);
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -56,7 +56,9 @@ MOZ_TOOLKIT_SEARCH=
MOZ_PLACES= MOZ_PLACES=
MOZ_B2G=1 MOZ_B2G=1
#MOZ_NUWA_PROCESS=1 if test "$OS_TARGET" = "Android"; then
MOZ_NUWA_PROCESS=1
fi
MOZ_FOLD_LIBS=1 MOZ_FOLD_LIBS=1
MOZ_JSDOWNLOADS=1 MOZ_JSDOWNLOADS=1

Просмотреть файл

@ -2030,13 +2030,21 @@ ContentPermissionPrompt.prototype = {
prompt: function CPP_prompt(request) { 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", const kFeatureKeys = { "geolocation" : "geo",
"desktop-notification" : "desktop-notification", "desktop-notification" : "desktop-notification",
"pointerLock" : "pointerLock", "pointerLock" : "pointerLock",
}; };
// Make sure that we support the request. // Make sure that we support the request.
if (!(request.type in kFeatureKeys)) { if (!(perm.type in kFeatureKeys)) {
return; return;
} }
@ -2048,7 +2056,7 @@ ContentPermissionPrompt.prototype = {
return; return;
var autoAllow = false; var autoAllow = false;
var permissionKey = kFeatureKeys[request.type]; var permissionKey = kFeatureKeys[perm.type];
var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey); var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey);
if (result == Ci.nsIPermissionManager.DENY_ACTION) { if (result == Ci.nsIPermissionManager.DENY_ACTION) {
@ -2059,7 +2067,7 @@ ContentPermissionPrompt.prototype = {
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
autoAllow = true; autoAllow = true;
// For pointerLock, we still want to show a warning prompt. // For pointerLock, we still want to show a warning prompt.
if (request.type != "pointerLock") { if (perm.type != "pointerLock") {
request.allow(); request.allow();
return; return;
} }
@ -2073,7 +2081,7 @@ ContentPermissionPrompt.prototype = {
return; return;
// Show the prompt. // Show the prompt.
switch (request.type) { switch (perm.type) {
case "geolocation": case "geolocation":
this._promptGeo(request); this._promptGeo(request);
break; break;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -6,20 +6,156 @@
#include "GonkPermission.h" #include "GonkPermission.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#endif // MOZ_WIDGET_GONK #endif // MOZ_WIDGET_GONK
#include "nsContentPermissionHelper.h"
#include "nsIContentPermissionPrompt.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "mozilla/dom/Element.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/dom/TabParent.h"
#include "mozilla/unused.h" #include "mozilla/unused.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
using mozilla::unused; // <snicker> using mozilla::unused; // <snicker>
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla; 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() nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
{ {
MOZ_COUNT_CTOR(nsContentPermissionRequestProxy); MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
@ -31,14 +167,12 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
} }
nsresult nsresult
nsContentPermissionRequestProxy::Init(const nsACString & type, nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
const nsACString & access,
ContentPermissionRequestParent* parent) ContentPermissionRequestParent* parent)
{ {
NS_ASSERTION(parent, "null parent"); NS_ASSERTION(parent, "null parent");
mParent = parent; mParent = parent;
mType = type; mPermissionRequests = requests;
mAccess = access;
nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
if (!prompt) { if (!prompt) {
@ -58,17 +192,14 @@ nsContentPermissionRequestProxy::OnParentDestroyed()
NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest) NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
NS_IMETHODIMP NS_IMETHODIMP
nsContentPermissionRequestProxy::GetType(nsACString & aType) nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
{ {
aType = mType; nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
return NS_OK; if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
} types.forget(aTypes);
return NS_OK;
NS_IMETHODIMP }
nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess) return NS_ERROR_FAILURE;
{
aAccess = mAccess;
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -136,10 +267,18 @@ nsContentPermissionRequestProxy::Allow()
} }
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
if (mType.Equals("audio-capture")) { uint32_t len = mPermissionRequests.Length();
GonkPermissionService::GetInstance()->addGrantInfo( for (uint32_t i = 0; i < len; i++) {
"android.permission.RECORD_AUDIO", if (mPermissionRequests[i].type().Equals("audio-capture")) {
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid()); 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 #endif
@ -147,55 +286,3 @@ nsContentPermissionRequestProxy::Allow()
mParent = nullptr; mParent = nullptr;
return NS_OK; 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

Просмотреть файл

@ -6,60 +6,75 @@
#define nsContentPermissionHelper_h #define nsContentPermissionHelper_h
#include "nsIContentPermissionPrompt.h" #include "nsIContentPermissionPrompt.h"
#include "nsString.h" #include "nsTArray.h"
#include "nsIMutableArray.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
class nsContentPermissionRequestProxy; 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 mozilla {
namespace dom { namespace dom {
class Element; class Element;
class PermissionRequest;
class ContentPermissionRequestParent;
class PContentPermissionRequestParent;
class ContentPermissionRequestParent : public PContentPermissionRequestParent class ContentPermissionType : public nsIContentPermissionType
{ {
public: public:
ContentPermissionRequestParent(const nsACString& type, NS_DECL_ISUPPORTS
const nsACString& access, NS_DECL_NSICONTENTPERMISSIONTYPE
Element* element,
const IPC::Principal& principal);
virtual ~ContentPermissionRequestParent();
bool IsBeingDestroyed(); ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
virtual ~ContentPermissionType();
nsCOMPtr<nsIPrincipal> mPrincipal; protected:
nsCOMPtr<Element> mElement;
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
nsCString mType; nsCString mType;
nsCString mAccess; 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 dom
} // namespace mozilla } // namespace mozilla
class nsContentPermissionRequestProxy : public nsIContentPermissionRequest class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
{ {
public: public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
nsContentPermissionRequestProxy(); nsContentPermissionRequestProxy();
virtual ~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(); void OnParentDestroyed();
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
private: private:
// Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy. // Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
mozilla::dom::ContentPermissionRequestParent* mParent; mozilla::dom::ContentPermissionRequestParent* mParent;
nsCString mType; nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
nsCString mAccess;
}; };
#endif // nsContentPermissionHelper_h
#endif // nsContentPermissionHelper_h

Просмотреть файл

@ -105,6 +105,31 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
return cameraManager.forget(); 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 void
nsDOMCameraManager::GetCamera(const CameraSelector& aOptions, nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
nsICameraGetCameraCallback* onSuccess, nsICameraGetCameraCallback* onSuccess,
@ -116,22 +141,10 @@ nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
cameraId = 1; 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__); DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
// Creating this object will trigger the onSuccess handler
nsRefPtr<nsDOMCameraControl> cameraControl = nsRefPtr<nsDOMCameraControl> cameraControl =
new nsDOMCameraControl(cameraId, mCameraThread, GetCameraControl(cameraId, onSuccess, onError.WasPassed() ? onError.Value() : nullptr, aRv);
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow);
Register(cameraControl);
} }
void void

Просмотреть файл

@ -49,6 +49,11 @@ public:
CreateInstance(nsPIDOMWindow* aWindow); CreateInstance(nsPIDOMWindow* aWindow);
static bool IsWindowStillActive(uint64_t aWindowId); 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 Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
void OnNavigation(uint64_t aWindowId); void OnNavigation(uint64_t aWindowId);

Просмотреть файл

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

Просмотреть файл

@ -7,15 +7,13 @@
interface nsIPrincipal; interface nsIPrincipal;
interface nsIDOMWindow; interface nsIDOMWindow;
interface nsIDOMElement; interface nsIDOMElement;
interface nsIArray;
/** /**
* Interface allows access to a content to request * Interface provides the request type and its access.
* permission to perform a privileged operation such as
* geolocation.
*/ */
[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)] [scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
interface nsIContentPermissionRequest : nsISupports { interface nsIContentPermissionType : nsISupports {
/** /**
* The type of the permission request, such as * The type of the permission request, such as
* "geolocation". * "geolocation".
@ -27,8 +25,22 @@ interface nsIContentPermissionRequest : nsISupports {
* "read". * "read".
*/ */
readonly attribute ACString access; 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. * The principal of the permission request.
*/ */
readonly attribute nsIPrincipal principal; readonly attribute nsIPrincipal principal;

Просмотреть файл

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

Просмотреть файл

@ -1249,93 +1249,13 @@ ContentParent::ContentParent(mozIApplication* aApp,
Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle()); Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
// Set the subprocess's priority. We do this early on because we're likely InitInternal(aInitialPriority,
// /lowering/ the process's CPU and memory priority, which it has inherited true, /* Setup off-main thread compositing */
// from this process. true /* Send registered chrome */);
//
// 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
} }
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
static const FileDescriptor* static const mozilla::ipc::FileDescriptor*
FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds, FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
ProtocolId aProtoId) ProtocolId aProtoId)
{ {
@ -1401,8 +1321,9 @@ ContentParent::ContentParent(ContentParent* aTemplate,
priority = PROCESS_PRIORITY_FOREGROUND; priority = PROCESS_PRIORITY_FOREGROUND;
} }
ProcessPriorityManager::SetProcessPriority(this, priority); InitInternal(priority,
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this); false, /* Setup Off-main thread compositing */
false /* Send registered chrome */);
} }
#endif // MOZ_NUWA_PROCESS #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 bool
ContentParent::IsAlive() ContentParent::IsAlive()
{ {

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -281,6 +281,15 @@ PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
{ {
MOZ_ASSERT(NS_IsMainThread()); 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()) { if (!mNuwaForkWaitTasks.IsEmpty()) {
mNuwaForkWaitTasks.ElementAt(0)->Cancel(); mNuwaForkWaitTasks.ElementAt(0)->Cancel();
mNuwaForkWaitTasks.RemoveElementAt(0); mNuwaForkWaitTasks.RemoveElementAt(0);
@ -312,6 +321,14 @@ PreallocatedProcessManagerImpl::OnNuwaReady()
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess, ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
hal::PROCESS_PRIORITY_FOREGROUND); hal::PROCESS_PRIORITY_FOREGROUND);
mIsNuwaReady = true; 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(); NuwaFork();
} }

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/BrowserElementParent.h" #include "mozilla/BrowserElementParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h" #include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/Hal.h" #include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/layers/CompositorParent.h" #include "mozilla/layers/CompositorParent.h"
@ -579,9 +580,10 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
} }
PContentPermissionRequestParent* 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 bool

Просмотреть файл

@ -225,7 +225,8 @@ public:
virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor); virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor);
virtual PContentPermissionRequestParent* 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 bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor);
virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent( virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent(

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -226,8 +226,20 @@ BaselineInspector::expectedCompareType(jsbytecode *pc)
if (!first && !dimorphicStub(pc, &first, &second)) if (!first && !dimorphicStub(pc, &first, &second))
return MCompare::Compare_Unknown; 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; return MCompare::Compare_Int32;
}
if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) { if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
ICCompare_NumberWithUndefined *coerce = ICCompare_NumberWithUndefined *coerce =

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -141,7 +141,7 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
if (compare->compareType() == MCompare::Compare_Boolean && if (compare->compareType() == MCompare::Compare_Boolean &&
def->getOperand(0)->type() == MIRType_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" // Compare_Boolean specialization is done for "Anything === Bool"
@ -242,9 +242,28 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
replace = MToFloat32::New(alloc, in, convert); replace = MToFloat32::New(alloc, in, convert);
break; break;
} }
case MIRType_Int32: case MIRType_Int32: {
replace = MToInt32::New(alloc, in); 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; break;
}
case MIRType_Object: case MIRType_Object:
replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible); replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible);
break; break;

Просмотреть файл

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

Просмотреть файл

@ -1124,9 +1124,9 @@ CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &ind
int32_t cases = mir->numCases(); int32_t cases = mir->numCases();
// Lower value with low value // Lower value with low value
masm.ma_sub(index, Imm32(mir->low()), index, SetCond); 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); 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); masm.ma_b(defaultcase);
// To fill in the CodeLabels for the case entries, we need to first // To fill in the CodeLabels for the case entries, we need to first

Просмотреть файл

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

Просмотреть файл

@ -455,7 +455,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex); masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
masm.ma_sub(r8, Imm32(1), r8, SetCond); 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 // translate the framesize from values into bytes

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -436,15 +436,21 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
return(_status); 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 Compare this newly initialized candidate against the other initialized
candidates and discard the lower-priority one if they are redundant. candidates and discard the lower-priority one if they are redundant.
This algorithm combined with the other algorithms, favors This algorithm combined with the other algorithms, favors
host > srflx > relay 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) 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)){ (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 Since this algorithmis run whenever a new candidate
is initialized, there should at most one duplicate. 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; tmp = c1;
*was_pruned = 1; *was_pruned = 1;
} }

Просмотреть файл

@ -336,6 +336,10 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
ABORT(R_FAILED); 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); stream=STAILQ_FIRST(&pctx->peer_streams);
while(stream){ while(stream){
if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_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); stream=STAILQ_NEXT(stream,entry);
} }
pctx->state = NR_ICE_PEER_STATE_PAIRED;
_status=0; _status=0;
abort: abort:

Просмотреть файл

@ -380,6 +380,28 @@ nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
nr_turn_client_cancel(ctx); 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); RFREE(ctx);
return(0); return(0);
@ -457,6 +479,8 @@ abort:
int nr_turn_client_cancel(nr_turn_client_ctx *ctx) int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
{ {
nr_turn_stun_ctx *stun = 0;
if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED || if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
ctx->state == NR_TURN_CLIENT_STATE_FAILED) ctx->state == NR_TURN_CLIENT_STATE_FAILED)
return 0; 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 /* Cancel the STUN client ctxs */
it protects us in case we double cancel and for stun = STAILQ_FIRST(&ctx->stun_ctxs);
some reason bungle the states above in future.*/ while (stun) {
RFREE(ctx->username); nr_stun_client_cancel(stun->stun);
ctx->username = 0; stun = STAILQ_NEXT(stun, entry);
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 timers, if not already cancelled */ /* Cancel the timers, if not already cancelled */

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -63,6 +63,8 @@
#include "mozilla/dom/DataChannelBinding.h" #include "mozilla/dom/DataChannelBinding.h"
#include "MediaStreamList.h" #include "MediaStreamList.h"
#include "MediaStreamTrack.h" #include "MediaStreamTrack.h"
#include "AudioStreamTrack.h"
#include "VideoStreamTrack.h"
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "DOMMediaStream.h" #include "DOMMediaStream.h"
#include "rlogringbuffer.h" #include "rlogringbuffer.h"
@ -1796,26 +1798,51 @@ PeerConnectionImpl::IceGatheringStateChange_m(PCImplIceGatheringState aState)
} }
#ifdef MOZILLA_INTERNAL_API #ifdef MOZILLA_INTERNAL_API
void PeerConnectionImpl::GetStats_s( class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
uint32_t trackId, public:
bool internalStats, RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
DOMHighResTimeStamp now) { mPcid = pcid;
mInboundRTPStreamStats.Construct();
nsresult result = NS_OK; mOutboundRTPStreamStats.Construct();
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternal); mMediaStreamTrackStats.Construct();
if (!report) { mMediaStreamStats.Construct();
result = NS_ERROR_FAILURE; 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) { if (mMedia) {
RefPtr<NrIceMediaStream> mediaStream( nsresult rv;
mMedia->ice_media_stream(trackId));
// 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) { if (mediaStream) {
std::vector<NrIceCandidatePair> candPairs; std::vector<NrIceCandidatePair> candPairs;
mediaStream->GetCandidatePairs(&candPairs); mediaStream->GetCandidatePairs(&candPairs);
report->mIceCandidatePairStats.Construct();
report->mIceCandidateStats.Construct();
NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str()); NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) { for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str()); 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); nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread, RUN_ON_THREAD(mThread,
WrapRunnable(pc, WrapRunnable(pc,
&PeerConnectionImpl::OnStatsReport_m, &PeerConnectionImpl::OnStatsReport_m,
trackId, trackId,
result, rv,
report), report),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
void PeerConnectionImpl::OnStatsReport_m( void PeerConnectionImpl::OnStatsReport_m(
uint32_t trackId, TrackID trackId,
nsresult result, nsresult result,
nsAutoPtr<RTCStatsReportInternal> report) { nsAutoPtr<RTCStatsReportInternal> report) {
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver); nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);

Просмотреть файл

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

Просмотреть файл

@ -20,9 +20,11 @@
#include "MediaStreamList.h" #include "MediaStreamList.h"
#include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObject.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#endif #endif
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom;
namespace sipcc { namespace sipcc {
@ -465,6 +467,58 @@ SourceStreamInfo::GetPipeline(int aTrack) {
return it->second; 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 void
LocalSourceStreamInfo::StorePipeline(int aTrack, LocalSourceStreamInfo::StorePipeline(int aTrack,
mozilla::RefPtr<mozilla::MediaPipeline> aPipeline) mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)

Просмотреть файл

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

Просмотреть файл

@ -325,7 +325,8 @@ class MediaPipelineTest : public ::testing::Test {
PR_Sleep(10000); PR_Sleep(10000);
ASSERT_GE(p1_.GetAudioRtpCount(), 40); 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(p1_.GetAudioRtcpCount(), 1);
ASSERT_GE(p2_.GetAudioRtcpCount(), 1); ASSERT_GE(p2_.GetAudioRtcpCount(), 1);

Просмотреть файл

@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]), QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
handleExistingPermission: function handleExistingPermission(request, isApp) { handleExistingPermission: function handleExistingPermission(request, type, isApp) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type); let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow(); request.allow();
return true; return true;
@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = {
return true; return true;
} }
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) { if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
request.cancel(); request.cancel();
return true; return true;
} }
@ -62,8 +62,16 @@ ContentPermissionPrompt.prototype = {
prompt: function(request) { prompt: function(request) {
let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID; 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 // Returns true if the request was handled
if (this.handleExistingPermission(request, isApp)) if (this.handleExistingPermission(request, perm.type, isApp))
return; return;
let chromeWin = this.getChromeForRequest(request); let chromeWin = this.getChromeForRequest(request);
@ -72,17 +80,17 @@ ContentPermissionPrompt.prototype = {
return; return;
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let entityName = kEntities[request.type]; let entityName = kEntities[perm.type];
let buttons = [{ let buttons = [{
label: browserBundle.GetStringFromName(entityName + ".allow"), label: browserBundle.GetStringFromName(entityName + ".allow"),
callback: function(aChecked) { callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception // If the user checked "Don't ask again", make a permanent exception
if (aChecked) { 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") { } 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) // 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(); request.allow();
@ -93,7 +101,7 @@ ContentPermissionPrompt.prototype = {
callback: function(aChecked) { callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception // If the user checked "Don't ask again", make a permanent exception
if (aChecked) 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(); request.cancel();
} }

Просмотреть файл

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

Просмотреть файл

@ -34,9 +34,18 @@ this.MockPermissionPrompt = {
init: function() { init: function() {
this.reset(); this.reset();
if (!registrar.isCIDRegistered(newClassID)) { if (!registrar.isCIDRegistered(newClassID)) {
oldClassID = registrar.contractIDToCID(CONTRACT_ID); try {
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory); oldClassID = registrar.contractIDToCID(CONTRACT_ID);
registrar.unregisterFactory(oldClassID, oldFactory); 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); registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
} }
}, },
@ -61,14 +70,17 @@ MockPermissionPromptInstance.prototype = {
prompt: function(request) { prompt: function(request) {
this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal, let perms = request.types.QueryInterface(Ci.nsIArray);
request.type); for (let idx = 0; idx < perms.length; idx++) {
if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) { let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
request.allow(); if (Services.perms.testExactPermissionFromPrincipal(
} request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
else { request.cancel();
request.cancel(); return;
}
} }
request.allow();
} }
}; };

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -11,6 +11,9 @@
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/ThreadHangStats.h" #include "mozilla/ThreadHangStats.h"
#include "mozilla/ThreadLocal.h" #include "mozilla/ThreadLocal.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#include "prinrval.h" #include "prinrval.h"
#include "prthread.h" #include "prthread.h"
@ -31,6 +34,15 @@ private:
static void MonitorThread(void* aData) static void MonitorThread(void* aData)
{ {
PR_SetCurrentThreadName("BgHangManager"); 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 /* We do not hold a reference to BackgroundHangManager here
because the monitor thread only exists as long as the because the monitor thread only exists as long as the
BackgroundHangManager instance exists. We stop the monitor BackgroundHangManager instance exists. We stop the monitor