зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to f-t
This commit is contained in:
Коммит
4c3aca9987
2
CLOBBER
2
CLOBBER
|
@ -18,4 +18,4 @@
|
|||
# Modifying this file will now automatically clobber the buildbot machines \o/
|
||||
#
|
||||
|
||||
Bug 937317 required a clobber on Windows landing, backout probably will too
|
||||
Bug 908695 required a clobber on Windows because bug 928195
|
||||
|
|
|
@ -1310,7 +1310,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
|||
accessible = new XULLabelAccessible(aContent, aDoc);
|
||||
|
||||
} else if (role.EqualsLiteral("xul:textbox")) {
|
||||
accessible = new XULTextFieldAccessible(aContent, aDoc);
|
||||
accessible = new EnumRoleAccessible(aContent, aDoc, roles::SECTION);
|
||||
|
||||
} else if (role.EqualsLiteral("xul:thumb")) {
|
||||
accessible = new XULThumbAccessible(aContent, aDoc);
|
||||
|
|
|
@ -1052,56 +1052,37 @@ Accessible::TakeFocus()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
ENameValueFlag
|
||||
Accessible::GetHTMLName(nsString& aLabel)
|
||||
void
|
||||
Accessible::XULElmName(DocAccessible* aDocument,
|
||||
nsIContent* aElm, nsString& aName)
|
||||
{
|
||||
Accessible* labelAcc = nullptr;
|
||||
HTMLLabelIterator iter(Document(), this);
|
||||
while ((labelAcc = iter.Next())) {
|
||||
nsTextEquivUtils::AppendTextEquivFromContent(this, labelAcc->GetContent(),
|
||||
&aLabel);
|
||||
aLabel.CompressWhitespace();
|
||||
}
|
||||
/**
|
||||
* 3 main cases for XUL Controls to be labeled
|
||||
* 1 - control contains label="foo"
|
||||
* 2 - control has, as a child, a label element
|
||||
* - label has either value="foo" or children
|
||||
* 3 - non-child label contains control="controlID"
|
||||
* - label has either value="foo" or children
|
||||
* Once a label is found, the search is discontinued, so a control
|
||||
* that has a label child as well as having a label external to
|
||||
* the control that uses the control="controlID" syntax will use
|
||||
* the child label for its Name.
|
||||
*/
|
||||
|
||||
if (!aLabel.IsEmpty())
|
||||
return eNameOK;
|
||||
|
||||
nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
|
||||
return aLabel.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3 main cases for XUL Controls to be labeled
|
||||
* 1 - control contains label="foo"
|
||||
* 2 - control has, as a child, a label element
|
||||
* - label has either value="foo" or children
|
||||
* 3 - non-child label contains control="controlID"
|
||||
* - label has either value="foo" or children
|
||||
* Once a label is found, the search is discontinued, so a control
|
||||
* that has a label child as well as having a label external to
|
||||
* the control that uses the control="controlID" syntax will use
|
||||
* the child label for its Name.
|
||||
*/
|
||||
ENameValueFlag
|
||||
Accessible::GetXULName(nsString& aName)
|
||||
{
|
||||
// CASE #1 (via label attribute) -- great majority of the cases
|
||||
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
|
||||
do_QueryInterface(mContent);
|
||||
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl = do_QueryInterface(aElm);
|
||||
if (labeledEl) {
|
||||
labeledEl->GetLabel(aName);
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl =
|
||||
do_QueryInterface(mContent);
|
||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm);
|
||||
if (itemEl) {
|
||||
itemEl->GetLabel(aName);
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMXULSelectControlElement> select =
|
||||
do_QueryInterface(mContent);
|
||||
nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm);
|
||||
// Use label if this is not a select control element which
|
||||
// uses label attribute to indicate which option is selected
|
||||
if (!select) {
|
||||
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mContent));
|
||||
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm));
|
||||
if (xulEl)
|
||||
xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
|
||||
}
|
||||
|
@ -1111,7 +1092,7 @@ Accessible::GetXULName(nsString& aName)
|
|||
// CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
|
||||
if (aName.IsEmpty()) {
|
||||
Accessible* labelAcc = nullptr;
|
||||
XULLabelIterator iter(Document(), mContent);
|
||||
XULLabelIterator iter(aDocument, aElm);
|
||||
while ((labelAcc = iter.Next())) {
|
||||
nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
|
||||
do_QueryInterface(labelAcc->GetContent());
|
||||
|
@ -1120,30 +1101,27 @@ Accessible::GetXULName(nsString& aName)
|
|||
// If no value attribute, a non-empty label must contain
|
||||
// children that define its text -- possibly using HTML
|
||||
nsTextEquivUtils::
|
||||
AppendTextEquivFromContent(this, labelAcc->GetContent(), &aName);
|
||||
AppendTextEquivFromContent(labelAcc, labelAcc->GetContent(), &aName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aName.CompressWhitespace();
|
||||
if (!aName.IsEmpty())
|
||||
return eNameOK;
|
||||
return;
|
||||
|
||||
// Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
|
||||
nsIContent *bindingParent = mContent->GetBindingParent();
|
||||
nsIContent *parent = bindingParent? bindingParent->GetParent() :
|
||||
mContent->GetParent();
|
||||
nsIContent *bindingParent = aElm->GetBindingParent();
|
||||
nsIContent* parent =
|
||||
bindingParent? bindingParent->GetParent() : aElm->GetParent();
|
||||
while (parent) {
|
||||
if (parent->Tag() == nsGkAtoms::toolbaritem &&
|
||||
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
|
||||
aName.CompressWhitespace();
|
||||
return eNameOK;
|
||||
return;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
||||
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2478,11 +2456,30 @@ Accessible::ARIAName(nsString& aName)
|
|||
ENameValueFlag
|
||||
Accessible::NativeName(nsString& aName)
|
||||
{
|
||||
if (mContent->IsHTML())
|
||||
return GetHTMLName(aName);
|
||||
if (mContent->IsHTML()) {
|
||||
Accessible* label = nullptr;
|
||||
HTMLLabelIterator iter(Document(), this);
|
||||
while ((label = iter.Next())) {
|
||||
nsTextEquivUtils::AppendTextEquivFromContent(this, label->GetContent(),
|
||||
&aName);
|
||||
aName.CompressWhitespace();
|
||||
}
|
||||
|
||||
if (mContent->IsXUL())
|
||||
return GetXULName(aName);
|
||||
if (!aName.IsEmpty())
|
||||
return eNameOK;
|
||||
|
||||
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
||||
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||
}
|
||||
|
||||
if (mContent->IsXUL()) {
|
||||
XULElmName(mDoc, mContent, aName);
|
||||
if (!aName.IsEmpty())
|
||||
return eNameOK;
|
||||
|
||||
nsTextEquivUtils::GetNameFromSubtree(this, aName);
|
||||
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
|
||||
}
|
||||
|
||||
if (mContent->IsSVG()) {
|
||||
// If user agents need to choose among multiple ‘desc’ or ‘title’ elements
|
||||
|
|
|
@ -879,10 +879,10 @@ protected:
|
|||
void ARIAName(nsString& aName);
|
||||
|
||||
/**
|
||||
* Compute the name of HTML/XUL node.
|
||||
* Return the name for XUL element.
|
||||
*/
|
||||
mozilla::a11y::ENameValueFlag GetHTMLName(nsString& aName);
|
||||
mozilla::a11y::ENameValueFlag GetXULName(nsString& aName);
|
||||
static void XULElmName(DocAccessible* aDocument,
|
||||
nsIContent* aElm, nsString& aName);
|
||||
|
||||
// helper method to verify frames
|
||||
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
|
||||
|
|
|
@ -328,16 +328,10 @@ HTMLTextFieldAccessible::NativeName(nsString& aName)
|
|||
if (!aName.IsEmpty())
|
||||
return nameFlag;
|
||||
|
||||
if (mContent->GetBindingParent()) {
|
||||
// XXX: bug 459640
|
||||
// There's a binding parent.
|
||||
// This means we're part of another control, so use parent accessible for name.
|
||||
// This ensures that a textbox inside of a XUL widget gets
|
||||
// an accessible name.
|
||||
Accessible* parent = Parent();
|
||||
if (parent)
|
||||
parent->GetName(aName);
|
||||
}
|
||||
// If part of compound of XUL widget then grab a name from XUL widget element.
|
||||
nsIContent* widgetElm = XULWidgetElm();
|
||||
if (widgetElm)
|
||||
XULElmName(mDoc, widgetElm, aName);
|
||||
|
||||
if (!aName.IsEmpty())
|
||||
return eNameOK;
|
||||
|
@ -369,8 +363,13 @@ void
|
|||
HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
|
||||
{
|
||||
HyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
||||
|
||||
// If part of compound of XUL widget then pick up ARIA stuff from XUL widget
|
||||
// element.
|
||||
nsIContent* widgetElm = XULWidgetElm();
|
||||
if (widgetElm)
|
||||
aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -408,9 +407,8 @@ HTMLTextFieldAccessible::NativeState()
|
|||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
|
||||
return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
|
||||
|
||||
// No parent can mean a fake widget created for XUL textbox. If accessible
|
||||
// is unattached from tree then we don't care.
|
||||
if (mParent && Preferences::GetBool("browser.formfill.enable")) {
|
||||
// Ordinal XUL textboxes don't support autocomplete.
|
||||
if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
|
||||
// Check to see if autocompletion is allowed on this input. We don't expose
|
||||
// it for password fields even though the entire password can be remembered
|
||||
// for a page if the user asks it to be. However, the kind of autocomplete
|
||||
|
|
|
@ -143,6 +143,11 @@ public:
|
|||
protected:
|
||||
// Accessible
|
||||
virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Return a XUL widget element this input is part of.
|
||||
*/
|
||||
nsIContent* XULWidgetElm() const { return mContent->GetBindingParent(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -636,192 +636,3 @@ XULToolbarSeparatorAccessible::NativeState()
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULTextFieldAccessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
XULTextFieldAccessible::
|
||||
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
HyperTextAccessibleWrap(aContent, aDoc)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED2(XULTextFieldAccessible,
|
||||
Accessible,
|
||||
nsIAccessibleText,
|
||||
nsIAccessibleEditableText)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULTextFieldAccessible: nsIAccessible
|
||||
|
||||
void
|
||||
XULTextFieldAccessible::Value(nsString& aValue)
|
||||
{
|
||||
aValue.Truncate();
|
||||
if (NativeRole() == roles::PASSWORD_TEXT) // Don't return password text!
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mContent));
|
||||
if (textBox) {
|
||||
textBox->GetValue(aValue);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
|
||||
if (menuList)
|
||||
menuList->GetLabel(aValue);
|
||||
}
|
||||
|
||||
void
|
||||
XULTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
|
||||
{
|
||||
HyperTextAccessibleWrap::ApplyARIAState(aState);
|
||||
|
||||
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
XULTextFieldAccessible::NativeState()
|
||||
{
|
||||
uint64_t state = HyperTextAccessibleWrap::NativeState();
|
||||
|
||||
nsCOMPtr<nsIContent> inputField(GetInputField());
|
||||
NS_ENSURE_TRUE(inputField, state);
|
||||
|
||||
// Create a temporary accessible from the HTML text field to get
|
||||
// the accessible state from. Doesn't add to cache into document cache.
|
||||
nsRefPtr<HTMLTextFieldAccessible> tempAccessible =
|
||||
new HTMLTextFieldAccessible(inputField, mDoc);
|
||||
if (tempAccessible)
|
||||
return state | tempAccessible->NativeState();
|
||||
return state;
|
||||
}
|
||||
|
||||
role
|
||||
XULTextFieldAccessible::NativeRole()
|
||||
{
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::password, eIgnoreCase))
|
||||
return roles::PASSWORD_TEXT;
|
||||
|
||||
return roles::ENTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only one actions available
|
||||
*/
|
||||
uint8_t
|
||||
XULTextFieldAccessible::ActionCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of our only action
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
XULTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
|
||||
{
|
||||
if (aIndex == eAction_Click) {
|
||||
aName.AssignLiteral("activate");
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the button to do its action
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
XULTextFieldAccessible::DoAction(uint8_t index)
|
||||
{
|
||||
if (index == 0) {
|
||||
nsCOMPtr<nsIDOMXULElement> element(do_QueryInterface(mContent));
|
||||
if (element)
|
||||
{
|
||||
element->Focus();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool
|
||||
XULTextFieldAccessible::CanHaveAnonChildren()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
XULTextFieldAccessible::IsAcceptableChild(Accessible* aPossibleChild) const
|
||||
{
|
||||
// XXX: entry shouldn't contain anything but text leafs. Currently it may
|
||||
// contain a trailing fake HTML br element added for layout needs. We don't
|
||||
// need to expose it since it'd be confusing for AT.
|
||||
return aPossibleChild->IsTextLeaf();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIEditor>
|
||||
XULTextFieldAccessible::GetEditor() const
|
||||
{
|
||||
nsCOMPtr<nsIContent> inputField = GetInputField();
|
||||
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
|
||||
if (!editableElt)
|
||||
return nullptr;
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editableElt->GetEditor(getter_AddRefs(editor));
|
||||
return editor.forget();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULTextFieldAccessible: Accessible protected
|
||||
|
||||
void
|
||||
XULTextFieldAccessible::CacheChildren()
|
||||
{
|
||||
NS_ENSURE_TRUE_VOID(mDoc);
|
||||
// Create child accessibles for native anonymous content of underlying HTML
|
||||
// input element.
|
||||
nsCOMPtr<nsIContent> inputContent(GetInputField());
|
||||
if (!inputContent)
|
||||
return;
|
||||
|
||||
TreeWalker walker(this, inputContent);
|
||||
while (Accessible* child = walker.NextChild())
|
||||
AppendChild(child);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULTextFieldAccessible: HyperTextAccessible protected
|
||||
|
||||
already_AddRefed<nsFrameSelection>
|
||||
XULTextFieldAccessible::FrameSelection() const
|
||||
{
|
||||
nsCOMPtr<nsIContent> inputContent(GetInputField());
|
||||
NS_ASSERTION(inputContent, "No input content");
|
||||
if (!inputContent)
|
||||
return nullptr;
|
||||
|
||||
nsIFrame* frame = inputContent->GetPrimaryFrame();
|
||||
return frame ? frame->GetFrameSelection() : nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XULTextFieldAccessible protected
|
||||
|
||||
already_AddRefed<nsIContent>
|
||||
XULTextFieldAccessible::GetInputField() const
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> inputFieldDOMNode;
|
||||
nsCOMPtr<nsIDOMXULTextBoxElement> textBox = do_QueryInterface(mContent);
|
||||
if (textBox)
|
||||
textBox->GetInputField(getter_AddRefs(inputFieldDOMNode));
|
||||
|
||||
NS_ASSERTION(inputFieldDOMNode, "No input field for XULTextFieldAccessible");
|
||||
|
||||
nsCOMPtr<nsIContent> inputField = do_QueryInterface(inputFieldDOMNode);
|
||||
return inputField.forget();
|
||||
}
|
||||
|
|
|
@ -215,47 +215,6 @@ public:
|
|||
virtual uint64_t NativeState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for XUL textbox element.
|
||||
*/
|
||||
class XULTextFieldAccessible : public HyperTextAccessibleWrap
|
||||
{
|
||||
public:
|
||||
enum { eAction_Click = 0 };
|
||||
|
||||
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIAccessible
|
||||
NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
|
||||
NS_IMETHOD DoAction(uint8_t index);
|
||||
|
||||
// HyperTextAccessible
|
||||
virtual already_AddRefed<nsIEditor> GetEditor() const;
|
||||
|
||||
// Accessible
|
||||
virtual void Value(nsString& aValue);
|
||||
virtual void ApplyARIAState(uint64_t* aState) const;
|
||||
virtual mozilla::a11y::role NativeRole();
|
||||
virtual uint64_t NativeState();
|
||||
virtual bool CanHaveAnonChildren();
|
||||
virtual bool IsAcceptableChild(Accessible* aPossibleChild) const MOZ_OVERRIDE;
|
||||
|
||||
// ActionAccessible
|
||||
virtual uint8_t ActionCount();
|
||||
|
||||
protected:
|
||||
// Accessible
|
||||
virtual void CacheChildren();
|
||||
|
||||
// HyperTextAccessible
|
||||
virtual already_AddRefed<nsFrameSelection> FrameSelection() const;
|
||||
|
||||
// nsXULTextFieldAccessible
|
||||
already_AddRefed<nsIContent> GetInputField() const;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -635,7 +635,7 @@ XULListitemAccessible::NativeName(nsString& aName)
|
|||
}
|
||||
}
|
||||
|
||||
return GetXULName(aName);
|
||||
return Accessible::NativeName(aName);
|
||||
}
|
||||
|
||||
role
|
||||
|
|
|
@ -21,7 +21,6 @@ support-files =
|
|||
states.js
|
||||
table.js
|
||||
value.js
|
||||
testTextboxes.js
|
||||
text.js
|
||||
treeview.css
|
||||
treeview.js
|
||||
|
@ -32,5 +31,3 @@ support-files =
|
|||
[test_nsIAccessibleDocument.html]
|
||||
[test_nsIAccessibleImage.html]
|
||||
[test_OuterDocAccessible.html]
|
||||
[test_textboxes.html]
|
||||
[test_textboxes.xul]
|
||||
|
|
|
@ -91,6 +91,23 @@ function testActions(aArray)
|
|||
gActionsQueue.invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test action names and descriptions.
|
||||
*/
|
||||
function testActionNames(aID, aActions)
|
||||
{
|
||||
var actions = (typeof aActions == "string") ?
|
||||
[ aActions ] : (aActions || []);
|
||||
|
||||
var acc = getAccessible(aID);
|
||||
is(acc.actionCount, actions.length, "Wong number of actions.");
|
||||
for (var i = 0; i < actions.length; i++ ) {
|
||||
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
|
||||
is(acc.getActionDescription(0), gActionDescrMap[actions[i]],
|
||||
"Wrong action description at " + i + "index.");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
|
||||
|
@ -151,3 +168,20 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj)
|
|||
aActionObj.checkOnClickEvent(aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
var gActionDescrMap =
|
||||
{
|
||||
jump: "Jump",
|
||||
press: "Press",
|
||||
check: "Check",
|
||||
uncheck: "Uncheck",
|
||||
select: "Select",
|
||||
open: "Open",
|
||||
close: "Close",
|
||||
switch: "Switch",
|
||||
click: "Click",
|
||||
collapse: "Collapse",
|
||||
expand: "Expand",
|
||||
activate: "Activate",
|
||||
cycle: "Cycle"
|
||||
};
|
||||
|
|
|
@ -328,6 +328,14 @@ function getApplicationAccessible()
|
|||
QueryInterface(nsIAccessibleApplication);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of accessible tree testing, doesn't fail if tree is not complete.
|
||||
*/
|
||||
function testElm(aID, aTreeObj)
|
||||
{
|
||||
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flags used for testAccessibleTree
|
||||
*/
|
||||
|
@ -370,11 +378,7 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
|
|||
|
||||
switch (prop) {
|
||||
case "actions": {
|
||||
var actions = (typeof accTree.actions == "string") ?
|
||||
[ accTree.actions ] : (accTree.actions || []);
|
||||
is(acc.actionCount, actions.length, "Wong number of actions.");
|
||||
for (var i = 0; i < actions.length; i++ )
|
||||
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
|
||||
testActionNames(acc, accTree.actions);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../actions.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
|
@ -22,11 +24,6 @@
|
|||
src="../name.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
function testElm(aID, aTreeObj)
|
||||
{
|
||||
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
function doTests()
|
||||
{
|
||||
|
||||
if (MAC) {
|
||||
todo(false, "Make these tests pass on OSX (bug 650294)");
|
||||
SimpleTest.finish();
|
||||
|
@ -38,10 +37,11 @@
|
|||
gQueue = new eventQueue(EVENT_TEXT_CARET_MOVED);
|
||||
|
||||
var id = "textbox";
|
||||
gQueue.push(new synthFocus(id, new caretMoveChecker(5, id)));
|
||||
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, id)));
|
||||
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, id)));
|
||||
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, id)));
|
||||
var input = getNode(id).inputField;
|
||||
gQueue.push(new synthFocus(id, new caretMoveChecker(5, input)));
|
||||
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, input)));
|
||||
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, input)));
|
||||
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, input)));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
|
|
@ -38,8 +38,10 @@
|
|||
// Test focus events.
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new synthFocus("textbox"));
|
||||
gQueue.push(new synthFocus("textbox_multiline"));
|
||||
gQueue.push(new synthFocus("textbox",
|
||||
new focusChecker(getNode("textbox").inputField)));
|
||||
gQueue.push(new synthFocus("textbox_multiline",
|
||||
new focusChecker(getNode("textbox_multiline").inputField)));
|
||||
gQueue.push(new synthFocus("scale"));
|
||||
gQueue.push(new synthFocusOnFrame("editabledoc"));
|
||||
gQueue.push(new synthFocus("radioclothes",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
//gA11yEventDumpToConsole = true; // debug stuff
|
||||
gA11yEventDumpToConsole = true; // debug stuff
|
||||
|
||||
var gQueue = null;
|
||||
function doTests()
|
||||
|
|
|
@ -36,10 +36,11 @@
|
|||
// Test focus events.
|
||||
gQueue = new eventQueue();
|
||||
|
||||
var textbox = getNode("textbox").inputField;
|
||||
gQueue.push(new synthClick("tab1", new focusChecker("tab1")));
|
||||
gQueue.push(new synthTab("tab1", new focusChecker("checkbox1")));
|
||||
gQueue.push(new synthKey("tab1", "VK_TAB", { ctrlKey: true },
|
||||
new focusChecker("textbox")));
|
||||
new focusChecker(textbox)));
|
||||
gQueue.push(new synthKey("tab2", "VK_TAB", { ctrlKey: true },
|
||||
new focusChecker("tab3")));
|
||||
gQueue.push(new synthKey("tab3", "VK_TAB", { ctrlKey: true },
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// aria-labelledby
|
||||
|
||||
|
||||
// Single relation. The value of 'aria-labelledby' contains the ID of
|
||||
// an element. Gets the name from text node of that element.
|
||||
testName("btn_labelledby_text", "text");
|
||||
|
|
|
@ -18,11 +18,16 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function getInput(aID)
|
||||
{
|
||||
return getNode(aID).inputField;
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Ordinary textbox
|
||||
testStates("textbox",
|
||||
testStates(getInput("textbox"),
|
||||
STATE_FOCUSABLE,
|
||||
EXT_STATE_EDITABLE,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
@ -31,7 +36,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Password textbox
|
||||
testStates("password",
|
||||
testStates(getInput("password"),
|
||||
STATE_FOCUSABLE | STATE_PROTECTED,
|
||||
EXT_STATE_EDITABLE,
|
||||
STATE_UNAVAILABLE,
|
||||
|
@ -40,7 +45,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Textarea
|
||||
testStates("textarea",
|
||||
testStates(getInput("textarea"),
|
||||
STATE_FOCUSABLE,
|
||||
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
@ -49,7 +54,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Readonly textbox
|
||||
testStates("readonly_textbox",
|
||||
testStates(getInput("readonly_textbox"),
|
||||
STATE_FOCUSABLE | STATE_READONLY,
|
||||
EXT_STATE_EDITABLE,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
@ -58,7 +63,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Disabled textbox
|
||||
testStates("disabled_textbox",
|
||||
testStates(getInput("disabled_textbox"),
|
||||
STATE_UNAVAILABLE,
|
||||
EXT_STATE_EDITABLE,
|
||||
STATE_FOCUSABLE | STATE_PROTECTED,
|
||||
|
@ -67,7 +72,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Readonly textarea
|
||||
testStates("readonly_textarea",
|
||||
testStates(getInput("readonly_textarea"),
|
||||
STATE_FOCUSABLE | STATE_READONLY,
|
||||
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
@ -76,7 +81,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Disabled textarea
|
||||
testStates("disabled_textarea",
|
||||
testStates(getInput("disabled_textarea"),
|
||||
STATE_UNAVAILABLE,
|
||||
EXT_STATE_EDITABLE| EXT_STATE_MULTI_LINE,
|
||||
STATE_PROTECTED | STATE_FOCUSABLE,
|
||||
|
@ -86,7 +91,7 @@
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
// Search textbox without search button, searches as you type and filters
|
||||
// a separate control.
|
||||
testStates("searchbox",
|
||||
testStates(getInput("searchbox"),
|
||||
STATE_FOCUSABLE,
|
||||
EXT_STATE_EDITABLE | EXT_STATE_SUPPORTS_AUTOCOMPLETION,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
@ -95,7 +100,7 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Search textbox with search button, does not support autoCompletion.
|
||||
testStates("searchfield",
|
||||
testStates(getInput("searchfield"),
|
||||
STATE_FOCUSABLE,
|
||||
EXT_STATE_EDITABLE,
|
||||
STATE_PROTECTED | STATE_UNAVAILABLE,
|
||||
|
|
|
@ -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
|
||||
|
||||
testTextAtOffset([ "tbox1" ], BOUNDARY_LINE_START,
|
||||
testTextAtOffset([ getNode("tbox1").inputField ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 4, "test", 0, 4 ] ]);
|
||||
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -23,64 +23,68 @@
|
|||
|
||||
function doTest()
|
||||
{
|
||||
////////////////////
|
||||
// textbox
|
||||
////////////////////
|
||||
var accTree = {
|
||||
role: ROLE_ENTRY,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// textboxes
|
||||
|
||||
var accTree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [ { TEXT_LEAF: [] } ] },
|
||||
{ MENUPOPUP: [] }
|
||||
] };
|
||||
|
||||
// default textbox
|
||||
testAccessibleTree("txc1", accTree);
|
||||
testAccessibleTree("txc", accTree);
|
||||
|
||||
// number textbox
|
||||
testAccessibleTree("txc2", accTree);
|
||||
// multiline
|
||||
testAccessibleTree("txc_multiline", accTree);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// search textbox
|
||||
testAccessibleTree("txc3", accTree);
|
||||
|
||||
// timed textbox
|
||||
testAccessibleTree("txc4_deprecated", accTree);
|
||||
if (MAC) {
|
||||
accTree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [ { TEXT_LEAF: [] } ] },
|
||||
{ MENUPOPUP: [] }
|
||||
] };
|
||||
} else {
|
||||
accTree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [ { TEXT_LEAF: [] } ] },
|
||||
{ PUSHBUTTON: [] },
|
||||
{ MENUPOPUP: [] }
|
||||
] };
|
||||
}
|
||||
|
||||
////////////////////
|
||||
testAccessibleTree("txc_search", accTree);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// number textbox
|
||||
|
||||
accTree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [ { TEXT_LEAF: [] } ] },
|
||||
{ MENUPOPUP: [] },
|
||||
{ PUSHBUTTON: [] },
|
||||
{ PUSHBUTTON: [] }
|
||||
] };
|
||||
|
||||
testAccessibleTree("txc_number", accTree);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// password textbox
|
||||
////////////////////
|
||||
accTree = {
|
||||
role: ROLE_PASSWORD_TEXT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
testAccessibleTree("txc5", accTree);
|
||||
accTree =
|
||||
{ SECTION: [
|
||||
{ PASSWORD_TEXT: [ { TEXT_LEAF: [] } ] },
|
||||
{ MENUPOPUP: [] }
|
||||
] };
|
||||
|
||||
////////////////////
|
||||
// multiline textbox
|
||||
////////////////////
|
||||
accTree = {
|
||||
role: ROLE_ENTRY,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree("txc_password", accTree);
|
||||
|
||||
testAccessibleTree("txc6", accTree);
|
||||
|
||||
////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// autocomplete textbox
|
||||
////////////////////
|
||||
|
||||
accTree = {
|
||||
// textbox
|
||||
role: ROLE_AUTOCOMPLETE,
|
||||
|
@ -104,14 +108,14 @@
|
|||
]
|
||||
};
|
||||
|
||||
function test_txc7() {
|
||||
testAccessibleTree("txc7", accTree);
|
||||
function test_AutocompleteControl() {
|
||||
testAccessibleTree("txc_autocomplete", accTree);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// XPFE and Toolkit autocomplete widgets differ.
|
||||
var txc7 = document.getElementById("txc7");
|
||||
if ("clearResults" in txc7) {
|
||||
var txc = document.getElementById("txc_autocomplete");
|
||||
if ("clearResults" in txc) {
|
||||
SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget.");
|
||||
|
||||
// Popup is always created. (See code below.)
|
||||
|
@ -141,14 +145,14 @@
|
|||
]
|
||||
}
|
||||
);
|
||||
test_txc7();
|
||||
test_AutocompleteControl();
|
||||
|
||||
} else {
|
||||
SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
|
||||
|
||||
// Dumb access to trigger popup lazy creation.
|
||||
waitForEvent(EVENT_REORDER, txc7, test_txc7);
|
||||
txc7.popup;
|
||||
waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
|
||||
txc.popup;
|
||||
|
||||
accTree.children.push(
|
||||
{
|
||||
|
@ -189,15 +193,12 @@
|
|||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<textbox id="txc1" value="hello"/>
|
||||
<textbox id="txc2" type="number" value="44"/>
|
||||
<textbox id="txc3" type="search" value="hello"/>
|
||||
<!-- This textbox triggers "Warning: Timed textboxes are deprecated. Consider using type="search" instead.".
|
||||
Yet let's test it too as long as it's (still) supported. -->
|
||||
<textbox id="txc4_deprecated" type="timed" value="hello"/>
|
||||
<textbox id="txc5" type="password" value="hello"/>
|
||||
<textbox id="txc6" multiline="true" value="hello"/>
|
||||
<textbox id="txc7" type="autocomplete" value="hello"/>
|
||||
<textbox id="txc" value="hello"/>
|
||||
<textbox id="txc_search" type="search" value="hello"/>
|
||||
<textbox id="txc_number" type="number" value="44"/>
|
||||
<textbox id="txc_password" type="password" value="hello"/>
|
||||
<textbox id="txc_multiline" multiline="true" value="hello"/>
|
||||
<textbox id="txc_autocomplete" type="autocomplete" value="hello"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"use strict"
|
||||
|
||||
function debug(str) {
|
||||
//dump("-*- ContentPermissionPrompt: " + s + "\n");
|
||||
//dump("-*- ContentPermissionPrompt: " + str + "\n");
|
||||
}
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
|
@ -13,11 +13,14 @@ const Cr = Components.results;
|
|||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
|
||||
const PROMPT_FOR_UNKNOWN = ["geolocation", "desktop-notification",
|
||||
"audio-capture"];
|
||||
const PROMPT_FOR_UNKNOWN = ["audio-capture",
|
||||
"desktop-notification",
|
||||
"geolocation",
|
||||
"video-capture"];
|
||||
// Due to privary issue, permission requests like GetUserMedia should prompt
|
||||
// every time instead of providing session persistence.
|
||||
const PERMISSION_NO_SESSION = ["audio-capture"];
|
||||
const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
|
||||
const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
@ -41,7 +44,21 @@ XPCOMUtils.defineLazyServiceGetter(this,
|
|||
"@mozilla.org/telephony/audiomanager;1",
|
||||
"nsIAudioManager");
|
||||
|
||||
function rememberPermission(aPermission, aPrincipal, aSession)
|
||||
/**
|
||||
* aTypesInfo is an array of {permission, access, action, deny} which keeps
|
||||
* the information of each permission. This arrary is initialized in
|
||||
* ContentPermissionPrompt.prompt and used among functions.
|
||||
*
|
||||
* aTypesInfo[].permission : permission name
|
||||
* aTypesInfo[].access : permission name + request.access
|
||||
* aTypesInfo[].action : the default action of this permission
|
||||
* aTypesInfo[].deny : true if security manager denied this app's origin
|
||||
* principal.
|
||||
* Note:
|
||||
* aTypesInfo[].permission will be sent to prompt only when
|
||||
* aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false.
|
||||
*/
|
||||
function rememberPermission(aTypesInfo, aPrincipal, aSession)
|
||||
{
|
||||
function convertPermToAllow(aPerm, aPrincipal)
|
||||
{
|
||||
|
@ -49,12 +66,13 @@ function rememberPermission(aPermission, aPrincipal, aSession)
|
|||
permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm);
|
||||
if (type == Ci.nsIPermissionManager.PROMPT_ACTION ||
|
||||
(type == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
|
||||
PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) {
|
||||
PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) {
|
||||
debug("add " + aPerm + " to permission manager with ALLOW_ACTION");
|
||||
if (!aSession) {
|
||||
permissionManager.addFromPrincipal(aPrincipal,
|
||||
aPerm,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
} else if (PERMISSION_NO_SESSION.indexOf(aPermission) < 0) {
|
||||
} else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
|
||||
permissionManager.addFromPrincipal(aPrincipal,
|
||||
aPerm,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
|
@ -63,14 +81,18 @@ function rememberPermission(aPermission, aPrincipal, aSession)
|
|||
}
|
||||
}
|
||||
|
||||
// Expand the permission to see if we have multiple access properties to convert
|
||||
let access = PermissionsTable[aPermission].access;
|
||||
if (access) {
|
||||
for (let idx in access) {
|
||||
convertPermToAllow(aPermission + "-" + access[idx], aPrincipal);
|
||||
for (let i in aTypesInfo) {
|
||||
// Expand the permission to see if we have multiple access properties
|
||||
// to convert
|
||||
let perm = aTypesInfo[i].permission;
|
||||
let access = PermissionsTable[perm].access;
|
||||
if (access) {
|
||||
for (let idx in access) {
|
||||
convertPermToAllow(perm + "-" + access[idx], aPrincipal);
|
||||
}
|
||||
} else {
|
||||
convertPermToAllow(perm, aPrincipal);
|
||||
}
|
||||
} else {
|
||||
convertPermToAllow(aPermission, aPrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,23 +100,66 @@ function ContentPermissionPrompt() {}
|
|||
|
||||
ContentPermissionPrompt.prototype = {
|
||||
|
||||
handleExistingPermission: function handleExistingPermission(request) {
|
||||
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
|
||||
request.type;
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, access);
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
handleExistingPermission: function handleExistingPermission(request,
|
||||
typesInfo) {
|
||||
typesInfo.forEach(function(type) {
|
||||
type.action =
|
||||
Services.perms.testExactPermissionFromPrincipal(request.principal,
|
||||
type.access);
|
||||
if (type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
|
||||
PROMPT_FOR_UNKNOWN.indexOf(type.access) >= 0) {
|
||||
type.action = Ci.nsIPermissionManager.PROMPT_ACTION;
|
||||
}
|
||||
});
|
||||
|
||||
// If all permissions are allowed already, call allow() without prompting.
|
||||
let checkAllowPermission = function(type) {
|
||||
if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (typesInfo.every(checkAllowPermission)) {
|
||||
debug("all permission requests are allowed");
|
||||
request.allow();
|
||||
return true;
|
||||
}
|
||||
if (result == Ci.nsIPermissionManager.DENY_ACTION ||
|
||||
result == Ci.nsIPermissionManager.UNKNOWN_ACTION && PROMPT_FOR_UNKNOWN.indexOf(access) < 0) {
|
||||
|
||||
// If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel()
|
||||
// without prompting.
|
||||
let checkDenyPermission = function(type) {
|
||||
if (type.action == Ci.nsIPermissionManager.DENY_ACTION ||
|
||||
type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (typesInfo.every(checkDenyPermission)) {
|
||||
debug("all permission requests are denied");
|
||||
request.cancel();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByApp: function handledByApp(request) {
|
||||
// multiple requests should be audio and video
|
||||
checkMultipleRequest: function checkMultipleRequest(typesInfo) {
|
||||
if (typesInfo.length == 1) {
|
||||
return true;
|
||||
} else if (typesInfo.length > 1) {
|
||||
let checkIfAllowMultiRequest = function(type) {
|
||||
return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
|
||||
}
|
||||
if (typesInfo.every(checkIfAllowMultiRequest)) {
|
||||
debug("legal multiple requests");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByApp: function handledByApp(request, typesInfo) {
|
||||
if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
|
||||
request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
|
||||
// This should not really happen
|
||||
|
@ -106,49 +171,94 @@ ContentPermissionPrompt.prototype = {
|
|||
.getService(Ci.nsIAppsService);
|
||||
let app = appsService.getAppByLocalId(request.principal.appId);
|
||||
|
||||
let url = Services.io.newURI(app.origin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(url, request.principal.appId,
|
||||
/*mozbrowser*/false);
|
||||
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
|
||||
request.type;
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(principal, access);
|
||||
// Check each permission if it's denied by permission manager with app's
|
||||
// URL.
|
||||
let notDenyAppPrincipal = function(type) {
|
||||
let url = Services.io.newURI(app.origin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(url,
|
||||
request.principal.appId,
|
||||
/*mozbrowser*/false);
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(principal,
|
||||
type.access);
|
||||
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
|
||||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
|
||||
return false;
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
|
||||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
|
||||
type.deny = false;
|
||||
}
|
||||
return !type.deny;
|
||||
}
|
||||
if (typesInfo.filter(notDenyAppPrincipal).length === 0) {
|
||||
request.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
request.cancel();
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
handledByPermissionType: function handledByPermissionType(request) {
|
||||
return permissionSpecificChecker.hasOwnProperty(request.type)
|
||||
? permissionSpecificChecker[request.type](request)
|
||||
: false;
|
||||
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
|
||||
for (let i in typesInfo) {
|
||||
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
|
||||
permissionSpecificChecker[typesInfo[i].permission](request)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_id: 0,
|
||||
prompt: function(request) {
|
||||
if (secMan.isSystemPrincipal(request.principal)) {
|
||||
request.allow();
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.handledByApp(request) ||
|
||||
this.handledByPermissionType(request)) {
|
||||
// Initialize the typesInfo and set the default value.
|
||||
let typesInfo = [];
|
||||
let perms = request.types.QueryInterface(Ci.nsIArray);
|
||||
for (let idx = 0; idx < perms.length; idx++) {
|
||||
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
|
||||
let tmp = {
|
||||
permission: perm.type,
|
||||
access: (perm.access && perm.access !== "unused") ?
|
||||
perm.type + "-" + perm.access : perm.type,
|
||||
deny: true,
|
||||
action: Ci.nsIPermissionManager.UNKNOWN_ACTION
|
||||
};
|
||||
typesInfo.push(tmp);
|
||||
}
|
||||
if (typesInfo.length == 0) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.checkMultipleRequest(typesInfo)) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.handledByApp(request, typesInfo) ||
|
||||
this.handledByPermissionType(request, typesInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// returns true if the request was handled
|
||||
if (this.handleExistingPermission(request))
|
||||
if (this.handleExistingPermission(request, typesInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prompt PROMPT_ACTION request only.
|
||||
typesInfo.forEach(function(aType, aIndex) {
|
||||
if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) {
|
||||
typesInfo.splice(aIndex);
|
||||
}
|
||||
});
|
||||
|
||||
let frame = request.element;
|
||||
let requestId = this._id++;
|
||||
|
||||
if (!frame) {
|
||||
this.delegatePrompt(request, requestId);
|
||||
this.delegatePrompt(request, requestId, typesInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -163,7 +273,7 @@ ContentPermissionPrompt.prototype = {
|
|||
if (evt.detail.visible === true)
|
||||
return;
|
||||
|
||||
self.cancelPrompt(request, requestId);
|
||||
self.cancelPrompt(request, requestId, typesInfo);
|
||||
cancelRequest();
|
||||
}
|
||||
|
||||
|
@ -180,7 +290,7 @@ ContentPermissionPrompt.prototype = {
|
|||
// away but the request is still here.
|
||||
frame.addEventListener("mozbrowservisibilitychange", onVisibilityChange);
|
||||
|
||||
self.delegatePrompt(request, requestId, function onCallback() {
|
||||
self.delegatePrompt(request, requestId, typesInfo, function onCallback() {
|
||||
frame.removeEventListener("mozbrowservisibilitychange", onVisibilityChange);
|
||||
});
|
||||
};
|
||||
|
@ -191,22 +301,17 @@ ContentPermissionPrompt.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
cancelPrompt: function(request, requestId) {
|
||||
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId);
|
||||
cancelPrompt: function(request, requestId, typesInfo) {
|
||||
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId,
|
||||
typesInfo);
|
||||
},
|
||||
|
||||
delegatePrompt: function(request, requestId, callback) {
|
||||
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
|
||||
request.type;
|
||||
let principal = request.principal;
|
||||
delegatePrompt: function(request, requestId, typesInfo, callback) {
|
||||
|
||||
this._permission = access;
|
||||
this._uri = principal.URI.spec;
|
||||
this._origin = principal.origin;
|
||||
|
||||
this.sendToBrowserWindow("permission-prompt", request, requestId, function(type, remember) {
|
||||
this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo,
|
||||
function(type, remember) {
|
||||
if (type == "permission-allow") {
|
||||
rememberPermission(request.type, principal, !remember);
|
||||
rememberPermission(typesInfo, request.principal, !remember);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
@ -214,14 +319,20 @@ ContentPermissionPrompt.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (remember) {
|
||||
Services.perms.addFromPrincipal(principal, access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION);
|
||||
} else {
|
||||
Services.perms.addFromPrincipal(principal, access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION,
|
||||
Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
|
||||
let addDenyPermission = function(type) {
|
||||
debug("add " + type.permission +
|
||||
" to permission manager with DENY_ACTION");
|
||||
if (remember) {
|
||||
Services.perms.addFromPrincipal(request.principal, type.access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION);
|
||||
} else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
|
||||
Services.perms.addFromPrincipal(request.principal, type.access,
|
||||
Ci.nsIPermissionManager.DENY_ACTION,
|
||||
Ci.nsIPermissionManager.EXPIRE_SESSION,
|
||||
0);
|
||||
}
|
||||
}
|
||||
typesInfo.forEach(addDenyPermission);
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
|
@ -230,7 +341,7 @@ ContentPermissionPrompt.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
sendToBrowserWindow: function(type, request, requestId, callback) {
|
||||
sendToBrowserWindow: function(type, request, requestId, typesInfo, callback) {
|
||||
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let content = browser.getContentWindow();
|
||||
if (!content)
|
||||
|
@ -253,10 +364,15 @@ ContentPermissionPrompt.prototype = {
|
|||
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
|
||||
? true
|
||||
: request.remember;
|
||||
let permissions = {};
|
||||
for (let i in typesInfo) {
|
||||
debug("prompt " + typesInfo[i].permission);
|
||||
permissions[typesInfo[i].permission] = [];
|
||||
}
|
||||
|
||||
let details = {
|
||||
type: type,
|
||||
permission: request.type,
|
||||
permissions: permissions,
|
||||
id: requestId,
|
||||
origin: principal.origin,
|
||||
isApp: isApp,
|
||||
|
@ -289,6 +405,5 @@ ContentPermissionPrompt.prototype = {
|
|||
};
|
||||
})();
|
||||
|
||||
|
||||
//module initialization
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "961def304c067c112f9f3c149431dba70887c5e0",
|
||||
"revision": "7343851c97c278a338434d2632098a263e19bbb6",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -56,7 +56,9 @@ MOZ_TOOLKIT_SEARCH=
|
|||
MOZ_PLACES=
|
||||
MOZ_B2G=1
|
||||
|
||||
#MOZ_NUWA_PROCESS=1
|
||||
if test "$OS_TARGET" = "Android"; then
|
||||
MOZ_NUWA_PROCESS=1
|
||||
fi
|
||||
MOZ_FOLD_LIBS=1
|
||||
|
||||
MOZ_JSDOWNLOADS=1
|
||||
|
|
|
@ -2030,13 +2030,21 @@ ContentPermissionPrompt.prototype = {
|
|||
|
||||
prompt: function CPP_prompt(request) {
|
||||
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
|
||||
|
||||
const kFeatureKeys = { "geolocation" : "geo",
|
||||
"desktop-notification" : "desktop-notification",
|
||||
"pointerLock" : "pointerLock",
|
||||
};
|
||||
|
||||
// Make sure that we support the request.
|
||||
if (!(request.type in kFeatureKeys)) {
|
||||
if (!(perm.type in kFeatureKeys)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2048,7 +2056,7 @@ ContentPermissionPrompt.prototype = {
|
|||
return;
|
||||
|
||||
var autoAllow = false;
|
||||
var permissionKey = kFeatureKeys[request.type];
|
||||
var permissionKey = kFeatureKeys[perm.type];
|
||||
var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey);
|
||||
|
||||
if (result == Ci.nsIPermissionManager.DENY_ACTION) {
|
||||
|
@ -2059,7 +2067,7 @@ ContentPermissionPrompt.prototype = {
|
|||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
autoAllow = true;
|
||||
// For pointerLock, we still want to show a warning prompt.
|
||||
if (request.type != "pointerLock") {
|
||||
if (perm.type != "pointerLock") {
|
||||
request.allow();
|
||||
return;
|
||||
}
|
||||
|
@ -2073,7 +2081,7 @@ ContentPermissionPrompt.prototype = {
|
|||
return;
|
||||
|
||||
// Show the prompt.
|
||||
switch (request.type) {
|
||||
switch (perm.type) {
|
||||
case "geolocation":
|
||||
this._promptGeo(request);
|
||||
break;
|
||||
|
|
|
@ -44,6 +44,8 @@ let IndexedDB = {
|
|||
}
|
||||
|
||||
let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt);
|
||||
let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
types.appendElement({type: type, access: "unused"}, false);
|
||||
|
||||
// If the user waits a long time before responding, we default to UNKNOWN_ACTION.
|
||||
let timeoutId = setTimeout(function() {
|
||||
|
@ -60,7 +62,7 @@ let IndexedDB = {
|
|||
}
|
||||
|
||||
prompt.prompt({
|
||||
type: type,
|
||||
types: types,
|
||||
uri: Services.io.newURI(payload.location, null, null),
|
||||
window: null,
|
||||
element: aMessage.target,
|
||||
|
|
|
@ -56,8 +56,8 @@ ContentPermissionPrompt.prototype = {
|
|||
return chromeWin.Browser.getNotificationBox(request.element);
|
||||
},
|
||||
|
||||
handleExistingPermission: function handleExistingPermission(request) {
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
|
||||
handleExistingPermission: function handleExistingPermission(request, type) {
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
request.allow();
|
||||
return true;
|
||||
|
@ -70,20 +70,28 @@ ContentPermissionPrompt.prototype = {
|
|||
},
|
||||
|
||||
prompt: function(request) {
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
|
||||
|
||||
// returns true if the request was handled
|
||||
if (this.handleExistingPermission(request))
|
||||
if (this.handleExistingPermission(request, perm.type))
|
||||
return;
|
||||
|
||||
let pm = Services.perms;
|
||||
let notificationBox = this.getNotificationBoxForRequest(request);
|
||||
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
let notification = notificationBox.getNotificationWithValue(request.type);
|
||||
let notification = notificationBox.getNotificationWithValue(perm.type);
|
||||
if (notification)
|
||||
return;
|
||||
|
||||
let entityName = kEntities[request.type];
|
||||
let icon = kIcons[request.type] || "";
|
||||
let entityName = kEntities[perm.type];
|
||||
let icon = kIcons[perm.type] || "";
|
||||
|
||||
let buttons = [{
|
||||
label: browserBundle.GetStringFromName(entityName + ".allow"),
|
||||
|
@ -96,7 +104,7 @@ ContentPermissionPrompt.prototype = {
|
|||
label: browserBundle.GetStringFromName("contentPermissions.alwaysForSite"),
|
||||
accessKey: "",
|
||||
callback: function(notification) {
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
request.allow();
|
||||
}
|
||||
},
|
||||
|
@ -104,7 +112,7 @@ ContentPermissionPrompt.prototype = {
|
|||
label: browserBundle.GetStringFromName("contentPermissions.neverForSite"),
|
||||
accessKey: "",
|
||||
callback: function(notification) {
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
request.cancel();
|
||||
}
|
||||
}];
|
||||
|
@ -112,12 +120,12 @@ ContentPermissionPrompt.prototype = {
|
|||
let message = browserBundle.formatStringFromName(entityName + ".wantsTo",
|
||||
[request.principal.URI.host], 1);
|
||||
let newBar = notificationBox.appendNotification(message,
|
||||
request.type,
|
||||
perm.type,
|
||||
icon,
|
||||
notificationBox.PRIORITY_WARNING_MEDIUM,
|
||||
buttons);
|
||||
|
||||
if (request.type == "geolocation") {
|
||||
if (perm.type == "geolocation") {
|
||||
// Add the "learn more" link.
|
||||
let link = newBar.ownerDocument.createElement("label");
|
||||
link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore"));
|
||||
|
|
|
@ -217,6 +217,8 @@
|
|||
#include "mozilla/dom/XPathEvaluator.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsIStructuredCloneContainer.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -10729,17 +10731,11 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest,
|
|||
nsIContentPermissionRequest)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetType(nsACString& aType)
|
||||
nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
aType = "pointerLock";
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess)
|
||||
{
|
||||
aAccess = "unused";
|
||||
return NS_OK;
|
||||
return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef MEDIAENGINE_H_
|
||||
#define MEDIAENGINE_H_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
|
@ -35,7 +36,7 @@ enum {
|
|||
kAudioTrack = 2
|
||||
};
|
||||
|
||||
class MediaEngine
|
||||
class MediaEngine : public RefCounted<MediaEngine>
|
||||
{
|
||||
public:
|
||||
virtual ~MediaEngine() {}
|
||||
|
|
|
@ -101,7 +101,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
|
|||
// We've already seen this device, just append.
|
||||
aVSources->AppendElement(vSource.get());
|
||||
} else {
|
||||
vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i, mWindowId);
|
||||
vSource = new MediaEngineWebRTCVideoSource(mCameraManager, i);
|
||||
mVideoSources.Put(uuid, vSource); // Hashtable takes ownership.
|
||||
aVSources->AppendElement(vSource);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "ImageContainer.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "prprf.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#endif
|
||||
|
||||
#include "NullTransport.h"
|
||||
|
@ -73,7 +74,7 @@ class GetCameraNameRunnable;
|
|||
* mSources, mImageContainer, mSources, mState, mImage, mLastCapture
|
||||
*
|
||||
* MainThread:
|
||||
* mDOMCameraControl, mCaptureIndex, mCameraThread, mWindowId, mCameraManager,
|
||||
* mDOMCameraControl, mCaptureIndex, mCameraThread, mCameraManager,
|
||||
* mNativeCameraControl, mPreviewStream, mState, mLastCapture, mWidth, mHeight
|
||||
*
|
||||
* Where mWidth, mHeight, mImage are protected by mMonitor
|
||||
|
@ -96,11 +97,10 @@ class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource
|
|||
public:
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
MediaEngineWebRTCVideoSource(nsDOMCameraManager* aCameraManager,
|
||||
int aIndex, uint64_t aWindowId)
|
||||
int aIndex)
|
||||
: mCameraManager(aCameraManager)
|
||||
, mNativeCameraControl(nullptr)
|
||||
, mPreviewStream(nullptr)
|
||||
, mWindowId(aWindowId)
|
||||
, mCallbackMonitor("WebRTCCamera.CallbackMonitor")
|
||||
, mCaptureIndex(aIndex)
|
||||
, mMonitor("WebRTCCamera.Monitor")
|
||||
|
@ -223,7 +223,6 @@ private:
|
|||
nsRefPtr<nsDOMCameraControl> mDOMCameraControl;
|
||||
nsRefPtr<nsGonkCameraControl> mNativeCameraControl;
|
||||
nsRefPtr<DOMCameraPreview> mPreviewStream;
|
||||
uint64_t mWindowId;
|
||||
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
|
||||
nsRefPtr<nsIThread> mCameraThread;
|
||||
nsRefPtr<nsIDOMFile> mLastCapture;
|
||||
|
@ -352,15 +351,14 @@ class MediaEngineWebRTC : public MediaEngine
|
|||
{
|
||||
public:
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
MediaEngineWebRTC(nsDOMCameraManager* aCameraManager, uint64_t aWindowId)
|
||||
MediaEngineWebRTC(nsDOMCameraManager* aCameraManager)
|
||||
: mMutex("mozilla::MediaEngineWebRTC")
|
||||
, mVideoEngine(nullptr)
|
||||
, mVoiceEngine(nullptr)
|
||||
, mVideoEngineInit(false)
|
||||
, mAudioEngineInit(false)
|
||||
, mCameraManager(aCameraManager)
|
||||
, mWindowId(aWindowId)
|
||||
, mHasTabVideoSource(false)
|
||||
, mCameraManager(aCameraManager)
|
||||
{
|
||||
AsyncLatencyLogger::Get(true)->AddRef();
|
||||
mLoadMonitor = new LoadMonitor();
|
||||
|
@ -401,6 +399,8 @@ private:
|
|||
nsRefPtrHashtable<nsStringHashKey, MediaEngineWebRTCAudioSource > mAudioSources;
|
||||
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
// XXX Should use nsMainThreadPtrHandle/etc
|
||||
|
||||
// MediaEngine hold this DOM object, and the MediaEngine is hold by Navigator
|
||||
// Their life time is always much longer than this object. Use a raw-pointer
|
||||
// here should be safe.
|
||||
|
@ -409,7 +409,6 @@ private:
|
|||
// avoid any bad thing do to addref/release DOM-object on other thread, we use
|
||||
// raw-pointer for now.
|
||||
nsDOMCameraManager* mCameraManager;
|
||||
uint64_t mWindowId;
|
||||
#endif
|
||||
|
||||
nsRefPtr<LoadMonitor> mLoadMonitor;
|
||||
|
|
|
@ -312,7 +312,6 @@ nsresult
|
|||
MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
{
|
||||
LOG((__FUNCTION__));
|
||||
int error = 0;
|
||||
if (!mInitDone || !aStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -341,7 +340,7 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
|
|||
}
|
||||
#else
|
||||
mState = kStarted;
|
||||
error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
|
||||
int error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this);
|
||||
if (error == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -492,12 +491,9 @@ void
|
|||
MediaEngineWebRTCVideoSource::AllocImpl() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mDOMCameraControl = new nsDOMCameraControl(mCaptureIndex,
|
||||
mCameraThread,
|
||||
this,
|
||||
this,
|
||||
nsGlobalWindow::GetInnerWindowWithId(mWindowId));
|
||||
mCameraManager->Register(mDOMCameraControl);
|
||||
ErrorResult rv;
|
||||
mDOMCameraControl = mCameraManager->GetCameraControl(mCaptureIndex,
|
||||
this, this, rv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -506,6 +502,7 @@ MediaEngineWebRTCVideoSource::DeallocImpl() {
|
|||
|
||||
mNativeCameraControl->ReleaseHardware(this, this);
|
||||
mNativeCameraControl = nullptr;
|
||||
mDOMCameraControl = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -323,6 +323,11 @@ this.PermissionsTable = { geolocation: {
|
|||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"video-capture": {
|
||||
app: PROMPT_ACTION,
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: PROMPT_ACTION
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,20 +6,156 @@
|
|||
#include "GonkPermission.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#endif // MOZ_WIDGET_GONK
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/PContentPermission.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
using mozilla::unused; // <snicker>
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ContentPermissionRequestParent : public PContentPermissionRequestParent
|
||||
{
|
||||
public:
|
||||
ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
|
||||
Element* element,
|
||||
const IPC::Principal& principal);
|
||||
virtual ~ContentPermissionRequestParent();
|
||||
|
||||
bool IsBeingDestroyed();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<Element> mElement;
|
||||
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
|
||||
nsTArray<PermissionRequest> mRequests;
|
||||
|
||||
private:
|
||||
virtual bool Recvprompt();
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
};
|
||||
|
||||
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
|
||||
Element* aElement,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
mElement = aElement;
|
||||
mRequests = aRequests;
|
||||
}
|
||||
|
||||
ContentPermissionRequestParent::~ContentPermissionRequestParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentPermissionRequestParent::Recvprompt()
|
||||
{
|
||||
mProxy = new nsContentPermissionRequestProxy();
|
||||
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
|
||||
if (NS_FAILED(mProxy->Init(mRequests, this))) {
|
||||
mProxy->Cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (mProxy) {
|
||||
mProxy->OnParentDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContentPermissionRequestParent::IsBeingDestroyed()
|
||||
{
|
||||
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
|
||||
// to send out any message now.
|
||||
TabParent* tabParent = static_cast<TabParent*>(Manager());
|
||||
return tabParent->IsDestroyed();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType)
|
||||
|
||||
ContentPermissionType::ContentPermissionType(const nsACString& aType,
|
||||
const nsACString& aAccess)
|
||||
{
|
||||
mType = aType;
|
||||
mAccess = aAccess;
|
||||
}
|
||||
|
||||
ContentPermissionType::~ContentPermissionType()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentPermissionType::GetType(nsACString& aType)
|
||||
{
|
||||
aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentPermissionType::GetAccess(nsACString& aAccess)
|
||||
{
|
||||
aAccess = mAccess;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
|
||||
nsIMutableArray* aDesArray)
|
||||
{
|
||||
uint32_t len = aSrcArray.Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
nsRefPtr<ContentPermissionType> cpt =
|
||||
new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access());
|
||||
aDesArray->AppendElement(cpt, false);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreatePermissionArray(const nsACString& aType,
|
||||
const nsACString& aAccess,
|
||||
nsIArray** aTypesArray)
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
|
||||
aAccess);
|
||||
types->AppendElement(permType, false);
|
||||
types.forget(aTypesArray);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PContentPermissionRequestParent*
|
||||
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
|
||||
Element* element,
|
||||
const IPC::Principal& principal)
|
||||
{
|
||||
return new ContentPermissionRequestParent(aRequests, element, principal);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
|
||||
|
@ -31,14 +167,12 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsContentPermissionRequestProxy::Init(const nsACString & type,
|
||||
const nsACString & access,
|
||||
nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
|
||||
ContentPermissionRequestParent* parent)
|
||||
{
|
||||
NS_ASSERTION(parent, "null parent");
|
||||
mParent = parent;
|
||||
mType = type;
|
||||
mAccess = access;
|
||||
mPermissionRequests = requests;
|
||||
|
||||
nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
|
||||
if (!prompt) {
|
||||
|
@ -58,17 +192,14 @@ nsContentPermissionRequestProxy::OnParentDestroyed()
|
|||
NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetType(nsACString & aType)
|
||||
nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess)
|
||||
{
|
||||
aAccess = mAccess;
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
|
||||
types.forget(aTypes);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -136,10 +267,18 @@ nsContentPermissionRequestProxy::Allow()
|
|||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (mType.Equals("audio-capture")) {
|
||||
GonkPermissionService::GetInstance()->addGrantInfo(
|
||||
"android.permission.RECORD_AUDIO",
|
||||
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
|
||||
uint32_t len = mPermissionRequests.Length();
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
if (mPermissionRequests[i].type().Equals("audio-capture")) {
|
||||
GonkPermissionService::GetInstance()->addGrantInfo(
|
||||
"android.permission.RECORD_AUDIO",
|
||||
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
|
||||
}
|
||||
if (mPermissionRequests[i].type().Equals("video-capture")) {
|
||||
GonkPermissionService::GetInstance()->addGrantInfo(
|
||||
"android.permission.CAMERA",
|
||||
static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -147,55 +286,3 @@ nsContentPermissionRequestProxy::Allow()
|
|||
mParent = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType,
|
||||
const nsACString& aAccess,
|
||||
Element* aElement,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
mElement = aElement;
|
||||
mType = aType;
|
||||
mAccess = aAccess;
|
||||
}
|
||||
|
||||
ContentPermissionRequestParent::~ContentPermissionRequestParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentPermissionRequestParent::Recvprompt()
|
||||
{
|
||||
mProxy = new nsContentPermissionRequestProxy();
|
||||
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
|
||||
if (NS_FAILED(mProxy->Init(mType, mAccess, this))) {
|
||||
mProxy->Cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (mProxy) {
|
||||
mProxy->OnParentDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContentPermissionRequestParent::IsBeingDestroyed()
|
||||
{
|
||||
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
|
||||
// to send out any message now.
|
||||
TabParent* tabParent = static_cast<TabParent*>(Manager());
|
||||
return tabParent->IsDestroyed();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -6,60 +6,75 @@
|
|||
#define nsContentPermissionHelper_h
|
||||
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMutableArray.h"
|
||||
|
||||
class nsContentPermissionRequestProxy;
|
||||
|
||||
// Forward declare IPC::Principal here which is defined in
|
||||
// PermissionMessageUtils.h. Include this file will transitively includes
|
||||
// "windows.h" and it defines
|
||||
// #define CreateEvent CreateEventW
|
||||
// #define LoadImage LoadImageW
|
||||
// That will mess up windows build.
|
||||
namespace IPC {
|
||||
class Principal;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Element;
|
||||
class PermissionRequest;
|
||||
class ContentPermissionRequestParent;
|
||||
class PContentPermissionRequestParent;
|
||||
|
||||
class ContentPermissionRequestParent : public PContentPermissionRequestParent
|
||||
class ContentPermissionType : public nsIContentPermissionType
|
||||
{
|
||||
public:
|
||||
ContentPermissionRequestParent(const nsACString& type,
|
||||
const nsACString& access,
|
||||
Element* element,
|
||||
const IPC::Principal& principal);
|
||||
virtual ~ContentPermissionRequestParent();
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONTYPE
|
||||
|
||||
bool IsBeingDestroyed();
|
||||
ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
|
||||
virtual ~ContentPermissionType();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<Element> mElement;
|
||||
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
|
||||
protected:
|
||||
nsCString mType;
|
||||
nsCString mAccess;
|
||||
|
||||
private:
|
||||
virtual bool Recvprompt();
|
||||
virtual void ActorDestroy(ActorDestroyReason why);
|
||||
};
|
||||
|
||||
uint32_t ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
|
||||
nsIMutableArray* aDesArray);
|
||||
|
||||
nsresult CreatePermissionArray(const nsACString& aType,
|
||||
const nsACString& aAccess,
|
||||
nsIArray** aTypesArray);
|
||||
|
||||
PContentPermissionRequestParent*
|
||||
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
|
||||
Element* element,
|
||||
const IPC::Principal& principal);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
nsContentPermissionRequestProxy();
|
||||
virtual ~nsContentPermissionRequestProxy();
|
||||
|
||||
nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent);
|
||||
nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
|
||||
mozilla::dom::ContentPermissionRequestParent* parent);
|
||||
void OnParentDestroyed();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
private:
|
||||
// Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
|
||||
mozilla::dom::ContentPermissionRequestParent* mParent;
|
||||
nsCString mType;
|
||||
nsCString mAccess;
|
||||
nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
|
||||
};
|
||||
#endif // nsContentPermissionHelper_h
|
||||
|
||||
#endif // nsContentPermissionHelper_h
|
||||
|
|
|
@ -105,6 +105,31 @@ nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
|
|||
return cameraManager.forget();
|
||||
}
|
||||
|
||||
nsDOMCameraControl*
|
||||
nsDOMCameraManager::GetCameraControl(uint32_t aDeviceNum,
|
||||
nsICameraGetCameraCallback* onSuccess,
|
||||
nsICameraErrorCallback* onError,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv = NS_OK;
|
||||
|
||||
// reuse the same camera thread to conserve resources
|
||||
if (!mCameraThread) {
|
||||
aRv = NS_NewThread(getter_AddRefs(mCameraThread));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Creating this object will trigger the onSuccess handler
|
||||
nsDOMCameraControl* cameraControl = new nsDOMCameraControl(aDeviceNum, mCameraThread,
|
||||
onSuccess, onError, mWindow);
|
||||
if (cameraControl) {
|
||||
Register(cameraControl);
|
||||
}
|
||||
return cameraControl;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
|
||||
nsICameraGetCameraCallback* onSuccess,
|
||||
|
@ -116,22 +141,10 @@ nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
|
|||
cameraId = 1;
|
||||
}
|
||||
|
||||
// reuse the same camera thread to conserve resources
|
||||
if (!mCameraThread) {
|
||||
aRv = NS_NewThread(getter_AddRefs(mCameraThread));
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
// Creating this object will trigger the onSuccess handler
|
||||
nsRefPtr<nsDOMCameraControl> cameraControl =
|
||||
new nsDOMCameraControl(cameraId, mCameraThread,
|
||||
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow);
|
||||
|
||||
Register(cameraControl);
|
||||
GetCameraControl(cameraId, onSuccess, onError.WasPassed() ? onError.Value() : nullptr, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -49,6 +49,11 @@ public:
|
|||
CreateInstance(nsPIDOMWindow* aWindow);
|
||||
static bool IsWindowStillActive(uint64_t aWindowId);
|
||||
|
||||
// Build us an nsDOMCameraControl
|
||||
mozilla::nsDOMCameraControl* GetCameraControl(uint32_t aDeviceNum,
|
||||
nsICameraGetCameraCallback* onSuccess,
|
||||
nsICameraErrorCallback* onError,
|
||||
mozilla::ErrorResult& aRv);
|
||||
void Register(mozilla::nsDOMCameraControl* aDOMCameraControl);
|
||||
void OnNavigation(uint64_t aWindowId);
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "nsIStringBundle.h"
|
||||
#include "nsIDocument.h"
|
||||
#include <algorithm>
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
#include "mozilla/dom/DeviceStorageBinding.h"
|
||||
|
||||
|
@ -1733,17 +1734,14 @@ nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorageCursor::GetType(nsACString & aType)
|
||||
nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
|
||||
aType);
|
||||
}
|
||||
nsCString type;
|
||||
nsresult rv =
|
||||
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess)
|
||||
{
|
||||
aAccess = NS_LITERAL_CSTRING("read");
|
||||
return NS_OK;
|
||||
return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2251,8 +2249,10 @@ public:
|
|||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
permArray.AppendElement(PermissionRequest(type, access));
|
||||
child->SendPContentPermissionRequestConstructor(
|
||||
this, type, access, IPC::Principal(mPrincipal));
|
||||
this, permArray, IPC::Principal(mPrincipal));
|
||||
|
||||
Sendprompt();
|
||||
return NS_OK;
|
||||
|
@ -2266,26 +2266,23 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetType(nsACString & aType)
|
||||
NS_IMETHODIMP GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
nsCString type;
|
||||
nsresult rv
|
||||
= DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
|
||||
aType);
|
||||
nsresult rv =
|
||||
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetAccess(nsACString & aAccess)
|
||||
{
|
||||
nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest(
|
||||
DeviceStorageRequestType(mRequestType), aAccess);
|
||||
nsCString access;
|
||||
rv = DeviceStorageTypeChecker::GetAccessForRequest(
|
||||
DeviceStorageRequestType(mRequestType), access);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
return CreatePermissionArray(type, access, aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
|
||||
|
@ -3299,8 +3296,10 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath,
|
|||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
child->SendPContentPermissionRequestConstructor(r, type,
|
||||
NS_LITERAL_CSTRING("read"),
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read")));
|
||||
child->SendPContentPermissionRequestConstructor(r,
|
||||
permArray,
|
||||
IPC::Principal(mPrincipal));
|
||||
|
||||
r->Sendprompt();
|
||||
|
|
|
@ -7,15 +7,13 @@
|
|||
interface nsIPrincipal;
|
||||
interface nsIDOMWindow;
|
||||
interface nsIDOMElement;
|
||||
interface nsIArray;
|
||||
|
||||
/**
|
||||
* Interface allows access to a content to request
|
||||
* permission to perform a privileged operation such as
|
||||
* geolocation.
|
||||
* Interface provides the request type and its access.
|
||||
*/
|
||||
[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)]
|
||||
interface nsIContentPermissionRequest : nsISupports {
|
||||
|
||||
[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
|
||||
interface nsIContentPermissionType : nsISupports {
|
||||
/**
|
||||
* The type of the permission request, such as
|
||||
* "geolocation".
|
||||
|
@ -27,8 +25,22 @@ interface nsIContentPermissionRequest : nsISupports {
|
|||
* "read".
|
||||
*/
|
||||
readonly attribute ACString access;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface allows access to a content to request
|
||||
* permission to perform a privileged operation such as
|
||||
* geolocation.
|
||||
*/
|
||||
[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)]
|
||||
interface nsIContentPermissionRequest : nsISupports {
|
||||
/**
|
||||
* The array will include the request types. Elements of this array are
|
||||
* nsIContentPermissionType object.
|
||||
*/
|
||||
readonly attribute nsIArray types;
|
||||
|
||||
/*
|
||||
* The principal of the permission request.
|
||||
*/
|
||||
readonly attribute nsIPrincipal principal;
|
||||
|
|
|
@ -1348,17 +1348,6 @@ PreloadSlowThings()
|
|||
|
||||
TabChild::PreloadSlowThings();
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// After preload of slow things, start freezing threads.
|
||||
if (IsNuwaProcess()) {
|
||||
// Perform GC before freezing the Nuwa process to reduce memory usage.
|
||||
ContentChild::GetSingleton()->RecvGarbageCollect();
|
||||
|
||||
MessageLoop::current()->
|
||||
PostTask(FROM_HERE,
|
||||
NewRunnableFunction(OnFinishNuwaPreparation));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1369,15 +1358,32 @@ ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
|
|||
mAppInfo.buildID.Assign(buildID);
|
||||
mAppInfo.name.Assign(name);
|
||||
mAppInfo.UAName.Assign(UAName);
|
||||
|
||||
if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're part of the mozbrowser machinery, go ahead and start
|
||||
// preloading things. We can only do this for mozbrowser because
|
||||
// PreloadSlowThings() may set the docshell of the first TabChild
|
||||
// inactive, and we can only safely restore it to active from
|
||||
// BrowserElementChild.js.
|
||||
if ((mIsForApp || mIsForBrowser) &&
|
||||
Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
|
||||
if ((mIsForApp || mIsForBrowser)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
&& !IsNuwaProcess()
|
||||
#endif
|
||||
) {
|
||||
PreloadSlowThings();
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
ContentChild::GetSingleton()->RecvGarbageCollect();
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1249,93 +1249,13 @@ ContentParent::ContentParent(mozIApplication* aApp,
|
|||
|
||||
Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
|
||||
|
||||
// Set the subprocess's priority. We do this early on because we're likely
|
||||
// /lowering/ the process's CPU and memory priority, which it has inherited
|
||||
// from this process.
|
||||
//
|
||||
// This call can cause us to send IPC messages to the child process, so it
|
||||
// must come after the Open() call above.
|
||||
ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
|
||||
|
||||
// NB: internally, this will send an IPC message to the child
|
||||
// process to get it to create the CompositorChild. This
|
||||
// message goes through the regular IPC queue for this
|
||||
// channel, so delivery will happen-before any other messages
|
||||
// we send. The CompositorChild must be created before any
|
||||
// PBrowsers are created, because they rely on the Compositor
|
||||
// already being around. (Creation is async, so can't happen
|
||||
// on demand.)
|
||||
bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
|
||||
if (useOffMainThreadCompositing) {
|
||||
DebugOnly<bool> opened = PCompositor::Open(this);
|
||||
MOZ_ASSERT(opened);
|
||||
|
||||
if (Preferences::GetBool("layers.async-video.enabled",false)) {
|
||||
opened = PImageBridge::Open(this);
|
||||
MOZ_ASSERT(opened);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
|
||||
nsChromeRegistryChrome* chromeRegistry =
|
||||
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
|
||||
chromeRegistry->SendRegisteredChrome(this);
|
||||
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
|
||||
|
||||
if (gAppData) {
|
||||
nsCString version(gAppData->version);
|
||||
nsCString buildID(gAppData->buildID);
|
||||
nsCString name(gAppData->name);
|
||||
nsCString UAName(gAppData->UAName);
|
||||
|
||||
// Sending all information to content process.
|
||||
unused << SendAppInfo(version, buildID, name, UAName);
|
||||
}
|
||||
|
||||
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
|
||||
if (sheetService) {
|
||||
// This looks like a lot of work, but in a normal browser session we just
|
||||
// send two loads.
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets();
|
||||
for (uint32_t i = 0; i < agentSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(agentSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
|
||||
}
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets();
|
||||
for (uint32_t i = 0; i < userSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(userSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
|
||||
}
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets();
|
||||
for (uint32_t i = 0; i < authorSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(authorSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// Bug 921817. We enable the sandbox in RecvSetProcessPrivileges,
|
||||
// which is where a preallocated process drops unnecessary privileges,
|
||||
// but a non-preallocated process will already have changed its
|
||||
// uid/gid/etc immediately after forking. Thus, we send this message,
|
||||
// which is otherwise a no-op, to sandbox it at an appropriate point
|
||||
// during startup.
|
||||
if (aOSPrivileges != base::PRIVILEGES_INHERIT) {
|
||||
if (!SendSetProcessPrivileges(base::PRIVILEGES_INHERIT)) {
|
||||
KillHard();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
InitInternal(aInitialPriority,
|
||||
true, /* Setup off-main thread compositing */
|
||||
true /* Send registered chrome */);
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static const FileDescriptor*
|
||||
static const mozilla::ipc::FileDescriptor*
|
||||
FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
|
||||
ProtocolId aProtoId)
|
||||
{
|
||||
|
@ -1401,8 +1321,9 @@ ContentParent::ContentParent(ContentParent* aTemplate,
|
|||
priority = PROCESS_PRIORITY_FOREGROUND;
|
||||
}
|
||||
|
||||
ProcessPriorityManager::SetProcessPriority(this, priority);
|
||||
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
|
||||
InitInternal(priority,
|
||||
false, /* Setup Off-main thread compositing */
|
||||
false /* Send registered chrome */);
|
||||
}
|
||||
#endif // MOZ_NUWA_PROCESS
|
||||
|
||||
|
@ -1432,6 +1353,101 @@ ContentParent::~ContentParent()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
||||
bool aSetupOffMainThreadCompositing,
|
||||
bool aSendRegisteredChrome)
|
||||
{
|
||||
// Set the subprocess's priority. We do this early on because we're likely
|
||||
// /lowering/ the process's CPU and memory priority, which it has inherited
|
||||
// from this process.
|
||||
//
|
||||
// This call can cause us to send IPC messages to the child process, so it
|
||||
// must come after the Open() call above.
|
||||
ProcessPriorityManager::SetProcessPriority(this, aInitialPriority);
|
||||
|
||||
if (aSetupOffMainThreadCompositing) {
|
||||
// NB: internally, this will send an IPC message to the child
|
||||
// process to get it to create the CompositorChild. This
|
||||
// message goes through the regular IPC queue for this
|
||||
// channel, so delivery will happen-before any other messages
|
||||
// we send. The CompositorChild must be created before any
|
||||
// PBrowsers are created, because they rely on the Compositor
|
||||
// already being around. (Creation is async, so can't happen
|
||||
// on demand.)
|
||||
bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
|
||||
if (useOffMainThreadCompositing) {
|
||||
DebugOnly<bool> opened = PCompositor::Open(this);
|
||||
MOZ_ASSERT(opened);
|
||||
|
||||
if (Preferences::GetBool("layers.async-video.enabled",false)) {
|
||||
opened = PImageBridge::Open(this);
|
||||
MOZ_ASSERT(opened);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aSendRegisteredChrome) {
|
||||
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
|
||||
nsChromeRegistryChrome* chromeRegistry =
|
||||
static_cast<nsChromeRegistryChrome*>(registrySvc.get());
|
||||
chromeRegistry->SendRegisteredChrome(this);
|
||||
}
|
||||
|
||||
mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
|
||||
|
||||
if (gAppData) {
|
||||
nsCString version(gAppData->version);
|
||||
nsCString buildID(gAppData->buildID);
|
||||
nsCString name(gAppData->name);
|
||||
nsCString UAName(gAppData->UAName);
|
||||
|
||||
// Sending all information to content process.
|
||||
unused << SendAppInfo(version, buildID, name, UAName);
|
||||
}
|
||||
|
||||
nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
|
||||
if (sheetService) {
|
||||
// This looks like a lot of work, but in a normal browser session we just
|
||||
// send two loads.
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets();
|
||||
for (uint32_t i = 0; i < agentSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(agentSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
|
||||
}
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets();
|
||||
for (uint32_t i = 0; i < userSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(userSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
|
||||
}
|
||||
|
||||
nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets();
|
||||
for (uint32_t i = 0; i < authorSheets.Length(); i++) {
|
||||
URIParams uri;
|
||||
SerializeURI(authorSheets[i]->GetSheetURI(), uri);
|
||||
unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// Bug 921817. We enable the sandbox in RecvSetProcessPrivileges,
|
||||
// which is where a preallocated process drops unnecessary privileges,
|
||||
// but a non-preallocated process will already have changed its
|
||||
// uid/gid/etc immediately after forking. Thus, we send this message,
|
||||
// which is otherwise a no-op, to sandbox it at an appropriate point
|
||||
// during startup.
|
||||
if (mOSPrivileges != base::PRIVILEGES_INHERIT) {
|
||||
if (!SendSetProcessPrivileges(base::PRIVILEGES_INHERIT)) {
|
||||
KillHard();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::IsAlive()
|
||||
{
|
||||
|
|
|
@ -265,6 +265,11 @@ private:
|
|||
// The common initialization for the constructors.
|
||||
void InitializeMembers();
|
||||
|
||||
// The common initialization logic shared by all constuctors.
|
||||
void InitInternal(ProcessPriority aPriority,
|
||||
bool aSetupOffMainThreadCompositing,
|
||||
bool aSendRegisteredChrome);
|
||||
|
||||
virtual ~ContentParent();
|
||||
|
||||
void Init();
|
||||
|
|
|
@ -16,6 +16,7 @@ include protocol PIndexedDB;
|
|||
include DOMTypes;
|
||||
include JavaScriptTypes;
|
||||
include URIParams;
|
||||
include PContentPermission;
|
||||
|
||||
|
||||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
|
@ -206,10 +207,8 @@ parent:
|
|||
* Initiates an asynchronous request for permission for the
|
||||
* provided principal.
|
||||
*
|
||||
* @param aType
|
||||
* The type of permission to request.
|
||||
* @param aAccess
|
||||
* Access type. "read" for example.
|
||||
* @param aRequests
|
||||
* The array of permissions to request.
|
||||
* @param aPrincipal
|
||||
* The principal of the request.
|
||||
*
|
||||
|
@ -217,7 +216,7 @@ parent:
|
|||
* principals that can live in the content process should
|
||||
* provided.
|
||||
*/
|
||||
PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal);
|
||||
PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
|
||||
|
||||
PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
|
||||
int32_t[] aIntParams, nsString[] aStringParams);
|
||||
|
|
|
@ -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());
|
||||
|
||||
if (Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
nsresult rv = ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-add-new-process"),
|
||||
JSVAL_NULL, JSVAL_NULL, cx, 1);
|
||||
}
|
||||
|
||||
if (!mNuwaForkWaitTasks.IsEmpty()) {
|
||||
mNuwaForkWaitTasks.ElementAt(0)->Cancel();
|
||||
mNuwaForkWaitTasks.RemoveElementAt(0);
|
||||
|
@ -312,6 +321,14 @@ PreallocatedProcessManagerImpl::OnNuwaReady()
|
|||
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
|
||||
hal::PROCESS_PRIORITY_FOREGROUND);
|
||||
mIsNuwaReady = true;
|
||||
if (Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
|
||||
AutoJSContext cx;
|
||||
nsCOMPtr<nsIMessageBroadcaster> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
nsresult rv = ppmm->BroadcastAsyncMessage(
|
||||
NS_LITERAL_STRING("TEST-ONLY:nuwa-ready"),
|
||||
JSVAL_NULL, JSVAL_NULL, cx, 1);
|
||||
}
|
||||
NuwaFork();
|
||||
}
|
||||
|
||||
|
|
|
@ -1157,12 +1157,11 @@ TabChild::ArraysToParams(const InfallibleTArray<int>& aIntParams,
|
|||
#ifdef DEBUG
|
||||
PContentPermissionRequestChild*
|
||||
TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
|
||||
const nsCString& aType,
|
||||
const nsCString& aAccess,
|
||||
const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
|
||||
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal);
|
||||
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal);
|
||||
child->mIPCOpen = true;
|
||||
return request;
|
||||
}
|
||||
|
@ -2014,7 +2013,8 @@ TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog)
|
|||
}
|
||||
|
||||
PContentPermissionRequestChild*
|
||||
TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&)
|
||||
TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
NS_RUNTIMEABORT("unused");
|
||||
return nullptr;
|
||||
|
|
|
@ -278,13 +278,11 @@ public:
|
|||
#ifdef DEBUG
|
||||
virtual PContentPermissionRequestChild*
|
||||
SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
|
||||
const nsCString& aType,
|
||||
const nsCString& aAccess,
|
||||
const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal);
|
||||
#endif /* DEBUG */
|
||||
|
||||
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType,
|
||||
const nsCString& aAccess,
|
||||
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal);
|
||||
virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/ipc/DocumentRendererParent.h"
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
|
@ -579,9 +580,10 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
|
|||
}
|
||||
|
||||
PContentPermissionRequestParent*
|
||||
TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal)
|
||||
TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal)
|
||||
{
|
||||
return new ContentPermissionRequestParent(type, access, mFrameElement, principal);
|
||||
return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -225,7 +225,8 @@ public:
|
|||
virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor);
|
||||
|
||||
virtual PContentPermissionRequestParent*
|
||||
AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal);
|
||||
AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
|
||||
const IPC::Principal& aPrincipal);
|
||||
virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor);
|
||||
|
||||
virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent(
|
||||
|
|
|
@ -68,6 +68,7 @@ IPDL_SOURCES += [
|
|||
'PBrowser.ipdl',
|
||||
'PContent.ipdl',
|
||||
'PContentDialog.ipdl',
|
||||
'PContentPermission.ipdlh',
|
||||
'PContentPermissionRequest.ipdl',
|
||||
'PCrashReporter.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/.
|
||||
|
||||
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"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#ifdef MOZ_B2G
|
||||
#include "MediaPermissionGonk.h"
|
||||
#endif
|
||||
|
||||
|
@ -756,7 +756,7 @@ public:
|
|||
, mListener(aListener)
|
||||
, mPrefs(aPrefs)
|
||||
, mDeviceChosen(false)
|
||||
, mBackendChosen(false)
|
||||
, mBackend(nullptr)
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{}
|
||||
|
||||
|
@ -778,15 +778,11 @@ public:
|
|||
, mListener(aListener)
|
||||
, mPrefs(aPrefs)
|
||||
, mDeviceChosen(false)
|
||||
, mBackendChosen(true)
|
||||
, mBackend(aBackend)
|
||||
, mManager(MediaManager::GetInstance())
|
||||
{}
|
||||
|
||||
~GetUserMediaRunnable() {
|
||||
if (mBackendChosen) {
|
||||
delete mBackend;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
|
@ -794,14 +790,15 @@ public:
|
|||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
|
||||
MediaEngine* backend = mBackend;
|
||||
// Was a backend provided?
|
||||
if (!mBackendChosen) {
|
||||
mBackend = mManager->GetBackend(mWindowID);
|
||||
if (!backend) {
|
||||
backend = mManager->GetBackend(mWindowID);
|
||||
}
|
||||
|
||||
// Was a device provided?
|
||||
if (!mDeviceChosen) {
|
||||
nsresult rv = SelectDevice();
|
||||
nsresult rv = SelectDevice(backend);
|
||||
if (rv != NS_OK) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -873,10 +870,10 @@ public:
|
|||
}
|
||||
|
||||
nsresult
|
||||
SelectDevice()
|
||||
SelectDevice(MediaEngine* backend)
|
||||
{
|
||||
if (mConstraints.mPicture || mConstraints.mVideo) {
|
||||
ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
|
||||
ScopedDeletePtr<SourceSet> sources (GetSources(backend,
|
||||
mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices));
|
||||
|
||||
if (!sources->Length()) {
|
||||
|
@ -890,7 +887,7 @@ public:
|
|||
}
|
||||
|
||||
if (mConstraints.mAudio) {
|
||||
ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
|
||||
ScopedDeletePtr<SourceSet> sources (GetSources(backend,
|
||||
mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices));
|
||||
|
||||
if (!sources->Length()) {
|
||||
|
@ -984,9 +981,8 @@ private:
|
|||
MediaEnginePrefs mPrefs;
|
||||
|
||||
bool mDeviceChosen;
|
||||
bool mBackendChosen;
|
||||
|
||||
MediaEngine* mBackend;
|
||||
RefPtr<MediaEngine> mBackend;
|
||||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
};
|
||||
|
||||
|
@ -1266,10 +1262,10 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
|
|||
// Force MediaManager to startup before we try to access it from other threads
|
||||
// Hack: should init singleton earlier unless it's expensive (mem or CPU)
|
||||
(void) MediaManager::Get();
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#ifdef MOZ_B2G
|
||||
// Initialize MediaPermissionManager before send out any permission request.
|
||||
(void) MediaPermissionManager::GetInstance();
|
||||
#endif //MOZ_WIDGET_GONK
|
||||
#endif //MOZ_B2G
|
||||
}
|
||||
|
||||
// Store the WindowID in a hash table and mark as active. The entry is removed
|
||||
|
@ -1415,11 +1411,11 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
|||
MutexAutoLock lock(mMutex);
|
||||
if (!mBackend) {
|
||||
#if defined(MOZ_WEBRTC)
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
#ifndef MOZ_B2G_CAMERA
|
||||
mBackend = new MediaEngineWebRTC(mPrefs);
|
||||
#else
|
||||
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
|
||||
#endif
|
||||
#else
|
||||
mBackend = new MediaEngineWebRTC(mCameraManager);
|
||||
#endif
|
||||
#else
|
||||
mBackend = new MediaEngineDefault();
|
||||
#endif
|
||||
|
|
|
@ -513,9 +513,7 @@ private:
|
|||
// Make private because we want only one instance of this class
|
||||
MediaManager();
|
||||
|
||||
~MediaManager() {
|
||||
delete mBackend;
|
||||
}
|
||||
~MediaManager() {}
|
||||
|
||||
nsresult MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVideo,
|
||||
bool* aAudio);
|
||||
|
@ -530,11 +528,11 @@ private:
|
|||
|
||||
Mutex mMutex;
|
||||
// protected with mMutex:
|
||||
MediaEngine* mBackend;
|
||||
RefPtr<MediaEngine> mBackend;
|
||||
|
||||
static StaticRefPtr<MediaManager> sSingleton;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#ifdef MOZ_B2G_CAMERA
|
||||
nsRefPtr<nsDOMCameraManager> mCameraManager;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -20,14 +20,36 @@
|
|||
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
|
||||
#define AUDIO_PERMISSION_NAME "audio-capture"
|
||||
#define VIDEO_PERMISSION_NAME "video-capture"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static MediaPermissionManager *gMediaPermMgr = nullptr;
|
||||
|
||||
static uint32_t
|
||||
ConvertArrayToPermissionRequest(nsIArray* aSrcArray,
|
||||
nsTArray<PermissionRequest>& aDesArray)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
aSrcArray->GetLength(&len);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
|
||||
nsAutoCString type;
|
||||
nsAutoCString access;
|
||||
cpt->GetType(type);
|
||||
cpt->GetAccess(access);
|
||||
aDesArray.AppendElement(PermissionRequest(type, access));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Helper function for notifying permission granted
|
||||
static nsresult
|
||||
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
|
||||
|
@ -93,6 +115,7 @@ public:
|
|||
|
||||
private:
|
||||
bool mAudio; // Request for audio permission
|
||||
bool mVideo; // Request for video permission
|
||||
nsRefPtr<dom::GetUserMediaRequest> mRequest;
|
||||
nsTArray<nsCOMPtr<nsIMediaDevice> > mDevices; // candiate device list
|
||||
};
|
||||
|
@ -108,6 +131,7 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
|
|||
mRequest->GetConstraints(constraints);
|
||||
|
||||
mAudio = constraints.mAudio;
|
||||
mVideo = constraints.mVideo;
|
||||
|
||||
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
|
||||
nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
|
||||
|
@ -116,10 +140,34 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
|
|||
if (mAudio && deviceType.EqualsLiteral("audio")) {
|
||||
mDevices.AppendElement(device);
|
||||
}
|
||||
if (mVideo && deviceType.EqualsLiteral("video")) {
|
||||
mDevices.AppendElement(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nsIContentPermissionRequest methods
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
if (mAudio) {
|
||||
nsCOMPtr<ContentPermissionType> AudioType =
|
||||
new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
|
||||
NS_LITERAL_CSTRING("unused"));
|
||||
types->AppendElement(AudioType, false);
|
||||
}
|
||||
if (mVideo) {
|
||||
nsCOMPtr<ContentPermissionType> VideoType =
|
||||
new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
|
||||
NS_LITERAL_CSTRING("unused"));
|
||||
types->AppendElement(VideoType, false);
|
||||
}
|
||||
NS_IF_ADDREF(*aTypes = types);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
|
||||
{
|
||||
|
@ -135,24 +183,6 @@ MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetType(nsACString &aType)
|
||||
{
|
||||
if (mAudio) {
|
||||
aType = AUDIO_PERMISSION_NAME;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetAccess(nsACString &aAccess)
|
||||
{
|
||||
aAccess = "unused";
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
|
||||
{
|
||||
|
@ -278,13 +308,12 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
|
|||
dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell());
|
||||
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoCString type;
|
||||
rv = req->GetType(type);
|
||||
nsCOMPtr<nsIArray> typeArray;
|
||||
rv = req->GetTypes(getter_AddRefs(typeArray));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString access;
|
||||
rv = req->GetAccess(access);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
ConvertArrayToPermissionRequest(typeArray, permArray);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = req->GetPrincipal(getter_AddRefs(principal));
|
||||
|
@ -292,8 +321,7 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
|
|||
|
||||
req->AddRef();
|
||||
child->SendPContentPermissionRequestConstructor(req,
|
||||
type,
|
||||
access,
|
||||
permArray,
|
||||
IPC::Principal(principal));
|
||||
|
||||
req->Sendprompt();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -385,17 +386,11 @@ nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::GetType(nsACString & aType)
|
||||
nsGeolocationRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
aType = "geolocation";
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::GetAccess(nsACString & aAccess)
|
||||
{
|
||||
aAccess = "unused";
|
||||
return NS_OK;
|
||||
return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1452,12 +1447,15 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
|
|||
return false;
|
||||
}
|
||||
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
|
||||
NS_LITERAL_CSTRING("unused")));
|
||||
|
||||
// Retain a reference so the object isn't deleted without IPDL's knowledge.
|
||||
// Corresponding release occurs in DeallocPContentPermissionRequest.
|
||||
request->AddRef();
|
||||
child->SendPContentPermissionRequestConstructor(request,
|
||||
NS_LITERAL_CSTRING("geolocation"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
permArray,
|
||||
IPC::Principal(mPrincipal));
|
||||
|
||||
request->Sendprompt();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "PCOMContentPermissionRequestChild.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "PermissionMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -179,9 +180,12 @@ DesktopNotification::Init()
|
|||
// Corresponding release occurs in DeallocPContentPermissionRequest.
|
||||
nsRefPtr<DesktopNotificationRequest> copy = request;
|
||||
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
permArray.AppendElement(PermissionRequest(
|
||||
NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused")));
|
||||
child->SendPContentPermissionRequestConstructor(copy.forget().get(),
|
||||
NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
permArray,
|
||||
IPC::Principal(mPrincipal));
|
||||
|
||||
request->Sendprompt();
|
||||
|
@ -353,17 +357,11 @@ DesktopNotificationRequest::Allow()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetType(nsACString & aType)
|
||||
DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
aType = "desktop-notification";
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetAccess(nsACString & aAccess)
|
||||
{
|
||||
aAccess = "unused";
|
||||
return NS_OK;
|
||||
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
aTypes);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "nsDOMJSUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#ifdef MOZ_B2G
|
||||
#include "nsIDOMDesktopNotification.h"
|
||||
#endif
|
||||
|
@ -267,9 +268,11 @@ NotificationPermissionRequest::Run()
|
|||
// Corresponding release occurs in DeallocPContentPermissionRequest.
|
||||
AddRef();
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(type, "desktop-notification");
|
||||
NS_NAMED_LITERAL_CSTRING(access, "unused");
|
||||
child->SendPContentPermissionRequestConstructor(this, type, access,
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
permArray.AppendElement(PermissionRequest(
|
||||
NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused")));
|
||||
child->SendPContentPermissionRequestConstructor(this, permArray,
|
||||
IPC::Principal(mPrincipal));
|
||||
|
||||
Sendprompt();
|
||||
|
@ -342,17 +345,11 @@ NotificationPermissionRequest::CallCallback()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NotificationPermissionRequest::GetAccess(nsACString& aAccess)
|
||||
NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
aAccess.AssignLiteral("unused");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
NotificationPermissionRequest::GetType(nsACString& aType)
|
||||
{
|
||||
aType.AssignLiteral("desktop-notification");
|
||||
return NS_OK;
|
||||
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
aTypes);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -27,7 +27,7 @@ dictionary RTCStats {
|
|||
dictionary RTCRTPStreamStats : RTCStats {
|
||||
DOMString ssrc;
|
||||
DOMString remoteId;
|
||||
boolean isRemote;
|
||||
boolean isRemote = false;
|
||||
DOMString mediaTrackId;
|
||||
DOMString transportId;
|
||||
DOMString codecId;
|
||||
|
@ -124,7 +124,7 @@ callback RTCStatsReportCallback = void (RTCStatsReport obj);
|
|||
// to be received from c++
|
||||
|
||||
dictionary RTCStatsReportInternal {
|
||||
DOMString pcid;
|
||||
DOMString pcid = "";
|
||||
sequence<RTCRTPStreamStats> rtpStreamStats;
|
||||
sequence<RTCInboundRTPStreamStats> inboundRTPStreamStats;
|
||||
sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;
|
||||
|
|
|
@ -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))
|
||||
return MCompare::Compare_Unknown;
|
||||
|
||||
if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind())))
|
||||
if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
|
||||
ICCompare_Int32WithBoolean *coerce =
|
||||
first->isCompare_Int32WithBoolean()
|
||||
? first->toCompare_Int32WithBoolean()
|
||||
: ((second && second->isCompare_Int32WithBoolean())
|
||||
? second->toCompare_Int32WithBoolean()
|
||||
: nullptr);
|
||||
if (coerce) {
|
||||
return coerce->lhsIsInt32()
|
||||
? MCompare::Compare_Int32MaybeCoerceRHS
|
||||
: MCompare::Compare_Int32MaybeCoerceLHS;
|
||||
}
|
||||
return MCompare::Compare_Int32;
|
||||
}
|
||||
|
||||
if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
|
||||
ICCompare_NumberWithUndefined *coerce =
|
||||
|
|
|
@ -201,7 +201,8 @@ CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
|
|||
masm.bind(oolDouble->rejoin());
|
||||
} else {
|
||||
masm.convertValueToInt32(operand, input, temp, output, &fails,
|
||||
lir->mirNormal()->canBeNegativeZero());
|
||||
lir->mirNormal()->canBeNegativeZero(),
|
||||
lir->mirNormal()->conversion());
|
||||
}
|
||||
|
||||
return bailoutFrom(&fails, lir->snapshot());
|
||||
|
@ -3839,7 +3840,7 @@ CodeGenerator::visitAbsI(LAbsI *ins)
|
|||
|
||||
JS_ASSERT(input == ToRegister(ins->output()));
|
||||
masm.test32(input, input);
|
||||
masm.j(Assembler::GreaterThanOrEqual, &positive);
|
||||
masm.j(Assembler::NotSigned, &positive);
|
||||
masm.neg32(input);
|
||||
if (ins->snapshot() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
|
||||
return false;
|
||||
|
|
|
@ -1449,7 +1449,7 @@ jit::ExtractLinearInequality(MTest *test, BranchDirection direction,
|
|||
MDefinition *rhs = compare->getOperand(1);
|
||||
|
||||
// TODO: optimize Compare_UInt32
|
||||
if (compare->compareType() != MCompare::Compare_Int32)
|
||||
if (!compare->isInt32Comparison())
|
||||
return false;
|
||||
|
||||
JS_ASSERT(lhs->type() == MIRType_Int32);
|
||||
|
|
|
@ -1563,7 +1563,8 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
|
|||
Label *handleStringEntry, Label *handleStringRejoin,
|
||||
Label *truncateDoubleSlow,
|
||||
Register stringReg, FloatRegister temp, Register output,
|
||||
Label *fail, IntConversionBehavior behavior)
|
||||
Label *fail, IntConversionBehavior behavior,
|
||||
IntConversionInputKind conversion)
|
||||
{
|
||||
Register tag = splitTagForTest(value);
|
||||
bool handleStrings = (behavior == IntConversion_Truncate ||
|
||||
|
@ -1572,29 +1573,36 @@ MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput,
|
|||
handleStringRejoin;
|
||||
bool zeroObjects = behavior == IntConversion_ClampToUint8;
|
||||
|
||||
JS_ASSERT_IF(handleStrings || zeroObjects, conversion == IntConversion_Any);
|
||||
|
||||
Label done, isInt32, isBool, isDouble, isNull, isString;
|
||||
|
||||
branchEqualTypeIfNeeded(MIRType_Int32, maybeInput, tag, &isInt32);
|
||||
branchEqualTypeIfNeeded(MIRType_Boolean, maybeInput, tag, &isBool);
|
||||
if (conversion == IntConversion_Any)
|
||||
branchEqualTypeIfNeeded(MIRType_Boolean, maybeInput, tag, &isBool);
|
||||
branchEqualTypeIfNeeded(MIRType_Double, maybeInput, tag, &isDouble);
|
||||
|
||||
// If we are not truncating, we fail for anything that's not
|
||||
// null. Otherwise we might be able to handle strings and objects.
|
||||
switch (behavior) {
|
||||
case IntConversion_Normal:
|
||||
case IntConversion_NegativeZeroCheck:
|
||||
branchTestNull(Assembler::NotEqual, tag, fail);
|
||||
break;
|
||||
if (conversion == IntConversion_Any) {
|
||||
// If we are not truncating, we fail for anything that's not
|
||||
// null. Otherwise we might be able to handle strings and objects.
|
||||
switch (behavior) {
|
||||
case IntConversion_Normal:
|
||||
case IntConversion_NegativeZeroCheck:
|
||||
branchTestNull(Assembler::NotEqual, tag, fail);
|
||||
break;
|
||||
|
||||
case IntConversion_Truncate:
|
||||
case IntConversion_ClampToUint8:
|
||||
branchEqualTypeIfNeeded(MIRType_Null, maybeInput, tag, &isNull);
|
||||
if (handleStrings)
|
||||
branchEqualTypeIfNeeded(MIRType_String, maybeInput, tag, &isString);
|
||||
if (zeroObjects)
|
||||
branchEqualTypeIfNeeded(MIRType_Object, maybeInput, tag, &isNull);
|
||||
branchTestUndefined(Assembler::NotEqual, tag, fail);
|
||||
break;
|
||||
case IntConversion_Truncate:
|
||||
case IntConversion_ClampToUint8:
|
||||
branchEqualTypeIfNeeded(MIRType_Null, maybeInput, tag, &isNull);
|
||||
if (handleStrings)
|
||||
branchEqualTypeIfNeeded(MIRType_String, maybeInput, tag, &isString);
|
||||
if (zeroObjects)
|
||||
branchEqualTypeIfNeeded(MIRType_Object, maybeInput, tag, &isNull);
|
||||
branchTestUndefined(Assembler::NotEqual, tag, fail);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
jump(fail);
|
||||
}
|
||||
|
||||
// The value is null or undefined in truncation contexts - just emit 0.
|
||||
|
|
|
@ -1174,6 +1174,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
IntConversion_ClampToUint8,
|
||||
};
|
||||
|
||||
enum IntConversionInputKind {
|
||||
IntConversion_NumbersOnly,
|
||||
IntConversion_Any
|
||||
};
|
||||
|
||||
//
|
||||
// Functions for converting values to int.
|
||||
//
|
||||
|
@ -1188,7 +1193,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
Label *handleStringEntry, Label *handleStringRejoin,
|
||||
Label *truncateDoubleSlow,
|
||||
Register stringReg, FloatRegister temp, Register output,
|
||||
Label *fail, IntConversionBehavior behavior);
|
||||
Label *fail, IntConversionBehavior behavior,
|
||||
IntConversionInputKind conversion = IntConversion_Any);
|
||||
void convertValueToInt(ValueOperand value, FloatRegister temp, Register output, Label *fail,
|
||||
IntConversionBehavior behavior)
|
||||
{
|
||||
|
@ -1214,12 +1220,13 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
}
|
||||
void convertValueToInt32(ValueOperand value, MDefinition *input,
|
||||
FloatRegister temp, Register output, Label *fail,
|
||||
bool negativeZeroCheck)
|
||||
bool negativeZeroCheck, IntConversionInputKind conversion = IntConversion_Any)
|
||||
{
|
||||
convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
|
||||
negativeZeroCheck
|
||||
? IntConversion_NegativeZeroCheck
|
||||
: IntConversion_Normal);
|
||||
: IntConversion_Normal,
|
||||
conversion);
|
||||
}
|
||||
bool convertValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail,
|
||||
bool negativeZeroCheck)
|
||||
|
|
|
@ -769,20 +769,17 @@ LIRGenerator::visitTest(MTest *test)
|
|||
}
|
||||
|
||||
// Compare and branch Int32 or Object pointers.
|
||||
if (comp->compareType() == MCompare::Compare_Int32 ||
|
||||
if (comp->isInt32Comparison() ||
|
||||
comp->compareType() == MCompare::Compare_UInt32 ||
|
||||
comp->compareType() == MCompare::Compare_Object)
|
||||
{
|
||||
JSOp op = ReorderComparison(comp->jsop(), &left, &right);
|
||||
LAllocation lhs = useRegister(left);
|
||||
LAllocation rhs;
|
||||
if (comp->compareType() == MCompare::Compare_Int32 ||
|
||||
comp->compareType() == MCompare::Compare_UInt32)
|
||||
{
|
||||
if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32)
|
||||
rhs = useAnyOrConstant(right);
|
||||
} else {
|
||||
else
|
||||
rhs = useRegister(right);
|
||||
}
|
||||
LCompareAndBranch *lir = new(alloc()) LCompareAndBranch(op, lhs, rhs, ifTrue, ifFalse);
|
||||
return add(lir, comp);
|
||||
}
|
||||
|
@ -958,14 +955,14 @@ LIRGenerator::visitCompare(MCompare *comp)
|
|||
}
|
||||
|
||||
// Compare Int32 or Object pointers.
|
||||
if (comp->compareType() == MCompare::Compare_Int32 ||
|
||||
if (comp->isInt32Comparison() ||
|
||||
comp->compareType() == MCompare::Compare_UInt32 ||
|
||||
comp->compareType() == MCompare::Compare_Object)
|
||||
{
|
||||
JSOp op = ReorderComparison(comp->jsop(), &left, &right);
|
||||
LAllocation lhs = useRegister(left);
|
||||
LAllocation rhs;
|
||||
if (comp->compareType() == MCompare::Compare_Int32 ||
|
||||
if (comp->isInt32Comparison() ||
|
||||
comp->compareType() == MCompare::Compare_UInt32)
|
||||
{
|
||||
rhs = useAnyOrConstant(right);
|
||||
|
|
|
@ -1723,6 +1723,9 @@ MCompare::inputType()
|
|||
return MIRType_Boolean;
|
||||
case Compare_UInt32:
|
||||
case Compare_Int32:
|
||||
case Compare_Int32MaybeCoerceBoth:
|
||||
case Compare_Int32MaybeCoerceLHS:
|
||||
case Compare_Int32MaybeCoerceRHS:
|
||||
return MIRType_Int32;
|
||||
case Compare_Double:
|
||||
case Compare_DoubleMaybeCoerceLHS:
|
||||
|
@ -1809,7 +1812,7 @@ MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
|
|||
if ((lhs == MIRType_Int32 && rhs == MIRType_Int32) ||
|
||||
(lhs == MIRType_Boolean && rhs == MIRType_Boolean))
|
||||
{
|
||||
compareType_ = Compare_Int32;
|
||||
compareType_ = Compare_Int32MaybeCoerceBoth;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1818,7 +1821,7 @@ MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
|
|||
(lhs == MIRType_Int32 || lhs == MIRType_Boolean) &&
|
||||
(rhs == MIRType_Int32 || rhs == MIRType_Boolean))
|
||||
{
|
||||
compareType_ = Compare_Int32;
|
||||
compareType_ = Compare_Int32MaybeCoerceBoth;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2192,6 +2192,9 @@ class MCompare
|
|||
// Int32 compared to Int32
|
||||
// Boolean compared to Boolean
|
||||
Compare_Int32,
|
||||
Compare_Int32MaybeCoerceBoth,
|
||||
Compare_Int32MaybeCoerceLHS,
|
||||
Compare_Int32MaybeCoerceRHS,
|
||||
|
||||
// Int32 compared as unsigneds
|
||||
Compare_UInt32,
|
||||
|
@ -2258,6 +2261,12 @@ class MCompare
|
|||
CompareType compareType() const {
|
||||
return compareType_;
|
||||
}
|
||||
bool isInt32Comparison() const {
|
||||
return compareType() == Compare_Int32 ||
|
||||
compareType() == Compare_Int32MaybeCoerceBoth ||
|
||||
compareType() == Compare_Int32MaybeCoerceLHS ||
|
||||
compareType() == Compare_Int32MaybeCoerceRHS;
|
||||
}
|
||||
bool isDoubleComparison() const {
|
||||
return compareType() == Compare_Double ||
|
||||
compareType() == Compare_DoubleMaybeCoerceLHS ||
|
||||
|
@ -3041,10 +3050,12 @@ class MToInt32
|
|||
public ToInt32Policy
|
||||
{
|
||||
bool canBeNegativeZero_;
|
||||
MacroAssembler::IntConversionInputKind conversion_;
|
||||
|
||||
MToInt32(MDefinition *def)
|
||||
MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion)
|
||||
: MUnaryInstruction(def),
|
||||
canBeNegativeZero_(true)
|
||||
canBeNegativeZero_(true),
|
||||
conversion_(conversion)
|
||||
{
|
||||
setResultType(MIRType_Int32);
|
||||
setMovable();
|
||||
|
@ -3052,9 +3063,11 @@ class MToInt32
|
|||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ToInt32)
|
||||
static MToInt32 *New(TempAllocator &alloc, MDefinition *def)
|
||||
static MToInt32 *New(TempAllocator &alloc, MDefinition *def,
|
||||
MacroAssembler::IntConversionInputKind conversion =
|
||||
MacroAssembler::IntConversion_Any)
|
||||
{
|
||||
return new(alloc) MToInt32(def);
|
||||
return new(alloc) MToInt32(def, conversion);
|
||||
}
|
||||
|
||||
MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
|
||||
|
@ -3073,6 +3086,10 @@ class MToInt32
|
|||
return this;
|
||||
}
|
||||
|
||||
MacroAssembler::IntConversionInputKind conversion() const {
|
||||
return conversion_;
|
||||
}
|
||||
|
||||
bool congruentTo(MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
|
|||
if (compare->compareType() == MCompare::Compare_Boolean &&
|
||||
def->getOperand(0)->type() == MIRType_Boolean)
|
||||
{
|
||||
compare->setCompareType(MCompare::Compare_Int32);
|
||||
compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
|
||||
}
|
||||
|
||||
// Compare_Boolean specialization is done for "Anything === Bool"
|
||||
|
@ -242,9 +242,28 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
|
|||
replace = MToFloat32::New(alloc, in, convert);
|
||||
break;
|
||||
}
|
||||
case MIRType_Int32:
|
||||
replace = MToInt32::New(alloc, in);
|
||||
case MIRType_Int32: {
|
||||
MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly;
|
||||
if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
|
||||
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) ||
|
||||
(compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1))
|
||||
{
|
||||
convert = MacroAssembler::IntConversion_Any;
|
||||
}
|
||||
if (convert == MacroAssembler::IntConversion_NumbersOnly) {
|
||||
if (in->type() != MIRType_Int32 && in->type() != MIRType_Value)
|
||||
in = boxAt(alloc, def, in);
|
||||
} else {
|
||||
if (in->type() == MIRType_Undefined ||
|
||||
in->type() == MIRType_String ||
|
||||
in->type() == MIRType_Object)
|
||||
{
|
||||
in = boxAt(alloc, def, in);
|
||||
}
|
||||
}
|
||||
replace = MToInt32::New(alloc, in, convert);
|
||||
break;
|
||||
}
|
||||
case MIRType_Object:
|
||||
replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible);
|
||||
break;
|
||||
|
|
|
@ -1160,7 +1160,7 @@ class Assembler
|
|||
LessThanOrEqual = LE,
|
||||
Overflow = VS,
|
||||
Signed = MI,
|
||||
Unsigned = PL,
|
||||
NotSigned = PL,
|
||||
Zero = EQ,
|
||||
NonZero = NE,
|
||||
Always = AL,
|
||||
|
|
|
@ -1124,9 +1124,9 @@ CodeGeneratorARM::emitTableSwitchDispatch(MTableSwitch *mir, const Register &ind
|
|||
int32_t cases = mir->numCases();
|
||||
// Lower value with low value
|
||||
masm.ma_sub(index, Imm32(mir->low()), index, SetCond);
|
||||
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::Unsigned);
|
||||
masm.ma_rsb(index, Imm32(cases - 1), index, SetCond, Assembler::NotSigned);
|
||||
AutoForbidPools afp(&masm);
|
||||
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::Unsigned);
|
||||
masm.ma_ldr(DTRAddr(pc, DtrRegImmShift(index, LSL, 2)), pc, Offset, Assembler::NotSigned);
|
||||
masm.ma_b(defaultcase);
|
||||
|
||||
// To fill in the CodeLabels for the case entries, we need to first
|
||||
|
|
|
@ -958,7 +958,7 @@ MacroAssemblerARM::ma_mod_mask(Register src, Register dest, Register hold, int32
|
|||
// Do a trial subtraction, this is the same operation as cmp, but we store the dest
|
||||
ma_sub(dest, Imm32(mask), secondScratchReg_, SetCond);
|
||||
// If (sum - C) > 0, store sum - C back into sum, thus performing a modulus.
|
||||
ma_mov(secondScratchReg_, dest, NoSetCond, Unsigned);
|
||||
ma_mov(secondScratchReg_, dest, NoSetCond, NotSigned);
|
||||
// Get rid of the bits that we extracted before, and set the condition codes
|
||||
as_mov(ScratchRegister, lsr(ScratchRegister, shift), SetCond);
|
||||
// If the shift produced zero, finish, otherwise, continue in the loop.
|
||||
|
@ -3884,7 +3884,7 @@ MacroAssemblerARMCompat::floor(FloatRegister input, Register output, Label *bail
|
|||
// the int range, and special handling is required.
|
||||
// zero is also caught by this case, but floor of a negative number
|
||||
// should never be zero.
|
||||
ma_b(bail, Unsigned);
|
||||
ma_b(bail, NotSigned);
|
||||
|
||||
bind(&fin);
|
||||
}
|
||||
|
@ -3936,7 +3936,7 @@ MacroAssemblerARMCompat::floorf(FloatRegister input, Register output, Label *bai
|
|||
// the int range, and special handling is required.
|
||||
// zero is also caught by this case, but floor of a negative number
|
||||
// should never be zero.
|
||||
ma_b(bail, Unsigned);
|
||||
ma_b(bail, NotSigned);
|
||||
|
||||
bind(&fin);
|
||||
}
|
||||
|
@ -4023,7 +4023,7 @@ MacroAssemblerARMCompat::round(FloatRegister input, Register output, Label *bail
|
|||
// If the result looks non-negative, then this value didn't actually fit into
|
||||
// the int range, and special handling is required, or it was zero, which means
|
||||
// the result is actually -0.0 which also requires special handling.
|
||||
ma_b(bail, Unsigned);
|
||||
ma_b(bail, NotSigned);
|
||||
|
||||
bind(&fin);
|
||||
}
|
||||
|
|
|
@ -455,7 +455,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
|||
masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
|
||||
|
||||
masm.ma_sub(r8, Imm32(1), r8, SetCond);
|
||||
masm.ma_b(©LoopTop, Assembler::Unsigned);
|
||||
masm.ma_b(©LoopTop, Assembler::NotSigned);
|
||||
}
|
||||
|
||||
// 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
|
||||
// text into the equation.
|
||||
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
||||
// Text frames do not contribute to the min/max Y values for the
|
||||
// line (instead their parent frame's font-size contributes).
|
||||
// Text frames and bullets do not contribute to the min/max Y values for
|
||||
// the line (instead their parent frame's font-size contributes).
|
||||
// XXXrbs -- relax this restriction because it causes text frames
|
||||
// to jam together when 'font-size-adjust' is enabled
|
||||
// and layout is using dynamic font heights (bug 20394)
|
||||
|
@ -1961,17 +1961,15 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
|||
// For example in quirks mode, avoiding empty text frames prevents
|
||||
// "tall" lines around elements like <hr> since the rules of <hr>
|
||||
// in quirks.css have pseudo text contents with LF in them.
|
||||
#if 0
|
||||
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
#else
|
||||
// Only consider non empty text frames when line-height=normal
|
||||
bool canUpdate = !pfd->GetFlag(PFD_ISTEXTFRAME);
|
||||
if (!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
|
||||
if ((!canUpdate && pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) ||
|
||||
(canUpdate && (pfd->GetFlag(PFD_ISBULLET) ||
|
||||
nsGkAtoms::bulletFrame == frame->GetType()))) {
|
||||
// Only consider bullet / non-empty text frames when line-height:normal.
|
||||
canUpdate =
|
||||
frame->StyleText()->mLineHeight.GetUnit() == eStyleUnit_Normal;
|
||||
}
|
||||
if (canUpdate) {
|
||||
#endif
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
|
|
|
@ -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
|
||||
== 936670-1.svg 936670-1-ref.svg
|
||||
== 941940-1.html 941940-1-ref.html
|
||||
== 942017.html 942017-ref.html
|
||||
fails-if(winWidget&&!d2d) == 942672-1.html 942672-1-ref.html
|
||||
|
|
|
@ -436,15 +436,21 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
|
|||
return(_status);
|
||||
}
|
||||
|
||||
static int nr_ice_any_peer_paired(nr_ice_candidate* cand) {
|
||||
nr_ice_peer_ctx* pctx=STAILQ_FIRST(&cand->ctx->peers);
|
||||
while(pctx && pctx->state == NR_ICE_PEER_STATE_UNPAIRED){
|
||||
/* Is it worth actually looking through the check lists? Probably not. */
|
||||
pctx=STAILQ_NEXT(pctx,entry);
|
||||
}
|
||||
return pctx != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Compare this newly initialized candidate against the other initialized
|
||||
candidates and discard the lower-priority one if they are redundant.
|
||||
|
||||
This algorithm combined with the other algorithms, favors
|
||||
host > srflx > relay
|
||||
|
||||
This actually won't prune relayed in the very rare
|
||||
case that relayed is the same. Not relevant in practice.
|
||||
*/
|
||||
int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *comp, nr_ice_candidate *c1, int *was_pruned)
|
||||
{
|
||||
|
@ -463,12 +469,13 @@ int nr_ice_component_maybe_prune_candidate(nr_ice_ctx *ctx, nr_ice_component *co
|
|||
(c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
|
||||
|
||||
/*
|
||||
These are redundant. Remove the lower pri one.
|
||||
These are redundant. Remove the lower pri one, or if pairing has
|
||||
already occurred, remove the newest one.
|
||||
|
||||
Since this algorithmis run whenever a new candidate
|
||||
is initialized, there should at most one duplicate.
|
||||
*/
|
||||
if (c1->priority < c2->priority) {
|
||||
if ((c1->priority <= c2->priority) || nr_ice_any_peer_paired(c2)) {
|
||||
tmp = c1;
|
||||
*was_pruned = 1;
|
||||
}
|
||||
|
|
|
@ -336,6 +336,10 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
|
|||
ABORT(R_FAILED);
|
||||
}
|
||||
|
||||
/* Set this first; if we fail partway through, we do not want to end
|
||||
* up in UNPAIRED after creating some pairs. */
|
||||
pctx->state = NR_ICE_PEER_STATE_PAIRED;
|
||||
|
||||
stream=STAILQ_FIRST(&pctx->peer_streams);
|
||||
while(stream){
|
||||
if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream,
|
||||
|
@ -345,7 +349,6 @@ int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
|
|||
stream=STAILQ_NEXT(stream,entry);
|
||||
}
|
||||
|
||||
pctx->state = NR_ICE_PEER_STATE_PAIRED;
|
||||
|
||||
_status=0;
|
||||
abort:
|
||||
|
|
|
@ -380,6 +380,28 @@ nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
|
|||
|
||||
nr_turn_client_cancel(ctx);
|
||||
|
||||
RFREE(ctx->username);
|
||||
ctx->username = 0;
|
||||
r_data_destroy(&ctx->password);
|
||||
RFREE(ctx->nonce);
|
||||
ctx->nonce = 0;
|
||||
RFREE(ctx->realm);
|
||||
ctx->realm = 0;
|
||||
|
||||
/* Destroy the STUN client ctxs */
|
||||
while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
|
||||
nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
|
||||
STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
|
||||
nr_turn_stun_ctx_destroy(&stun);
|
||||
}
|
||||
|
||||
/* Destroy the permissions */
|
||||
while (!STAILQ_EMPTY(&ctx->permissions)) {
|
||||
nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
|
||||
STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
|
||||
nr_turn_permission_destroy(&perm);
|
||||
}
|
||||
|
||||
RFREE(ctx);
|
||||
|
||||
return(0);
|
||||
|
@ -457,6 +479,8 @@ abort:
|
|||
|
||||
int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
|
||||
{
|
||||
nr_turn_stun_ctx *stun = 0;
|
||||
|
||||
if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
|
||||
ctx->state == NR_TURN_CLIENT_STATE_FAILED)
|
||||
return 0;
|
||||
|
@ -482,29 +506,11 @@ int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
/* Setting these values to 0 isn't strictly necessary, but
|
||||
it protects us in case we double cancel and for
|
||||
some reason bungle the states above in future.*/
|
||||
RFREE(ctx->username);
|
||||
ctx->username = 0;
|
||||
r_data_destroy(&ctx->password);
|
||||
RFREE(ctx->nonce);
|
||||
ctx->nonce = 0;
|
||||
RFREE(ctx->realm);
|
||||
ctx->realm = 0;
|
||||
|
||||
/* Destroy the STUN client ctxs */
|
||||
while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
|
||||
nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
|
||||
STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
|
||||
nr_turn_stun_ctx_destroy(&stun);
|
||||
}
|
||||
|
||||
/* Destroy the permissions */
|
||||
while (!STAILQ_EMPTY(&ctx->permissions)) {
|
||||
nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
|
||||
STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
|
||||
nr_turn_permission_destroy(&perm);
|
||||
/* Cancel the STUN client ctxs */
|
||||
stun = STAILQ_FIRST(&ctx->stun_ctxs);
|
||||
while (stun) {
|
||||
nr_stun_client_cancel(stun->stun);
|
||||
stun = STAILQ_NEXT(stun, entry);
|
||||
}
|
||||
|
||||
/* Cancel the timers, if not already cancelled */
|
||||
|
|
|
@ -329,14 +329,16 @@ nsresult MediaPipeline::SendPacket(TransportFlow *flow, const void *data,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaPipeline::increment_rtp_packets_sent() {
|
||||
void MediaPipeline::increment_rtp_packets_sent(int32_t bytes) {
|
||||
++rtp_packets_sent_;
|
||||
rtp_bytes_sent_ += bytes;
|
||||
|
||||
if (!(rtp_packets_sent_ % 100)) {
|
||||
MOZ_MTLOG(ML_INFO, "RTP sent packet count for " << description_
|
||||
<< " Pipeline " << static_cast<void *>(this)
|
||||
<< " Flow : " << static_cast<void *>(rtp_transport_)
|
||||
<< ": " << rtp_packets_sent_);
|
||||
<< ": " << rtp_packets_sent_
|
||||
<< " (" << rtp_bytes_sent_ << " bytes)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,13 +352,15 @@ void MediaPipeline::increment_rtcp_packets_sent() {
|
|||
}
|
||||
}
|
||||
|
||||
void MediaPipeline::increment_rtp_packets_received() {
|
||||
void MediaPipeline::increment_rtp_packets_received(int32_t bytes) {
|
||||
++rtp_packets_received_;
|
||||
rtp_bytes_received_ += bytes;
|
||||
if (!(rtp_packets_received_ % 100)) {
|
||||
MOZ_MTLOG(ML_INFO, "RTP received packet count for " << description_
|
||||
<< " Pipeline " << static_cast<void *>(this)
|
||||
<< " Flow : " << static_cast<void *>(rtp_transport_)
|
||||
<< ": " << rtp_packets_received_);
|
||||
<< ": " << rtp_packets_received_
|
||||
<< " (" << rtp_bytes_received_ << " bytes)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,13 +407,12 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
|
|||
|
||||
// TODO(ekr@rtfm.com): filter for DTLS here and in RtcpPacketReceived
|
||||
// TODO(ekr@rtfm.com): filter on SSRC for bundle
|
||||
increment_rtp_packets_received();
|
||||
|
||||
// Make a copy rather than cast away constness
|
||||
ScopedDeletePtr<unsigned char> inner_data(
|
||||
new unsigned char[len]);
|
||||
memcpy(inner_data, data, len);
|
||||
int out_len;
|
||||
int out_len = 0;
|
||||
nsresult res = rtp_recv_srtp_->UnprotectRtp(inner_data,
|
||||
len, len, &out_len);
|
||||
if (!NS_SUCCEEDED(res)) {
|
||||
|
@ -426,6 +429,8 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
|
|||
|
||||
return;
|
||||
}
|
||||
increment_rtp_packets_received(out_len);
|
||||
|
||||
(void)conduit_->ReceivedRTPPacket(inner_data, out_len); // Ignore error codes
|
||||
}
|
||||
|
||||
|
@ -612,7 +617,7 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
|
|||
if (!NS_SUCCEEDED(res))
|
||||
return res;
|
||||
|
||||
pipeline_->increment_rtp_packets_sent();
|
||||
pipeline_->increment_rtp_packets_sent(out_len);
|
||||
return pipeline_->SendPacket(pipeline_->rtp_transport_, inner_data,
|
||||
out_len);
|
||||
}
|
||||
|
|
|
@ -92,6 +92,8 @@ class MediaPipeline : public sigslot::has_slots<> {
|
|||
rtcp_packets_sent_(0),
|
||||
rtp_packets_received_(0),
|
||||
rtcp_packets_received_(0),
|
||||
rtp_bytes_sent_(0),
|
||||
rtp_bytes_received_(0),
|
||||
pc_(pc),
|
||||
description_() {
|
||||
// To indicate rtcp-mux rtcp_transport should be nullptr.
|
||||
|
@ -123,17 +125,20 @@ class MediaPipeline : public sigslot::has_slots<> {
|
|||
virtual nsresult Init();
|
||||
|
||||
virtual Direction direction() const { return direction_; }
|
||||
virtual TrackID trackid() const { return track_id_; }
|
||||
|
||||
bool IsDoingRtcpMux() const {
|
||||
return (rtp_transport_ == rtcp_transport_);
|
||||
}
|
||||
|
||||
int rtp_packets_sent() const { return rtp_packets_sent_; }
|
||||
int rtcp_packets_sent() const { return rtcp_packets_sent_; }
|
||||
int rtp_packets_received() const { return rtp_packets_received_; }
|
||||
int rtcp_packets_received() const { return rtcp_packets_received_; }
|
||||
int32_t rtp_packets_sent() const { return rtp_packets_sent_; }
|
||||
int64_t rtp_bytes_sent() const { return rtp_bytes_sent_; }
|
||||
int32_t rtcp_packets_sent() const { return rtcp_packets_sent_; }
|
||||
int32_t rtp_packets_received() const { return rtp_packets_received_; }
|
||||
int64_t rtp_bytes_received() const { return rtp_bytes_received_; }
|
||||
int32_t rtcp_packets_received() const { return rtcp_packets_received_; }
|
||||
|
||||
MediaSessionConduit *Conduit() { return conduit_; }
|
||||
MediaSessionConduit *Conduit() const { return conduit_; }
|
||||
|
||||
// Thread counting
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline)
|
||||
|
@ -167,9 +172,9 @@ class MediaPipeline : public sigslot::has_slots<> {
|
|||
virtual nsresult TransportFailed_s(TransportFlow *flow); // The transport is down
|
||||
virtual nsresult TransportReady_s(TransportFlow *flow); // The transport is ready
|
||||
|
||||
void increment_rtp_packets_sent();
|
||||
void increment_rtp_packets_sent(int bytes);
|
||||
void increment_rtcp_packets_sent();
|
||||
void increment_rtp_packets_received();
|
||||
void increment_rtp_packets_received(int bytes);
|
||||
void increment_rtcp_packets_received();
|
||||
|
||||
virtual nsresult SendPacket(TransportFlow *flow, const void* data, int len);
|
||||
|
@ -216,10 +221,12 @@ class MediaPipeline : public sigslot::has_slots<> {
|
|||
// Written only on STS thread. May be read on other
|
||||
// threads but since there is no mutex, the values
|
||||
// will only be approximate.
|
||||
int rtp_packets_sent_;
|
||||
int rtcp_packets_sent_;
|
||||
int rtp_packets_received_;
|
||||
int rtcp_packets_received_;
|
||||
int32_t rtp_packets_sent_;
|
||||
int32_t rtcp_packets_sent_;
|
||||
int32_t rtp_packets_received_;
|
||||
int32_t rtcp_packets_received_;
|
||||
int64_t rtp_bytes_sent_;
|
||||
int64_t rtp_bytes_received_;
|
||||
|
||||
// Written on Init. Read on STS thread.
|
||||
std::string pc_;
|
||||
|
|
|
@ -63,6 +63,8 @@
|
|||
#include "mozilla/dom/DataChannelBinding.h"
|
||||
#include "MediaStreamList.h"
|
||||
#include "MediaStreamTrack.h"
|
||||
#include "AudioStreamTrack.h"
|
||||
#include "VideoStreamTrack.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "rlogringbuffer.h"
|
||||
|
@ -1796,26 +1798,51 @@ PeerConnectionImpl::IceGatheringStateChange_m(PCImplIceGatheringState aState)
|
|||
}
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
void PeerConnectionImpl::GetStats_s(
|
||||
uint32_t trackId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now) {
|
||||
|
||||
nsresult result = NS_OK;
|
||||
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternal);
|
||||
if (!report) {
|
||||
result = NS_ERROR_FAILURE;
|
||||
class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
|
||||
public:
|
||||
RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
|
||||
mPcid = pcid;
|
||||
mInboundRTPStreamStats.Construct();
|
||||
mOutboundRTPStreamStats.Construct();
|
||||
mMediaStreamTrackStats.Construct();
|
||||
mMediaStreamStats.Construct();
|
||||
mTransportStats.Construct();
|
||||
mIceComponentStats.Construct();
|
||||
mIceCandidatePairStats.Construct();
|
||||
mIceCandidateStats.Construct();
|
||||
mCodecStats.Construct();
|
||||
}
|
||||
};
|
||||
|
||||
report->mPcid.Construct(NS_ConvertASCIItoUTF16(mHandle.c_str()));
|
||||
nsresult PeerConnectionImpl::GetStatsImpl_s(
|
||||
TrackID trackId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
RTCStatsReportInternal *report) {
|
||||
if (mMedia) {
|
||||
RefPtr<NrIceMediaStream> mediaStream(
|
||||
mMedia->ice_media_stream(trackId));
|
||||
nsresult rv;
|
||||
|
||||
// Gather stats from media pipeline (can't touch stream itself on STS)
|
||||
|
||||
for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
|
||||
rv = mMedia->GetLocalStream(i)->GetPipelineStats(now, trackId,
|
||||
&report->mInboundRTPStreamStats.Value(),
|
||||
&report->mOutboundRTPStreamStats.Value());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) {
|
||||
rv = mMedia->GetRemoteStream(i)->GetPipelineStats(now, trackId,
|
||||
&report->mInboundRTPStreamStats.Value(),
|
||||
&report->mOutboundRTPStreamStats.Value());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Gather stats from ICE
|
||||
|
||||
RefPtr<NrIceMediaStream> mediaStream(mMedia->ice_media_stream(trackId));
|
||||
if (mediaStream) {
|
||||
std::vector<NrIceCandidatePair> candPairs;
|
||||
mediaStream->GetCandidatePairs(&candPairs);
|
||||
report->mIceCandidatePairStats.Construct();
|
||||
report->mIceCandidateStats.Construct();
|
||||
NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
|
||||
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
|
||||
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
|
||||
|
@ -1869,19 +1896,32 @@ void PeerConnectionImpl::GetStats_s(
|
|||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void PeerConnectionImpl::GetStats_s(
|
||||
TrackID trackId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now) {
|
||||
|
||||
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternalConstruct(
|
||||
NS_ConvertASCIItoUTF16(mHandle.c_str()), now));
|
||||
|
||||
nsresult rv = report ? GetStatsImpl_s(trackId, internalStats, now, report)
|
||||
: NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsRefPtr<PeerConnectionImpl> pc(this);
|
||||
RUN_ON_THREAD(mThread,
|
||||
WrapRunnable(pc,
|
||||
&PeerConnectionImpl::OnStatsReport_m,
|
||||
trackId,
|
||||
result,
|
||||
rv,
|
||||
report),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void PeerConnectionImpl::OnStatsReport_m(
|
||||
uint32_t trackId,
|
||||
TrackID trackId,
|
||||
nsresult result,
|
||||
nsAutoPtr<RTCStatsReportInternal> report) {
|
||||
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
@ -528,12 +529,17 @@ private:
|
|||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// Fills in an RTCStatsReportInternal. Must be run on STS.
|
||||
void GetStats_s(uint32_t trackId,
|
||||
void GetStats_s(mozilla::TrackID trackId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now);
|
||||
|
||||
nsresult GetStatsImpl_s(mozilla::TrackID trackId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
mozilla::dom::RTCStatsReportInternal *report);
|
||||
|
||||
// Sends an RTCStatsReport to JS. Must run on main thread.
|
||||
void OnStatsReport_m(uint32_t trackId,
|
||||
void OnStatsReport_m(mozilla::TrackID trackId,
|
||||
nsresult result,
|
||||
nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report);
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include "MediaStreamList.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/RTCStatsReportBinding.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace sipcc {
|
||||
|
||||
|
@ -465,6 +467,58 @@ SourceStreamInfo::GetPipeline(int aTrack) {
|
|||
return it->second;
|
||||
}
|
||||
|
||||
// This methods gathers statistics for the getStats API.
|
||||
// aTrack == 0 means gather stats for all tracks.
|
||||
|
||||
nsresult
|
||||
SourceStreamInfo::GetPipelineStats(DOMHighResTimeStamp now, int aTrack,
|
||||
Sequence<RTCInboundRTPStreamStats > *inbound,
|
||||
Sequence<RTCOutboundRTPStreamStats > *outbound)
|
||||
{
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
ASSERT_ON_THREAD(mParent->GetSTSThread());
|
||||
// walk through all the MediaPipelines and gather stats
|
||||
for (std::map<int, RefPtr<MediaPipeline> >::iterator it = mPipelines.begin();
|
||||
it != mPipelines.end();
|
||||
++it) {
|
||||
if (!aTrack || aTrack == it->first) {
|
||||
const MediaPipeline &mp = *it->second;
|
||||
nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ?
|
||||
NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
|
||||
idstr.AppendInt(mp.trackid());
|
||||
|
||||
switch (mp.direction()) {
|
||||
case MediaPipeline::TRANSMIT: {
|
||||
RTCOutboundRTPStreamStats s;
|
||||
s.mTimestamp.Construct(now);
|
||||
s.mId.Construct(NS_LITERAL_STRING("outbound_rtp_") + idstr);
|
||||
s.mType.Construct(RTCStatsType::Outboundrtp);
|
||||
// TODO: Get SSRC
|
||||
// int channel = mp.Conduit()->GetChannel();
|
||||
s.mSsrc.Construct(NS_LITERAL_STRING("123457"));
|
||||
s.mPacketsSent.Construct(mp.rtp_packets_sent());
|
||||
s.mBytesSent.Construct(mp.rtp_bytes_sent());
|
||||
outbound->AppendElement(s);
|
||||
break;
|
||||
}
|
||||
case MediaPipeline::RECEIVE: {
|
||||
RTCInboundRTPStreamStats s;
|
||||
s.mTimestamp.Construct(now);
|
||||
s.mId.Construct(NS_LITERAL_STRING("inbound_rtp_") + idstr);
|
||||
s.mType.Construct(RTCStatsType::Inboundrtp);
|
||||
s.mSsrc.Construct(NS_LITERAL_STRING("123457"));
|
||||
s.mPacketsReceived.Construct(mp.rtp_packets_received());
|
||||
s.mBytesReceived.Construct(mp.rtp_bytes_received());
|
||||
inbound->AppendElement(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LocalSourceStreamInfo::StorePipeline(int aTrack,
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> aPipeline)
|
||||
|
|
|
@ -29,12 +29,16 @@
|
|||
#include "VideoUtils.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "VideoSegment.h"
|
||||
#else
|
||||
namespace mozilla {
|
||||
class DataChannel;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
class DataChannel;
|
||||
namespace dom {
|
||||
class RTCInboundRTPStreamStats;
|
||||
class RTCOutboundRTPStreamStats;
|
||||
}
|
||||
}
|
||||
|
||||
#include "nricectx.h"
|
||||
#include "nriceresolver.h"
|
||||
#include "nricemediastream.h"
|
||||
|
@ -181,7 +185,9 @@ public:
|
|||
}
|
||||
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> GetPipeline(int aTrack);
|
||||
|
||||
nsresult GetPipelineStats(DOMHighResTimeStamp now, int aTrack,
|
||||
mozilla::dom::Sequence<mozilla::dom::RTCInboundRTPStreamStats > *inbound,
|
||||
mozilla::dom::Sequence<mozilla::dom::RTCOutboundRTPStreamStats > *outbound);
|
||||
protected:
|
||||
std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> > mPipelines;
|
||||
nsRefPtr<DOMMediaStream> mMediaStream;
|
||||
|
|
|
@ -325,7 +325,8 @@ class MediaPipelineTest : public ::testing::Test {
|
|||
PR_Sleep(10000);
|
||||
|
||||
ASSERT_GE(p1_.GetAudioRtpCount(), 40);
|
||||
ASSERT_GE(p2_.GetAudioRtpCount(), 40);
|
||||
// TODO: Fix to not fail or crash (Bug 947663)
|
||||
// ASSERT_GE(p2_.GetAudioRtpCount(), 40);
|
||||
ASSERT_GE(p1_.GetAudioRtcpCount(), 1);
|
||||
ASSERT_GE(p2_.GetAudioRtcpCount(), 1);
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = {
|
|||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
|
||||
|
||||
handleExistingPermission: function handleExistingPermission(request, isApp) {
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
|
||||
handleExistingPermission: function handleExistingPermission(request, type, isApp) {
|
||||
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
|
||||
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
request.allow();
|
||||
return true;
|
||||
|
@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) {
|
||||
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
|
||||
request.cancel();
|
||||
return true;
|
||||
}
|
||||
|
@ -62,8 +62,16 @@ ContentPermissionPrompt.prototype = {
|
|||
prompt: function(request) {
|
||||
let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID;
|
||||
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
|
||||
|
||||
// Returns true if the request was handled
|
||||
if (this.handleExistingPermission(request, isApp))
|
||||
if (this.handleExistingPermission(request, perm.type, isApp))
|
||||
return;
|
||||
|
||||
let chromeWin = this.getChromeForRequest(request);
|
||||
|
@ -72,17 +80,17 @@ ContentPermissionPrompt.prototype = {
|
|||
return;
|
||||
|
||||
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
let entityName = kEntities[request.type];
|
||||
let entityName = kEntities[perm.type];
|
||||
|
||||
let buttons = [{
|
||||
label: browserBundle.GetStringFromName(entityName + ".allow"),
|
||||
callback: function(aChecked) {
|
||||
// If the user checked "Don't ask again", make a permanent exception
|
||||
if (aChecked) {
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
} else if (isApp || entityName == "desktopNotification") {
|
||||
// Otherwise allow the permission for the current session (if the request comes from an app or if it's a desktop-notification request)
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
|
||||
}
|
||||
|
||||
request.allow();
|
||||
|
@ -93,7 +101,7 @@ ContentPermissionPrompt.prototype = {
|
|||
callback: function(aChecked) {
|
||||
// If the user checked "Don't ask again", make a permanent exception
|
||||
if (aChecked)
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
|
||||
|
||||
request.cancel();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
#include "nsNetUtil.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsISystemProxySettings.h"
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
using namespace mozilla;
|
||||
|
@ -674,6 +677,13 @@ nsPACMan::NamePACThread()
|
|||
{
|
||||
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "wrong thread");
|
||||
PR_SetCurrentThreadName("Proxy Resolution");
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
|
||||
"NuwaMarkCurrentThread is undefined!");
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -34,9 +34,18 @@ this.MockPermissionPrompt = {
|
|||
init: function() {
|
||||
this.reset();
|
||||
if (!registrar.isCIDRegistered(newClassID)) {
|
||||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
||||
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
|
||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
||||
try {
|
||||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
||||
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
|
||||
} catch (ex) {
|
||||
oldClassID = "";
|
||||
oldFactory = null;
|
||||
dump("TEST-INFO | can't get permission prompt registered component, " +
|
||||
"assuming there is none");
|
||||
}
|
||||
if (oldFactory) {
|
||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
||||
}
|
||||
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
|
||||
}
|
||||
},
|
||||
|
@ -61,14 +70,17 @@ MockPermissionPromptInstance.prototype = {
|
|||
|
||||
prompt: function(request) {
|
||||
|
||||
this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal,
|
||||
request.type);
|
||||
if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
request.allow();
|
||||
}
|
||||
else {
|
||||
request.cancel();
|
||||
let perms = request.types.QueryInterface(Ci.nsIArray);
|
||||
for (let idx = 0; idx < perms.length; idx++) {
|
||||
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
|
||||
if (Services.perms.testExactPermissionFromPrincipal(
|
||||
request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
request.allow();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -30,17 +30,25 @@ ContentPermission.prototype = {
|
|||
},
|
||||
|
||||
prompt: function(request) {
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
|
||||
|
||||
// Reuse any remembered permission preferences
|
||||
let result =
|
||||
Services.perms.testExactPermissionFromPrincipal(request.principal,
|
||||
request.type);
|
||||
perm.type);
|
||||
|
||||
// We used to use the name "geo" for the geolocation permission, now we're
|
||||
// using "geolocation". We need to check both to support existing
|
||||
// installations.
|
||||
if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
|
||||
result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
|
||||
request.type == "geolocation") {
|
||||
perm.type == "geolocation") {
|
||||
let geoResult = Services.perms.testExactPermission(request.principal.URI,
|
||||
"geo");
|
||||
// We override the result only if the "geo" permission was allowed or
|
||||
|
@ -56,7 +64,7 @@ ContentPermission.prototype = {
|
|||
return;
|
||||
} else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
|
||||
(result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
|
||||
UNKNOWN_FAIL.indexOf(request.type) >= 0)) {
|
||||
UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
@ -71,16 +79,16 @@ ContentPermission.prototype = {
|
|||
let remember = {value: false};
|
||||
let choice = Services.prompt.confirmEx(
|
||||
chromeWin,
|
||||
bundle.formatStringFromName(request.type + ".title", [name], 1),
|
||||
bundle.GetStringFromName(request.type + ".description"),
|
||||
bundle.formatStringFromName(perm.type + ".title", [name], 1),
|
||||
bundle.GetStringFromName(perm.type + ".description"),
|
||||
// Set both buttons to strings with the cancel button being default
|
||||
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
|
||||
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
|
||||
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
|
||||
bundle.GetStringFromName(request.type + ".allow"),
|
||||
bundle.GetStringFromName(request.type + ".deny"),
|
||||
bundle.GetStringFromName(perm.type + ".allow"),
|
||||
bundle.GetStringFromName(perm.type + ".deny"),
|
||||
null,
|
||||
bundle.GetStringFromName(request.type + ".remember"),
|
||||
bundle.GetStringFromName(perm.type + ".remember"),
|
||||
remember);
|
||||
|
||||
let action = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
@ -90,10 +98,10 @@ ContentPermission.prototype = {
|
|||
|
||||
if (remember.value) {
|
||||
// Persist the choice if the user wants to remember
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, action);
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, action);
|
||||
} else {
|
||||
// Otherwise allow the permission for the current session
|
||||
Services.perms.addFromPrincipal(request.principal, request.type, action,
|
||||
Services.perms.addFromPrincipal(request.principal, perm.type, action,
|
||||
Ci.nsIPermissionManager.EXPIRE_SESSION);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ public:
|
|||
typedef typename KeyClass::KeyType KeyType;
|
||||
typedef nsBaseHashtableET<KeyClass,DataType> EntryType;
|
||||
|
||||
using nsTHashtable<EntryType>::Contains;
|
||||
|
||||
nsBaseHashtable()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/ThreadHangStats.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#include "prinrval.h"
|
||||
#include "prthread.h"
|
||||
|
@ -31,6 +34,15 @@ private:
|
|||
static void MonitorThread(void* aData)
|
||||
{
|
||||
PR_SetCurrentThreadName("BgHangManager");
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
|
||||
"NuwaMarkCurrentThread is undefined!");
|
||||
NuwaMarkCurrentThread(nullptr, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We do not hold a reference to BackgroundHangManager here
|
||||
because the monitor thread only exists as long as the
|
||||
BackgroundHangManager instance exists. We stop the monitor
|
||||
|
|
Загрузка…
Ссылка в новой задаче