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