This commit is contained in:
Ryan VanderMeulen 2015-07-17 10:26:22 -04:00
Родитель 715c04c018 423e03562b
Коммит a33e05c88c
696 изменённых файлов: 15396 добавлений и 5314 удалений

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

@ -163,22 +163,24 @@ getTextAfterOffsetCB(AtkText *aText, gint aOffset,
AtkTextBoundary aBoundaryType,
gint *aStartOffset, gint *aEndOffset)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
ConvertTexttoAsterisks(accWrap, autoStr);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
&endOffset);
}
*aStartOffset = startOffset;
*aEndOffset = endOffset;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
}
@ -188,23 +190,26 @@ getTextAtOffsetCB(AtkText *aText, gint aOffset,
AtkTextBoundary aBoundaryType,
gint *aStartOffset, gint *aEndOffset)
{
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nullptr;
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
*aStartOffset = startOffset;
*aEndOffset = endOffset;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
&endOffset);
}
*aStartOffset = startOffset;
*aEndOffset = endOffset;
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
}
static gunichar
@ -233,22 +238,25 @@ getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
AtkTextBoundary aBoundaryType,
gint *aStartOffset, gint *aEndOffset)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextBeforeOffset(aOffset, aBoundaryType,
&startOffset, &endOffset, autoStr);
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
text->TextBeforeOffset(aOffset, aBoundaryType,
&startOffset, &endOffset, autoStr);
ConvertTexttoAsterisks(accWrap, autoStr);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
&endOffset);
}
*aStartOffset = startOffset;
*aEndOffset = endOffset;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
}

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

@ -30,6 +30,7 @@
#include "nsIScrollableFrame.h"
#include "nsIServiceManager.h"
#include "nsITextControlElement.h"
#include "nsIMathMLFrame.h"
#include "nsTextFragment.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/dom/Element.h"
@ -952,6 +953,145 @@ HyperTextAccessible::GetLevelInternal()
return AccessibleWrap::GetLevelInternal();
}
void
HyperTextAccessible::SetMathMLXMLRoles(nsIPersistentProperties* aAttributes)
{
// Add MathML xmlroles based on the position inside the parent.
Accessible* parent = Parent();
if (parent) {
switch (parent->Role()) {
case roles::MATHML_CELL:
case roles::MATHML_ENCLOSED:
case roles::MATHML_ERROR:
case roles::MATHML_MATH:
case roles::MATHML_ROW:
case roles::MATHML_SQUARE_ROOT:
case roles::MATHML_STYLE:
if (Role() == roles::MATHML_OPERATOR) {
// This is an operator inside an <mrow> (or an inferred <mrow>).
// See http://www.w3.org/TR/MathML3/chapter3.html#presm.inferredmrow
// XXX We should probably do something similar for MATHML_FENCED, but
// operators do not appear in the accessible tree. See bug 1175747.
nsIMathMLFrame* mathMLFrame = do_QueryFrame(GetFrame());
if (mathMLFrame) {
nsEmbellishData embellishData;
mathMLFrame->GetEmbellishData(embellishData);
if (NS_MATHML_EMBELLISH_IS_FENCE(embellishData.flags)) {
if (!PrevSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::open_fence);
} else if (!NextSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::close_fence);
}
}
if (NS_MATHML_EMBELLISH_IS_SEPARATOR(embellishData.flags)) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::separator_);
}
}
}
break;
case roles::MATHML_FRACTION:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ?
nsGkAtoms::numerator :
nsGkAtoms::denominator);
break;
case roles::MATHML_ROOT:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::root_index);
break;
case roles::MATHML_SUB:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::subscript);
break;
case roles::MATHML_SUP:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::superscript);
break;
case roles::MATHML_SUB_SUP: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::subscript :
nsGkAtoms::superscript));
} break;
case roles::MATHML_UNDER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::underscript);
break;
case roles::MATHML_OVER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::overscript);
break;
case roles::MATHML_UNDER_OVER: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::underscript :
nsGkAtoms::overscript));
} break;
case roles::MATHML_MULTISCRIPTS: {
// Get the <multiscripts> base.
nsIContent* child;
bool baseFound = false;
for (child = parent->GetContent()->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->IsMathMLElement()) {
baseFound = true;
break;
}
}
if (baseFound) {
nsIContent* content = GetContent();
if (child == content) {
// We are the base.
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::base);
} else {
// Browse the list of scripts to find us and determine our type.
bool postscript = true;
bool subscript = true;
for (child = child->GetNextSibling(); child;
child = child->GetNextSibling()) {
if (!child->IsMathMLElement())
continue;
if (child->IsMathMLElement(nsGkAtoms::mprescripts_)) {
postscript = false;
subscript = true;
continue;
}
if (child == content) {
if (postscript) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::subscript :
nsGkAtoms::superscript);
} else {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::presubscript :
nsGkAtoms::presuperscript);
}
break;
}
subscript = !subscript;
}
}
}
} break;
default:
break;
}
}
}
already_AddRefed<nsIPersistentProperties>
HyperTextAccessible::NativeAttributes()
{
@ -976,8 +1116,11 @@ HyperTextAccessible::NativeAttributes()
}
}
if (HasOwnContent())
if (HasOwnContent()) {
GetAccService()->MarkupAttributes(mContent, attributes);
if (mContent->IsMathMLElement())
SetMathMLXMLRoles(attributes);
}
return attributes.forget();
}

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

@ -561,6 +561,12 @@ protected:
uint32_t* aStartOffset, uint32_t* aEndOffset,
nsIPersistentProperties* aAttributes);
/**
* Set xml-roles attributes for MathML elements.
* @param aAttributes
*/
void SetMathMLXMLRoles(nsIPersistentProperties* aAttributes);
private:
/**
* End text offsets array.

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

@ -1652,6 +1652,24 @@ DocAccessibleChild::RecvEmbeddedChildAt(const uint64_t& aID,
return true;
}
bool
DocAccessibleChild::RecvFocusedChild(const uint64_t& aID,
uint64_t* aChild,
bool* aOk)
{
*aChild = 0;
*aOk = false;
Accessible* acc = IdToAccessible(aID);
if (acc) {
Accessible* child = acc->FocusedChild();
if (child) {
*aChild = reinterpret_cast<uint64_t>(child->UniqueID());
*aOk = true;
}
}
return true;
}
bool
DocAccessibleChild::RecvChildAtPoint(const uint64_t& aID,
const int32_t& aX,

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

@ -411,6 +411,10 @@ public:
virtual bool RecvEmbeddedChildAt(const uint64_t& aID, const uint32_t& aIdx,
uint64_t* aChildID) override final;
virtual bool RecvFocusedChild(const uint64_t& aID,
uint64_t* aChild,
bool* aOk) override;
virtual bool RecvChildAtPoint(const uint64_t& aID,
const int32_t& aX,
const int32_t& aY,

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

@ -222,6 +222,8 @@ child:
returns(uint32_t childIdx);
prio(high) sync EmbeddedChildAt(uint64_t aID, uint32_t aChildIdx)
returns(uint64_t aChild);
prio(high) sync FocusedChild(uint64_t aID)
returns(uint64_t aChild, bool aOk);
prio(high) sync ChildAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aWhich)
returns(uint64_t aChild, bool aOk);
prio(high) sync Bounds(uint64_t aID) returns(nsIntRect aRect);

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

@ -520,15 +520,27 @@ ProxyAccessible::RowExtent()
}
void
ProxyAccessible::ColHeaderCells(nsTArray<uint64_t>* aCells)
ProxyAccessible::ColHeaderCells(nsTArray<ProxyAccessible*>* aCells)
{
unused << mDoc->SendColHeaderCells(mID, aCells);
nsTArray<uint64_t> targetIDs;
unused << mDoc->SendColHeaderCells(mID, &targetIDs);
size_t targetCount = targetIDs.Length();
for (size_t i = 0; i < targetCount; i++) {
aCells->AppendElement(mDoc->GetAccessible(targetIDs[i]));
}
}
void
ProxyAccessible::RowHeaderCells(nsTArray<uint64_t>* aCells)
ProxyAccessible::RowHeaderCells(nsTArray<ProxyAccessible*>* aCells)
{
unused << mDoc->SendRowHeaderCells(mID, aCells);
nsTArray<uint64_t> targetIDs;
unused << mDoc->SendRowHeaderCells(mID, &targetIDs);
size_t targetCount = targetIDs.Length();
for (size_t i = 0; i < targetCount; i++) {
aCells->AppendElement(mDoc->GetAccessible(targetIDs[i]));
}
}
bool
@ -924,6 +936,15 @@ ProxyAccessible::EmbeddedChildAt(size_t aChildIdx)
return mDoc->GetAccessible(childID);
}
ProxyAccessible*
ProxyAccessible::FocusedChild()
{
uint64_t childID = 0;
bool ok = false;
unused << mDoc->SendFocusedChild(mID, &childID, &ok);
return ok ? mDoc->GetAccessible(childID) : nullptr;
}
ProxyAccessible*
ProxyAccessible::ChildAtPoint(int32_t aX, int32_t aY,
Accessible::EWhichChildAtPoint aWhichChild)

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

@ -194,6 +194,12 @@ public:
bool IsLinkValid();
// XXX checking mRole alone may not result in same behavior as Accessibles
// due to ARIA roles
inline bool IsTable() const { return mRole == roles::TABLE; }
inline bool IsTableRow() const { return mRole == roles::ROW; }
inline bool IsTableCell() const { return mRole == roles::CELL; }
uint32_t AnchorCount(bool* aOk);
void AnchorURIAt(uint32_t aIndex, nsCString& aURI, bool* aOk);
@ -218,9 +224,9 @@ public:
uint32_t RowExtent();
void ColHeaderCells(nsTArray<uint64_t>* aCells);
void ColHeaderCells(nsTArray<ProxyAccessible*>* aCells);
void RowHeaderCells(nsTArray<uint64_t>* aCells);
void RowHeaderCells(nsTArray<ProxyAccessible*>* aCells);
bool IsCellSelected();
@ -277,6 +283,7 @@ public:
double Step();
void TakeFocus();
ProxyAccessible* FocusedChild();
ProxyAccessible* ChildAtPoint(int32_t aX, int32_t aY,
Accessible::EWhichChildAtPoint aWhichChild);
nsIntRect Bounds();

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

@ -40,4 +40,6 @@ LOCAL_INCLUDES += [
FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')
FAIL_ON_WARNINGS = True

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

@ -18,6 +18,7 @@
#include "RootAccessible.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "mozilla/a11y/PDocAccessible.h"
#include "mozilla/Services.h"
#include "nsRect.h"
@ -211,9 +212,14 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
// unknown (either unimplemented, or irrelevant) elements are marked as ignored
// as well as expired elements.
AccessibleWrap* accWrap = [self getGeckoAccessible];
return !accWrap || ([[self role] isEqualToString:NSAccessibilityUnknownRole] &&
!(accWrap->InteractiveState() & states::FOCUSABLE));
bool noRole = [[self role] isEqualToString:NSAccessibilityUnknownRole];
if (AccessibleWrap* accWrap = [self getGeckoAccessible])
return (noRole && !(accWrap->InteractiveState() & states::FOCUSABLE));
if (ProxyAccessible* proxy = [self getProxyAccessible])
return (noRole && !(proxy->State() & states::FOCUSABLE));
return true;
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
}
@ -269,7 +275,8 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
// if we're expired, we don't support any attributes.
AccessibleWrap* accWrap = [self getGeckoAccessible];
if (!accWrap)
ProxyAccessible* proxy = [self getProxyAccessible];
if (!accWrap && !proxy)
return [NSArray array];
static NSArray* generalAttributes = nil;
@ -328,11 +335,11 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
NSArray* objectAttributes = generalAttributes;
if (accWrap->IsTable())
if ((accWrap && accWrap->IsTable()) || (proxy && proxy->IsTable()))
objectAttributes = tableAttrs;
else if (accWrap->IsTableRow())
else if ((accWrap && accWrap->IsTableRow()) || (proxy && proxy->IsTableRow()))
objectAttributes = tableRowAttrs;
else if (accWrap->IsTableCell())
else if ((accWrap && accWrap->IsTableCell()) || (proxy && proxy->IsTableCell()))
objectAttributes = tableCellAttrs;
NSArray* additionalAttributes = [self additionalAccessibilityAttributeNames];
@ -364,7 +371,8 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
AccessibleWrap* accWrap = [self getGeckoAccessible];
if (!accWrap)
ProxyAccessible* proxy = [self getProxyAccessible];
if (!accWrap && !proxy)
return nil;
#if DEBUG
@ -406,62 +414,117 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
if ([attribute isEqualToString:NSAccessibilityTitleAttribute])
return [self title];
if ([attribute isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
Relation rel =
accWrap->RelationByType(RelationType::LABELLED_BY);
Accessible* tempAcc = rel.Next();
return tempAcc ? GetNativeFromGeckoAccessible(tempAcc) : nil;
if (accWrap) {
Relation rel = accWrap->RelationByType(RelationType::LABELLED_BY);
Accessible* tempAcc = rel.Next();
return tempAcc ? GetNativeFromGeckoAccessible(tempAcc) : nil;
}
nsTArray<ProxyAccessible*> rel = proxy->RelationByType(RelationType::LABELLED_BY);
ProxyAccessible* tempProxy = rel.SafeElementAt(0);
return tempProxy ? GetNativeFromProxy(tempProxy) : nil;
}
if ([attribute isEqualToString:NSAccessibilityHelpAttribute])
return [self help];
if (accWrap->IsTable()) {
TableAccessible* table = accWrap->AsTable();
if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
return @(table->RowCount());
if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
return @(table->ColCount());
if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
// Create a new array with the list of table rows.
NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
uint32_t totalCount = accWrap->ChildCount();
for (uint32_t i = 0; i < totalCount; i++) {
if (accWrap->GetChildAt(i)->IsTableRow()) {
mozAccessible* curNative =
GetNativeFromGeckoAccessible(accWrap->GetChildAt(i));
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
if (accWrap) {
if (accWrap->IsTable()) {
TableAccessible* table = accWrap->AsTable();
if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
return @(table->RowCount());
if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
return @(table->ColCount());
if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
// Create a new array with the list of table rows.
NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
uint32_t totalCount = accWrap->ChildCount();
for (uint32_t i = 0; i < totalCount; i++) {
if (accWrap->GetChildAt(i)->IsTableRow()) {
mozAccessible* curNative =
GetNativeFromGeckoAccessible(accWrap->GetChildAt(i));
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
}
}
return nativeArray;
}
return nativeArray;
}
} else if (accWrap->IsTableRow()) {
if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
// Count the number of rows before that one to obtain the row index.
uint32_t index = 0;
for (int32_t i = accWrap->IndexInParent() - 1; i >= 0; i--) {
if (accWrap->GetChildAt(i)->IsTableRow()) {
index++;
} else if (accWrap->IsTableRow()) {
if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
// Count the number of rows before that one to obtain the row index.
uint32_t index = 0;
for (int32_t i = accWrap->IndexInParent() - 1; i >= 0; i--) {
if (accWrap->GetChildAt(i)->IsTableRow()) {
index++;
}
}
return [NSNumber numberWithUnsignedInteger:index];
}
} else if (accWrap->IsTableCell()) {
TableCellAccessible* cell = accWrap->AsTableCell();
if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
cell->RowExtent())];
if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
cell->ColExtent())];
if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
nsAutoTArray<Accessible*, 10> headerCells;
cell->RowHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
}
if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
nsAutoTArray<Accessible*, 10> headerCells;
cell->ColHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
}
return [NSNumber numberWithUnsignedInteger:index];
}
} else if (accWrap->IsTableCell()) {
TableCellAccessible* cell = accWrap->AsTableCell();
if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
cell->RowExtent())];
if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
cell->ColExtent())];
if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
nsAutoTArray<Accessible*, 10> headerCells;
cell->RowHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
}
if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
nsAutoTArray<Accessible*, 10> headerCells;
cell->ColHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
} else if (proxy) {
if (proxy->IsTable()) {
if ([attribute isEqualToString:NSAccessibilityRowCountAttribute])
return @(proxy->TableRowCount());
if ([attribute isEqualToString:NSAccessibilityColumnCountAttribute])
return @(proxy->TableColumnCount());
if ([attribute isEqualToString:NSAccessibilityRowsAttribute]) {
// Create a new array with the list of table rows.
NSMutableArray* nativeArray = [[NSMutableArray alloc] init];
uint32_t totalCount = proxy->ChildrenCount();
for (uint32_t i = 0; i < totalCount; i++) {
if (proxy->ChildAt(i)->IsTableRow()) {
mozAccessible* curNative =
GetNativeFromProxy(proxy->ChildAt(i));
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
}
}
return nativeArray;
}
} else if (proxy->IsTableRow()) {
if ([attribute isEqualToString:NSAccessibilityIndexAttribute]) {
// Count the number of rows before that one to obtain the row index.
uint32_t index = 0;
for (int32_t i = proxy->IndexInParent() - 1; i >= 0; i--) {
if (proxy->ChildAt(i)->IsTableRow()) {
index++;
}
}
return [NSNumber numberWithUnsignedInteger:index];
}
} else if (proxy->IsTableCell()) {
if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(),
proxy->RowExtent())];
if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
return [NSValue valueWithRange:NSMakeRange(proxy->ColIdx(),
proxy->ColExtent())];
if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
nsTArray<ProxyAccessible*> headerCells;
proxy->RowHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
}
if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
nsTArray<ProxyAccessible*> headerCells;
proxy->ColHeaderCells(&headerCells);
return ConvertToNSArray(headerCells);
}
}
}
@ -490,9 +553,20 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
// Per the MathML 3 spec, the latter happens iff the linethickness
// attribute is of the form [zero-float][optional-unit]. In that case we
// set line thickness to zero and in the other cases we set it to one.
nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
nsAutoString thickness;
nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
if (accWrap) {
nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
} else {
nsAutoTArray<Attribute, 10> attrs;
proxy->Attributes(&attrs);
for (size_t i = 0 ; i < attrs.Length() ; i++) {
if (attrs.ElementAt(i).Name() == "thickness") {
thickness = attrs.ElementAt(i).Value();
break;
}
}
}
double value = 1.0;
if (!thickness.IsEmpty())
value = PR_strtod(NS_LossyConvertUTF16toASCII(thickness).get(),
@ -606,7 +680,8 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
- (id)accessibilityHitTest:(NSPoint)point
{
AccessibleWrap* accWrap = [self getGeckoAccessible];
if (!accWrap)
ProxyAccessible* proxy = [self getProxyAccessible];
if (!accWrap && !proxy)
return nil;
// Convert the given screen-global point in the cocoa coordinate system (with
@ -618,16 +693,22 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
nsIntPoint geckoPoint = nsCocoaUtils::
CocoaPointsToDevPixels(tmpPoint, nsCocoaUtils::GetBackingScaleFactor(mainView));
Accessible* child =
accWrap->ChildAtPoint(geckoPoint.x, geckoPoint.y,
Accessible::eDeepestChild);
if (child) {
mozAccessible* nativeChild = GetNativeFromGeckoAccessible(child);
if (nativeChild)
return GetClosestInterestingAccessible(nativeChild);
mozAccessible* nativeChild = nil;
if (accWrap) {
Accessible* child = accWrap->ChildAtPoint(geckoPoint.x, geckoPoint.y,
Accessible::eDeepestChild);
if (child)
nativeChild = GetNativeFromGeckoAccessible(child);
} else if (proxy) {
ProxyAccessible* child = proxy->ChildAtPoint(geckoPoint.x, geckoPoint.y,
Accessible::eDeepestChild);
if (child)
nativeChild = GetNativeFromProxy(child);
}
if (nativeChild)
return GetClosestInterestingAccessible(nativeChild);
// if we didn't find anything, return ourself (or the first unignored ancestor).
return GetClosestInterestingAccessible(self);
}
@ -651,16 +732,24 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
- (id)accessibilityFocusedUIElement
{
AccessibleWrap* accWrap = [self getGeckoAccessible];
if (!accWrap)
ProxyAccessible* proxy = [self getProxyAccessible];
if (!accWrap && !proxy)
return nil;
Accessible* focusedGeckoChild = accWrap->FocusedChild();
if (focusedGeckoChild) {
mozAccessible *focusedChild = GetNativeFromGeckoAccessible(focusedGeckoChild);
if (focusedChild)
return GetClosestInterestingAccessible(focusedChild);
mozAccessible* focusedChild = nil;
if (accWrap) {
Accessible* focusedGeckoChild = accWrap->FocusedChild();
if (focusedGeckoChild)
focusedChild = GetNativeFromGeckoAccessible(focusedGeckoChild);
} else if (proxy) {
ProxyAccessible* focusedGeckoChild = proxy->FocusedChild();
if (focusedGeckoChild)
focusedChild = GetNativeFromProxy(focusedGeckoChild);
}
if (focusedChild)
return GetClosestInterestingAccessible(focusedChild);
// return ourself if we can't get a native focused child.
return GetClosestInterestingAccessible(self);
}

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

@ -78,7 +78,7 @@ enum CheckboxValue {
- (BOOL)accessibilityIsIgnored
{
return ![self getGeckoAccessible];
return ![self getGeckoAccessible] && ![self getProxyAccessible];
}
- (NSArray*)accessibilityActionNames

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

@ -55,7 +55,7 @@ ToNSString(id aValue)
- (BOOL)accessibilityIsIgnored
{
return ![self getGeckoAccessible];
return ![self getGeckoAccessible] && ![self getProxyAccessible];
}
- (NSArray*)accessibilityAttributeNames

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

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>XML landmark tests</title>
<title>XML roles tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
@ -36,6 +36,60 @@
testAttrs("search", {"xml-roles" : "searchbox"}, true);
testAttrs("open-1", {"xml-roles" : "open-fence"}, true);
testAttrs("open-2", {"xml-roles" : "open-fence"}, true);
testAttrs("open-3", {"xml-roles" : "open-fence"}, true);
testAttrs("open-4", {"xml-roles" : "open-fence"}, true);
testAttrs("open-5", {"xml-roles" : "open-fence"}, true);
testAttrs("open-6", {"xml-roles" : "open-fence"}, true);
testAttrs("open-7", {"xml-roles" : "open-fence"}, true);
testAttrs("sep-1", {"xml-roles" : "separator"}, true);
testAttrs("sep-2", {"xml-roles" : "separator"}, true);
testAttrs("sep-3", {"xml-roles" : "separator"}, true);
testAttrs("sep-4", {"xml-roles" : "separator"}, true);
testAttrs("sep-5", {"xml-roles" : "separator"}, true);
testAttrs("sep-6", {"xml-roles" : "separator"}, true);
testAttrs("sep-7", {"xml-roles" : "separator"}, true);
testAttrs("close-1", {"xml-roles" : "close-fence"}, true);
testAttrs("close-2", {"xml-roles" : "close-fence"}, true);
testAttrs("close-3", {"xml-roles" : "close-fence"}, true);
testAttrs("close-4", {"xml-roles" : "close-fence"}, true);
testAttrs("close-5", {"xml-roles" : "close-fence"}, true);
testAttrs("close-6", {"xml-roles" : "close-fence"}, true);
testAttrs("close-7", {"xml-roles" : "close-fence"}, true);
testAttrs("num", {"xml-roles" : "numerator"}, true);
testAttrs("den", {"xml-roles" : "denominator"}, true);
testAttrs("sub-1", {"xml-roles" : "subscript"}, true);
testAttrs("sub-2", {"xml-roles" : "subscript"}, true);
testAttrs("sub-3", {"xml-roles" : "subscript"}, true);
testAttrs("sup-1", {"xml-roles" : "superscript"}, true);
testAttrs("sup-2", {"xml-roles" : "superscript"}, true);
testAttrs("sup-3", {"xml-roles" : "superscript"}, true);
testAttrs("sup-4", {"xml-roles" : "superscript"}, true);
testAttrs("presub-1", {"xml-roles" : "presubscript"}, true);
testAttrs("presub-2", {"xml-roles" : "presubscript"}, true);
testAttrs("presup-1", {"xml-roles" : "presuperscript"}, true);
testAttrs("under-1", {"xml-roles" : "underscript"}, true);
testAttrs("under-2", {"xml-roles" : "underscript"}, true);
testAttrs("over-1", {"xml-roles" : "overscript"}, true);
testAttrs("over-2", {"xml-roles" : "overscript"}, true);
testAttrs("root-index-1", {"xml-roles" : "root-index"}, true);
testAttrs("base-1", {"xml-roles" : "base"}, true);
testAttrs("base-2", {"xml-roles" : "base"}, true);
testAttrs("base-3", {"xml-roles" : "base"}, true);
testAttrs("base-4", {"xml-roles" : "base"}, true);
testAttrs("base-5", {"xml-roles" : "base"}, true);
testAttrs("base-6", {"xml-roles" : "base"}, true);
testAttrs("base-7", {"xml-roles" : "base"}, true);
testAttrs("base-8", {"xml-roles" : "base"}, true);
SimpleTest.finish();
}
@ -109,5 +163,87 @@
<main id="main_element">another main area</main>
<input id="search" type="search"/>
<!-- open-fence, separator, close-fence -->
<math><mo id="open-1">(</mo><mi>x</mi><mo id="sep-1">,</mo><mi>y</mi><mo id="close-1">)</mo></math>
<math><mrow><mo id="open-2">(</mo><mi>x</mi><mo id="sep-2">,</mo><mi>y</mi><mo id="close-2">)</mo></mrow></math>
<math><mstyle><mo id="open-3">(</mo><mi>x</mi><mo id="sep-3">,</mo><mi>y</mi><mo id="close-3">)</mo></mstyle></math>
<math><msqrt><mo id="open-4">(</mo><mi>x</mi><mo id="sep-4">,</mo><mi>y</mi><mo id="close-4">)</mo></msqrt></math>
<math><menclose><mo id="open-5">(</mo><mi>x</mi><mo id="sep-5">,</mo><mi>y</mi><mo id="close-5">)</mo></menclose></math>
<math><merror><mo id="open-6">(</mo><mi>x</mi><mo id="sep-6">,</mo><mi>y</mi><mo id="close-6">)</mo></merror></math>
<math><mtable><mtr><mtd><mo id="open-7">(</mo><mi>x</mi><mo id="sep-7">,</mo><mi>y</mi><mo id="close-7">)</mo></mtd></mtr></mtable></math>
<!-- numerator, denominator -->
<math>
<mfrac>
<mi id="num">a</mi>
<mi id="den">b</mi>
</mfrac>
</math>
<!-- subscript, superscript, presubscript, presuperscript -->
<math>
<msub>
<mi id="base-1">a</mi>
<mi id="sub-1">b</mi>
</msub>
</math>
<math>
<msup>
<mi id="base-2">a</mi>
<mi id="sup-1">b</mi>
</msup>
</math>
<math>
<msubsup>
<mi id="base-3">a</mi>
<mi id="sub-2">b</mi>
<mi id="sup-2">c</mi>
</msubsup>
</math>
<math>
<mmultiscripts>
<mi id="base-4">a</mi>
<mi id="sub-3">b</mi>
<mi id="sup-3">c</mi>
<none/>
<mi id="sup-4">d</mi>
<mprescripts/>
<mi id="presub-1">e</mi>
<none/>
<mi id="presub-2">f</mi>
<mi id="presup-1">g</mi>
</mmultiscripts>
</math>
<!-- underscript, overscript -->
<math>
<munder>
<mi id="base-5">a</mi>
<mi id="under-1">b</mi>
</munder>
</math>
<math>
<mover>
<mi id="base-6">a</mi>
<mi id="over-1">b</mi>
</mover>
</math>
<math>
<munderover>
<mi id="base-7">a</mi>
<mi id="under-2">b</mi>
<mi id="over-2">c</mi>
</munderover>
</math>
<!-- root-index -->
<math>
<mroot>
<mi id="base-8">a</mi>
<mi id="root-index-1">b</mi>
</mroot>
</math>
</body>
</html>

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

@ -8,7 +8,13 @@ include $(topsrcdir)/config/rules.mk
MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in
MOZ_PKG_MANIFEST = $(srcdir)/package-manifest.in
ifdef MOZ_CHROME_MULTILOCALE
MOZ_PKG_MANIFEST_DEPS = locale-manifest.in
DEFINES += -DPKG_LOCALE_MANIFEST=$(CURDIR)/locale-manifest.in
endif
DEFINES += \
-DMOZ_APP_NAME=$(MOZ_APP_NAME) \
@ -42,10 +48,6 @@ ifdef ENABLE_MARIONETTE
DEFINES += -DENABLE_MARIONETTE=1
endif
ifdef MOZ_PKG_MANIFEST_P
MOZ_PKG_MANIFEST = package-manifest
endif
MOZ_PACKAGER_MINIFY=1
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
@ -107,19 +109,16 @@ DEFINES += -DMOZ_GTK3=1
endif
endif
ifdef MOZ_PKG_MANIFEST_P
$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) FORCE
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@)
ifdef MOZ_CHROME_MULTILOCALE
printf '\n[multilocale]\n' >> $@
locale-manifest.in: $(GLOBAL_DEPS) FORCE
printf '\n[multilocale]\n' > $@
for LOCALE in $(MOZ_CHROME_MULTILOCALE) ;\
do \
printf '$(BINPATH)/chrome/'"$$LOCALE"'$(JAREXT)\n' >> $@; \
printf '$(BINPATH)/chrome/'"$$LOCALE"'.manifest\n' >> $@; \
done
endif
GARBAGE += $(MOZ_PKG_MANIFEST)
GARBAGE += locale-manifest.in
endif
ifdef FXOS_SIMULATOR

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

@ -980,3 +980,7 @@ bin/libfreebl_32int64_3.so
@RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
@RESPATH@/gmp-clearkey/0.1/clearkey.info
#endif
#ifdef PKG_LOCALE_MANIFEST
#include @PKG_LOCALE_MANIFEST@
#endif

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

@ -1,21 +1,21 @@
# This file has default permissions for the permission manager.
# The file-format is strict:
# * matchtype \t type \t permission \t host
# * Only "host" is supported for matchtype
# * "origin" should be used for matchtype, "host" is supported for legacy reasons
# * type is a string that identifies the type of permission (e.g. "cookie")
# * permission is an integer between 1 and 15
# See nsPermissionManager.cpp for more...
# UITour
host uitour 1 www.mozilla.org
host uitour 1 self-repair.mozilla.org
host uitour 1 support.mozilla.org
host uitour 1 about:home
origin uitour 1 https://www.mozilla.org
origin uitour 1 https://self-repair.mozilla.org
origin uitour 1 https://support.mozilla.org
origin uitour 1 about:home
# XPInstall
host install 1 addons.mozilla.org
host install 1 marketplace.firefox.com
origin install 1 https://addons.mozilla.org
origin install 1 https://marketplace.firefox.com
# Remote troubleshooting
host remote-troubleshooting 1 input.mozilla.org
host remote-troubleshooting 1 support.mozilla.org
origin remote-troubleshooting 1 https://input.mozilla.org
origin remote-troubleshooting 1 https://support.mozilla.org

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

@ -44,14 +44,14 @@ var gPluginHandler = {
switch (msg.name) {
case "PluginContent:ShowClickToPlayNotification":
this.showClickToPlayNotification(msg.target, msg.data.plugins, msg.data.showNow,
msg.principal, msg.data.host, msg.data.location);
msg.principal, msg.data.location);
break;
case "PluginContent:RemoveNotification":
this.removeNotification(msg.target, msg.data.name);
break;
case "PluginContent:UpdateHiddenPluginUI":
this.updateHiddenPluginUI(msg.target, msg.data.haveInsecure, msg.data.actions,
msg.principal, msg.data.host, msg.data.location);
msg.principal, msg.data.location);
break;
case "PluginContent:HideNotificationBar":
this.hideNotificationBar(msg.target, msg.data.name);
@ -216,8 +216,8 @@ var gPluginHandler = {
});
},
showClickToPlayNotification: function (browser, plugins, showNow, principal,
host, location) {
showClickToPlayNotification: function (browser, plugins, showNow,
principal, location) {
// It is possible that we've received a message from the frame script to show
// a click to play notification for a principal that no longer matches the one
// that the browser's content now has assigned (ie, the browser has browsed away
@ -295,7 +295,6 @@ var gPluginHandler = {
primaryPlugin: primaryPluginPermission,
pluginData: pluginData,
principal: principal,
host: host,
};
PopupNotifications.show(browser, "click-to-play-plugins",
"", "plugins-notification-icon",
@ -316,8 +315,10 @@ var gPluginHandler = {
notificationBox.removeNotification(notification, true);
},
updateHiddenPluginUI: function (browser, haveInsecure, actions, principal,
host, location) {
updateHiddenPluginUI: function (browser, haveInsecure, actions,
principal, location) {
let origin = principal.originNoSuffix;
// It is possible that we've received a message from the frame script to show
// the hidden plugin notification for a principal that no longer matches the one
// that the browser's content now has assigned (ie, the browser has browsed away
@ -380,22 +381,22 @@ var gPluginHandler = {
case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
message = gNavigatorBundle.getFormattedString(
"pluginActivateNew.message",
[pluginName, host]);
[pluginName, origin]);
break;
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
message = gNavigatorBundle.getFormattedString(
"pluginActivateOutdated.message",
[pluginName, host, brand]);
[pluginName, origin, brand]);
break;
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
message = gNavigatorBundle.getFormattedString(
"pluginActivateVulnerable.message",
[pluginName, host, brand]);
[pluginName, origin, brand]);
}
} else {
// Multi-plugin
message = gNavigatorBundle.getFormattedString(
"pluginActivateMultiple.message", [host]);
"pluginActivateMultiple.message", [origin]);
}
let buttons = [

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

@ -99,7 +99,11 @@ let TrackingProtection = {
// Remove the current host from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI,
let normalizedUrl = Services.io.newURI(
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
null, null);
Services.perms.remove(normalizedUrl,
"trackingprotection");
// Telemetry for enable protection.

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

@ -1422,6 +1422,20 @@ var gBrowserInit = {
this.gmpInstallManager.simpleCheckAndInstall().then(null, () => {});
}, 1000 * 60);
// Report via telemetry whether we're able to play MP4/H.264/AAC video.
// We suspect that some Windows users have a broken or have not installed
// Windows Media Foundation, and we'd like to know how many. We'd also like
// to know how good our coverage is on other platforms.
// Note: we delay by 90 seconds reporting this, as calling canPlayType()
// on Windows will cause DLLs to load, i.e. cause disk I/O.
setTimeout(() => {
let v = document.createElementNS("http://www.w3.org/1999/xhtml", "video");
let aacWorks = v.canPlayType("audio/mp4") != "";
Services.telemetry.getHistogramById("VIDEO_CAN_CREATE_AAC_DECODER").add(aacWorks);
let h264Works = v.canPlayType("video/mp4") != "";
Services.telemetry.getHistogramById("VIDEO_CAN_CREATE_H264_DECODER").add(h264Works);
}, 90 * 1000);
SessionStore.promiseInitialized.then(() => {
// Bail out if the window has been closed in the meantime.
if (window.closed) {

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

@ -1117,8 +1117,9 @@ var imagePermissionObserver = {
var row = getSelectedRow(imageTree);
var item = gImageView.data[row][COL_IMAGE_NODE];
var url = gImageView.data[row][COL_IMAGE_ADDRESS];
if (makeURI(url).host == permission.host)
if (permission.matchesURI(makeURI(url), true)) {
makeBlockImage(url);
}
}
}
}

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

@ -18,7 +18,7 @@ var permissionObserver = {
{
if (aTopic == "perm-changed") {
var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
if (permission.host == gPermURI.host) {
if (permission.matchesURI(gPermURI, true)) {
if (gPermissions.indexOf(permission.type) > -1)
initRow(permission.type);
else if (permission.type.startsWith("plugin"))
@ -35,7 +35,7 @@ function onLoadPermission()
if (SitePermissions.isSupportedURI(uri)) {
gPermURI = uri;
var hostText = document.getElementById("hostText");
hostText.value = gPermURI.host;
hostText.value = gPermURI.prePath;
for (var i of gPermissions)
initRow(i);

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

@ -1926,7 +1926,7 @@
}
if (animate) {
mozRequestAnimationFrame(function () {
requestAnimationFrame(function () {
this.tabContainer._handleTabTelemetryStart(t, aURI);
// kick the animation off

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

@ -7,7 +7,7 @@ function test() {
isnot(tab.getAttribute("fadein"), "true", "newly opened tab is yet to fade in");
// Try to remove the tab right before the opening animation's first frame
window.mozRequestAnimationFrame(checkAnimationState);
window.requestAnimationFrame(checkAnimationState);
}
function checkAnimationState() {

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

@ -47,7 +47,7 @@ function test_install_lwtheme() {
is(LightweightThemeManager.currentTheme, null, "Should be no lightweight theme selected");
var pm = Services.perms;
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
pm.add(makeURI("https://example.com/"), "install", pm.ALLOW_ACTION);
gBrowser.selectedTab = gBrowser.addTab("https://example.com/browser/browser/base/content/test/general/bug592338.html");
gBrowser.selectedBrowser.addEventListener("pageshow", function() {

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

@ -80,7 +80,7 @@ add_task(function* () {
utils.sendMouseEvent("mousedown", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
return plugin && !overlay.classList.contains("visible");
return overlay.hasAttribute("dismissed") && !overlay.classList.contains("visible");
});
let notification = PopupNotifications.getNotification("click-to-play-plugins");

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

@ -238,7 +238,7 @@ function clearAllPluginPermissions() {
while (perms.hasMoreElements()) {
let perm = perms.getNext();
if (perm.type.startsWith('plugin')) {
info("removing permission:" + perm.host + " " + perm.type + "\n");
info("removing permission:" + perm.principal.origin + " " + perm.type + "\n");
Services.perms.removePermission(perm);
}
}

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

@ -2432,9 +2432,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
let normalizedUrl = Services.io.newURI(
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
null, null);
// Add the current host in the 'trackingprotection' consumer of
// Add the current host/port combination in the 'trackingprotection' consumer of
// the permission manager using a normalized URI. This effectively
// places this host on the tracking protection allowlist.
// places this host/port combination on the tracking protection allowlist.
Services.perms.add(normalizedUrl,
"trackingprotection", Services.perms.ALLOW_ACTION);
BrowserReload();
@ -2442,10 +2442,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
</method>
<method name="enableTrackingContentProtection">
<body><![CDATA[
// Remove the current host from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host
// Remove the current host/port combination from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host/port combination
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI,
let normalizedUrl = Services.io.newURI(
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
null, null);
Services.perms.remove(normalizedUrl,
"trackingprotection");
BrowserReload();
]]></body>
@ -2561,8 +2564,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
return;
}
let host = this.notification.options.host;
this._setupDescription("pluginActivateMultiple.message", null, host);
let prePath = this.notification.options.principal.URI.prePath;
this._setupDescription("pluginActivateMultiple.message", null, prePath);
var showBox = document.getAnonymousElementByAttribute(this, "anonid", "plugin-notification-showbox");
@ -2601,7 +2604,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<method name="_setupSingleState">
<body><![CDATA[
var action = this._items[0].action;
var host = action.pluginPermissionHost;
var prePath = action.pluginPermissionPrePath;
let label, linkLabel, linkUrl, button1, button2;
@ -2696,7 +2699,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
Cu.reportError(Error("Unexpected blocklist state"));
}
}
this._setupDescription(label, action.pluginName, host);
this._setupDescription(label, action.pluginName, prePath);
this._setupLink(linkLabel, action.detailsLink);
this._primaryButton.label = gNavigatorBundle.getString(button1.label);
@ -2717,7 +2720,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<method name="_setupDescription">
<parameter name="baseString" />
<parameter name="pluginName" /> <!-- null for the multiple-plugin case -->
<parameter name="host" />
<parameter name="prePath" />
<body><![CDATA[
var bsn = this._brandShortName;
var span = document.getAnonymousElementByAttribute(this, "anonid", "click-to-play-plugins-notification-description");
@ -2725,17 +2728,17 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
span.removeChild(span.lastChild);
}
var args = ["__host__", this._brandShortName];
var args = ["__prepath__", this._brandShortName];
if (pluginName) {
args.unshift(pluginName);
}
var bases = gNavigatorBundle.getFormattedString(baseString, args).
split("__host__", 2);
split("__prepath__", 2);
span.appendChild(document.createTextNode(bases[0]));
var hostSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em");
hostSpan.appendChild(document.createTextNode(host));
span.appendChild(hostSpan);
var prePathSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "em");
prePathSpan.appendChild(document.createTextNode(prePath));
span.appendChild(prePathSpan);
span.appendChild(document.createTextNode(bases[1] + " "));
]]></body>
</method>

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

@ -17,6 +17,9 @@ Cu.import("resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
let gSecMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager);
let gFaviconService = Cc["@mozilla.org/browser/favicon-service;1"].
getService(Ci.nsIFaviconService);
@ -26,7 +29,7 @@ let gPlacesDatabase = Cc["@mozilla.org/browser/nav-history-service;1"].
clone(true);
let gSitesStmt = gPlacesDatabase.createAsyncStatement(
"SELECT get_unreversed_host(rev_host) AS host " +
"SELECT url " +
"FROM moz_places " +
"WHERE rev_host > '.' " +
"AND visit_count > 0 " +
@ -46,14 +49,11 @@ let gVisitStmt = gPlacesDatabase.createAsyncStatement(
let TEST_EXACT_PERM_TYPES = ["geo", "camera", "microphone"];
/**
* Site object represents a single site, uniquely identified by a host.
* Site object represents a single site, uniquely identified by a principal.
*/
function Site(host) {
this.host = host;
function Site(principal) {
this.principal = principal;
this.listitem = null;
this.httpURI = NetUtil.newURI("http://" + this.host);
this.httpsURI = NetUtil.newURI("https://" + this.host);
}
Site.prototype = {
@ -75,16 +75,10 @@ Site.prototype = {
}
}
// Try to find favicon for both URIs, but always prefer the https favicon.
gFaviconService.getFaviconURLForPage(this.httpsURI, function (aURI) {
// Get the favicon for the origin
gFaviconService.getFaviconURLForPage(this.principal.URI, function (aURI) {
if (aURI) {
invokeCallback(aURI);
} else {
gFaviconService.getFaviconURLForPage(this.httpURI, function (aURI) {
if (aURI) {
invokeCallback(aURI);
}
});
}
}.bind(this));
},
@ -96,7 +90,9 @@ Site.prototype = {
* A function that takes the visit count (a number) as a parameter.
*/
getVisitCount: function Site_getVisitCount(aCallback) {
let rev_host = this.host.split("").reverse().join("") + ".";
// XXX This won't be a very reliable system, as it will count both http: and https: visits
// Unfortunately, I don't think that there is a much better way to do it right now.
let rev_host = this.principal.URI.host.split("").reverse().join("") + ".";
gVisitStmt.params.rev_host = rev_host;
gVisitStmt.executeAsync({
handleResult: function(aResults) {
@ -139,9 +135,9 @@ Site.prototype = {
let permissionValue;
if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) {
permissionValue = Services.perms.testPermission(this.httpURI, aType);
permissionValue = Services.perms.testPermissionFromPrincipal(this.principal, aType);
} else {
permissionValue = Services.perms.testExactPermission(this.httpURI, aType);
permissionValue = Services.perms.testExactPermissionFromPrincipal(this.principal, aType);
}
aResultObj.value = permissionValue;
@ -166,9 +162,7 @@ Site.prototype = {
return;
}
// Using httpURI is kind of bogus, but the permission manager stores the
// permission for the host, so the right thing happens in the end.
Services.perms.add(this.httpURI, aType, aPerm);
Services.perms.addFromPrincipal(this.principal, aType, aPerm);
},
/**
@ -179,7 +173,7 @@ Site.prototype = {
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
*/
clearPermission: function Site_clearPermission(aType) {
Services.perms.remove(this.httpURI, aType);
Services.perms.removeFromPrincipal(this.principal, aType);
},
/**
@ -189,13 +183,14 @@ Site.prototype = {
* @return An array of the cookies set for the site.
*/
get cookies() {
let host = this.principal.URI.host;
let cookies = [];
let enumerator = Services.cookies.getCookiesFromHost(this.host);
let enumerator = Services.cookies.getCookiesFromHost(host);
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
// getCookiesFromHost returns cookies for base domain, but we only want
// the cookies for the exact domain.
if (cookie.rawHost == this.host) {
if (cookie.rawHost == host) {
cookies.push(cookie);
}
}
@ -217,27 +212,27 @@ Site.prototype = {
* @return An array of the logins stored for the site.
*/
get logins() {
let httpLogins = Services.logins.findLogins({}, this.httpURI.prePath, "", "");
let httpsLogins = Services.logins.findLogins({}, this.httpsURI.prePath, "", "");
return httpLogins.concat(httpsLogins);
let logins = Services.logins.findLogins({}, this.principal.originNoSuffix, "", "");
return logins;
},
get loginSavingEnabled() {
// Only say that login saving is blocked if it is blocked for both http and https.
return Services.logins.getLoginSavingEnabled(this.httpURI.prePath) &&
Services.logins.getLoginSavingEnabled(this.httpsURI.prePath);
return Services.logins.getLoginSavingEnabled(this.principal.originNoSuffix);
},
set loginSavingEnabled(isEnabled) {
Services.logins.setLoginSavingEnabled(this.httpURI.prePath, isEnabled);
Services.logins.setLoginSavingEnabled(this.httpsURI.prePath, isEnabled);
Services.logins.setLoginSavingEnabled(this.principal.originNoSuffix, isEnabled);
},
/**
* Removes all data from the browser corresponding to the site.
*/
forgetSite: function Site_forgetSite() {
ForgetAboutSite.removeDataFromDomain(this.host);
// XXX This removes data for an entire domain, rather than just
// an origin. This may produce confusing results, as data will
// be cleared for the http:// as well as the https:// domain
// if you try to forget the https:// site.
ForgetAboutSite.removeDataFromDomain(this.principal.URI.host);
}
}
@ -366,7 +361,7 @@ let AboutPermissions = {
LIST_BUILD_DELAY: 100, // delay between intervals
/**
* Stores a mapping of host strings to Site objects.
* Stores a mapping of origin strings to Site objects.
*/
_sites: {},
@ -472,9 +467,9 @@ let AboutPermissions = {
break;
}
let permission = aSubject.QueryInterface(Ci.nsIPermission);
// We can't compare selectedSite.host and permission.host here because
// we need to handle the case where a parent domain was changed in a
// way that affects the subdomain.
// We can't compare selectedSite.principal and permission.principal here
// because we need to handle the case where a parent domain was changed
// in a way that affects the subdomain.
if (this._supportedPermissions.indexOf(permission.type) != -1) {
this.updatePermission(permission.type);
}
@ -512,8 +507,11 @@ let AboutPermissions = {
AboutPermissions.startSitesListBatch();
let row;
while (row = aResults.getNextRow()) {
let host = row.getResultByName("host");
AboutPermissions.addHost(host);
let spec = row.getResultByName("url");
let uri = NetUtil.newURI(spec);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
AboutPermissions.addPrincipal(principal);
}
AboutPermissions.endSitesListBatch();
},
@ -562,7 +560,8 @@ let AboutPermissions = {
try {
// aLogin.hostname is a string in origin URL format (e.g. "http://foo.com")
let uri = NetUtil.newURI(aLogin.hostname);
this.addHost(uri.host);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
this.addPrincipal(principal);
} catch (e) {
// newURI will throw for add-ons logins stored in chrome:// URIs
}
@ -577,7 +576,8 @@ let AboutPermissions = {
try {
// aHostname is a string in origin URL format (e.g. "http://foo.com")
let uri = NetUtil.newURI(aHostname);
this.addHost(uri.host);
let principal = gSecMan.getNoAppCodebasePrincipal(uri);
this.addPrincipal(principal);
} catch (e) {
// newURI will throw for add-ons logins stored in chrome:// URIs
}
@ -592,7 +592,7 @@ let AboutPermissions = {
let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
// Only include sites with exceptions set for supported permission types.
if (this._supportedPermissions.indexOf(permission.type) != -1) {
this.addHost(permission.host);
this.addPrincipal(permission.principal);
}
itemCnt++;
}
@ -603,15 +603,15 @@ let AboutPermissions = {
/**
* Creates a new Site and adds it to _sites if it's not already there.
*
* @param aHost
* A host string.
* @param aPrincipal
* A principal.
*/
addHost: function(aHost) {
if (aHost in this._sites) {
addPrincipal: function(aPrincipal) {
if (aPrincipal.origin in this._sites) {
return;
}
let site = new Site(aHost);
this._sites[aHost] = site;
let site = new Site(aPrincipal);
this._sites[aPrincipal.origin] = site;
this.addToSitesList(site);
},
@ -624,7 +624,7 @@ let AboutPermissions = {
addToSitesList: function(aSite) {
let item = document.createElement("richlistitem");
item.setAttribute("class", "site");
item.setAttribute("value", aSite.host);
item.setAttribute("value", aSite.principal.origin);
aSite.getFavicon(function(aURL) {
item.setAttribute("favicon", aURL);
@ -633,7 +633,7 @@ let AboutPermissions = {
// Make sure to only display relevant items when list is filtered
let filterValue = document.getElementById("sites-filter").value.toLowerCase();
item.collapsed = aSite.host.toLowerCase().indexOf(filterValue) == -1;
item.collapsed = aSite.principal.origin.toLowerCase().indexOf(filterValue) == -1;
(this._listFragment || this.sitesList).appendChild(item);
},
@ -686,16 +686,16 @@ let AboutPermissions = {
* The host string corresponding to the site to delete.
*/
deleteFromSitesList: function(aHost) {
for (let host in this._sites) {
let site = this._sites[host];
if (site.host.hasRootDomain(aHost)) {
for (let origin in this._sites) {
let site = this._sites[origin];
if (site.principal.URI.host.hasRootDomain(aHost)) {
if (site == this._selectedSite) {
// Replace site-specific interface with "All Sites" interface.
this.sitesList.selectedItem = document.getElementById("all-sites-item");
}
this.sitesList.removeChild(site.listitem);
delete this._sites[site.host];
delete this._sites[site.principal.origin];
}
}
},
@ -711,9 +711,9 @@ let AboutPermissions = {
return;
}
let host = event.target.value;
let site = this._selectedSite = this._sites[host];
document.getElementById("site-label").value = host;
let origin = event.target.value;
let site = this._selectedSite = this._sites[origin];
document.getElementById("site-label").value = origin;
document.getElementById("header-deck").selectedPanel =
document.getElementById("site-header");
@ -768,9 +768,9 @@ let AboutPermissions = {
// If there is no selected site, we are updating the default permissions interface.
permissionValue = PermissionDefaults[aType];
if (aType == "cookie")
// cookie-9 corresponds to ALLOW_FIRST_PARTY_ONLY, which is reserved
// for site-specific preferences only.
document.getElementById("cookie-9").hidden = true;
// cookie-9 corresponds to ALLOW_FIRST_PARTY_ONLY, which is reserved
// for site-specific preferences only.
document.getElementById("cookie-9").hidden = true;
} else {
if (aType == "cookie")
document.getElementById("cookie-9").hidden = false;
@ -825,18 +825,18 @@ let AboutPermissions = {
* Opens password manager dialog.
*/
managePasswords: function() {
let selectedHost = "";
let selectedOrigin = "";
if (this._selectedSite) {
selectedHost = this._selectedSite.host;
selectedOrigin = this._selectedSite.principal.URI.prePath;
}
let win = Services.wm.getMostRecentWindow("Toolkit:PasswordManager");
if (win) {
win.setFilter(selectedHost);
win.setFilter(selectedOrigin);
win.focus();
} else {
window.openDialog("chrome://passwordmgr/content/passwordManager.xul",
"Toolkit:PasswordManager", "", {filterString : selectedHost});
"Toolkit:PasswordManager", "", {filterString : selectedOrigin});
}
},
@ -877,9 +877,11 @@ let AboutPermissions = {
* Opens cookie manager dialog.
*/
manageCookies: function() {
// Cookies are stored by-host, and thus we filter the cookie window
// using only the host of the selected principal's origin
let selectedHost = "";
if (this._selectedSite) {
selectedHost = this._selectedSite.host;
selectedHost = this._selectedSite.principal.URI.host;
}
let win = Services.wm.getMostRecentWindow("Browser:Cookies");

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

@ -9,6 +9,7 @@ Components.utils.import("resource://gre/modules/ctypes.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
var gAdvancedPane = {
_inited: false,
@ -471,7 +472,7 @@ var gAdvancedPane = {
var usage = 0;
for (var i = 0; i < groups.length; i++) {
var uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == perm.host) {
if (perm.matchesURI(uri, true)) {
var cache = cacheService.getActiveCache(groups[i]);
usage += cache.usage;
}
@ -508,7 +509,7 @@ var gAdvancedPane = {
var row = document.createElement("listitem");
row.id = "";
row.className = "offlineapp";
row.setAttribute("host", perm.host);
row.setAttribute("origin", perm.principal.origin);
var converted = DownloadUtils.
convertByteUnits(this._getOfflineAppUsage(perm, groups));
row.setAttribute("usage",
@ -534,7 +535,8 @@ var gAdvancedPane = {
{
var list = document.getElementById("offlineAppsList");
var item = list.selectedItem;
var host = item.getAttribute("host");
var origin = item.getAttribute("origin");
var principal = BrowserUtils.principalFromOrigin(origin);
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
@ -543,13 +545,18 @@ var gAdvancedPane = {
var bundle = document.getElementById("bundlePreferences");
var title = bundle.getString("offlineAppRemoveTitle");
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]);
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [principal.URI.prePath]);
var confirm = bundle.getString("offlineAppRemoveConfirm");
var result = prompts.confirmEx(window, title, prompt, flags, confirm,
null, null, null, {});
if (result != 0)
return;
// get the permission
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var perm = pm.getPermissionObject(principal, "offline-app");
// clear offline cache entries
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
getService(Components.interfaces.nsIApplicationCacheService);
@ -557,25 +564,14 @@ var gAdvancedPane = {
getService(Components.interfaces.nsIIOService);
var groups = cacheService.getGroups();
for (var i = 0; i < groups.length; i++) {
let uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == host) {
var uri = ios.newURI(groups[i], null, null);
if (perm.matchesURI(uri, true)) {
var cache = cacheService.getActiveCache(groups[i]);
cache.discard();
}
}
// remove the permission
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
let uri;
try {
// file:// URIs are stored with their scheme. We try to parse them first, as
// URIs like http://file:///foo/bar/baz.html will parse as HTTP URIs.
uri = ios.newURI(host, null, null);
} catch (e) {
uri = ios.newURI("http://" + host, null, null);
}
pm.remove(uri, "offline-app");
pm.removePermission(perm);
list.removeChild(item);
gAdvancedPane.offlineAppSelected();

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

@ -502,7 +502,7 @@ var gAdvancedPane = {
var usage = 0;
for (var i = 0; i < groups.length; i++) {
var uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == perm.host) {
if (perm.matchesURI(uri, true)) {
var cache = cacheService.getActiveCache(groups[i]);
usage += cache.usage;
}
@ -544,7 +544,7 @@ var gAdvancedPane = {
var row = document.createElement("listitem");
row.id = "";
row.className = "offlineapp";
row.setAttribute("host", perm.host);
row.setAttribute("origin", perm.principal.origin);
var converted = DownloadUtils.
convertByteUnits(this._getOfflineAppUsage(perm, groups));
row.setAttribute("usage",
@ -570,7 +570,8 @@ var gAdvancedPane = {
{
var list = document.getElementById("offlineAppsList");
var item = list.selectedItem;
var host = item.getAttribute("host");
var origin = item.getAttribute("origin");
var principal = BrowserUtils.principalFromOrigin(origin);
var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
@ -579,13 +580,18 @@ var gAdvancedPane = {
var bundle = document.getElementById("bundlePreferences");
var title = bundle.getString("offlineAppRemoveTitle");
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]);
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [principal.URI.prePath]);
var confirm = bundle.getString("offlineAppRemoveConfirm");
var result = prompts.confirmEx(window, title, prompt, flags, confirm,
null, null, null, {});
if (result != 0)
return;
// get the permission
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var perm = pm.getPermissionObject(principal, "offline-app");
// clear offline cache entries
try {
var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
@ -594,26 +600,15 @@ var gAdvancedPane = {
getService(Components.interfaces.nsIIOService);
var groups = cacheService.getGroups();
for (var i = 0; i < groups.length; i++) {
let uri = ios.newURI(groups[i], null, null);
if (uri.asciiHost == host) {
var uri = ios.newURI(groups[i], null, null);
if (perm.matchesURI(uri, true)) {
var cache = cacheService.getActiveCache(groups[i]);
cache.discard();
}
}
} catch (e) {}
// remove the permission
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
let uri;
try {
// file:// URIs are stored with their scheme. We try to parse them first, as
// URIs like http://file:///foo/bar/baz.html will parse as HTTP URIs.
uri = ios.newURI(host, null, null);
} catch (e) {
uri = ios.newURI("http://" + host, null, null);
}
pm.remove(uri, "offline-app");
pm.removePermission(perm);
list.removeChild(item);
gAdvancedPane.offlineAppSelected();

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

@ -9,10 +9,10 @@ const nsICookiePermission = Components.interfaces.nsICookiePermission;
const NOTIFICATION_FLUSH_PERMISSIONS = "flush-pending-permissions";
function Permission(host, rawHost, type, capability)
function Permission(principal, type, capability)
{
this.host = host;
this.rawHost = rawHost;
this.principal = principal;
this.origin = principal.origin;
this.type = type;
this.capability = capability;
}
@ -35,7 +35,7 @@ var gPermissionManager = {
getCellText: function (aRow, aColumn)
{
if (aColumn.id == "siteCol")
return gPermissionManager._permissions[aRow].rawHost;
return gPermissionManager._permissions[aRow].origin;
else if (aColumn.id == "statusCol")
return gPermissionManager._permissions[aRow].capability;
return "";
@ -82,10 +82,17 @@ var gPermissionManager = {
addPermission: function (aCapability)
{
var textbox = document.getElementById("url");
var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme
var input_url = textbox.value.replace(/^\s*/, ""); // trim any leading space
let principal;
try {
var uri = Services.io.newURI("http://"+host, null, null);
host = uri.host;
// If the uri doesn't successfully parse, try adding a http:// and parsing again
let uri;
try {
let uri = Services.io.newURI(input_url, null, null);
} catch(ex) {
uri = Services.io.newURI("http://" + input_url, null, null);
}
principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
} catch(ex) {
var message = this._bundle.getString("invalidURI");
var title = this._bundle.getString("invalidURITitle");
@ -96,11 +103,11 @@ var gPermissionManager = {
var capabilityString = this._getCapabilityString(aCapability);
// check whether the permission already exists, if not, add it
let hostExists = false;
let permissionExists = false;
let capabilityExists = false;
for (var i = 0; i < this._permissions.length; ++i) {
if (this._permissions[i].rawHost == host) {
hostExists = true;
if (this._permissions[i].principal.equals(principal)) {
permissionExists = true;
capabilityExists = this._permissions[i].capability == capabilityString;
if (!capabilityExists) {
this._permissions[i].capability = capabilityString;
@ -109,14 +116,14 @@ var gPermissionManager = {
}
}
let permissionParams = {host: host, type: this._type, capability: aCapability};
if (!hostExists) {
this._permissionsToAdd.set(host, permissionParams);
let permissionParams = {principal: principal, type: this._type, capability: aCapability};
if (!permissionExists) {
this._permissionsToAdd.set(principal.origin, permissionParams);
this._addPermission(permissionParams);
}
else if (!capabilityExists) {
this._permissionsToAdd.set(host, permissionParams);
this._handleCapabilityChange();
this._permissionsToAdd.set(principal.origin, permissionParams);
this._handleCapabilityChange();
}
textbox.value = "";
@ -131,15 +138,15 @@ var gPermissionManager = {
_removePermission: function(aPermission)
{
this._removePermissionFromList(aPermission.host);
this._removePermissionFromList(aPermission.principal);
// If this permission was added during this session, let's remove
// it from the pending adds list to prevent calls to the
// permission manager.
let isNewPermission = this._permissionsToAdd.delete(aPermission.host);
let isNewPermission = this._permissionsToAdd.delete(aPermission.principal.origin);
if (!isNewPermission) {
this._permissionsToDelete.set(aPermission.host, aPermission);
this._permissionsToDelete.set(aPermission.principal.origin, aPermission);
}
},
@ -276,7 +283,7 @@ var gPermissionManager = {
}
else if (aData == "changed") {
for (var i = 0; i < this._permissions.length; ++i) {
if (this._permissions[i].host == permission.host) {
if (permission.matches(this._permissions[i].principal, true)) {
this._permissions[i].capability = this._getCapabilityString(permission.capability);
break;
}
@ -363,13 +370,11 @@ var gPermissionManager = {
this.uninit();
for (let permissionParams of this._permissionsToAdd.values()) {
let uri = Services.io.newURI("http://" + permissionParams.host, null, null);
Services.perms.add(uri, permissionParams.type, permissionParams.capability);
Services.perms.addFromPrincipal(permissionParams.principal, permissionParams.type, permissionParams.capability);
}
for (let p of this._permissionsToDelete.values()) {
let uri = Services.io.newURI("http://" + p.host, null, null);
Services.perms.remove(uri, p.type);
Services.perms.removeFromPrincipal(p.principal, p.type);
}
window.close();
@ -392,7 +397,7 @@ var gPermissionManager = {
// sort and display the table
this._tree.view = this._view;
this.onPermissionSort("rawHost");
this.onPermissionSort("origin");
// disable "remove all" button if there are none
document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;
@ -404,20 +409,19 @@ var gPermissionManager = {
(!this._manageCapability ||
(aPermission.capability == this._manageCapability))) {
var host = aPermission.host;
var principal = aPermission.principal;
var capabilityString = this._getCapabilityString(aPermission.capability);
var p = new Permission(host,
(host.charAt(0) == ".") ? host.substring(1,host.length) : host,
var p = new Permission(principal,
aPermission.type,
capabilityString);
this._permissions.push(p);
}
},
_removePermissionFromList: function (aHost)
_removePermissionFromList: function (aPrincipal)
{
for (let i = 0; i < this._permissions.length; ++i) {
if (this._permissions[i].host == aHost) {
if (this._permissions[i].principal.equals(aPrincipal)) {
this._permissions.splice(i, 1);
this._view._rowCount--;
this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, -1);
@ -427,15 +431,15 @@ var gPermissionManager = {
}
},
setHost: function (aHost)
setOrigin: function (aOrigin)
{
document.getElementById("url").value = aHost;
document.getElementById("url").value = aOrigin;
}
};
function setHost(aHost)
function setOrigin(aOrigin)
{
gPermissionManager.setHost(aHost);
gPermissionManager.setOrigin(aOrigin);
}
function initWithParams(aParams)

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

@ -103,11 +103,11 @@ var tests = [
sitesFilter.doCommand();
},
run: function() {
let testSite1 = getSiteItem(TEST_URI_1.host);
let testSite1 = getSiteItem(TEST_URI_1.prePath);
ok(testSite1.collapsed, "test site 1 is collapsed after early filtering");
let testSite2 = getSiteItem(TEST_URI_2.host);
let testSite2 = getSiteItem(TEST_URI_2.prePath);
ok(!testSite2.collapsed, "test site 2 is not collapsed after early filtering");
let testSite3 = getSiteItem(TEST_URI_3.host);
let testSite3 = getSiteItem(TEST_URI_3.prePath);
ok(testSite3.collapsed, "test site 3 is collapsed after early filtering");
runNextTest();
@ -119,11 +119,11 @@ var tests = [
ForgetAboutSite.removeDataFromDomain(TEST_URI_2.host);
},
run: function() {
let testSite1 = getSiteItem(TEST_URI_1.host);
let testSite1 = getSiteItem(TEST_URI_1.prePath);
ok(testSite1, "test site 1 was not removed from sites list");
let testSite2 = getSiteItem(TEST_URI_2.host);
let testSite2 = getSiteItem(TEST_URI_2.prePath);
ok(!testSite2, "test site 2 was pre-removed from sites list");
let testSite3 = getSiteItem(TEST_URI_3.host);
let testSite3 = getSiteItem(TEST_URI_3.prePath);
ok(testSite3, "test site 3 was not removed from sites list");
runNextTest();
@ -131,7 +131,7 @@ var tests = [
}
];
function getSiteItem(aHost) {
function getSiteItem(aPrePath) {
return gBrowser.contentDocument.
querySelector(".site[value='" + aHost + "']");
querySelector(".site[value='" + aPrePath + "']");
}

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

@ -20,7 +20,7 @@ var testRunner = {
"permission text should be set correctly");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "added",
observances: [{ type: "cookie", origin: "http://test.com", data: "added",
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
},
{
@ -31,7 +31,7 @@ var testRunner = {
"permission should change to deny in UI");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "changed",
observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
capability: Ci.nsIPermissionManager.DENY_ACTION }],
},
{
@ -42,7 +42,7 @@ var testRunner = {
"permission should revert back to allow");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "changed",
observances: [{ type: "cookie", origin: "http://test.com", data: "changed",
capability: Ci.nsIPermissionManager.ALLOW_ACTION }],
},
{
@ -52,7 +52,7 @@ var testRunner = {
is(params.tree.view.rowCount, 0, "exception should be removed");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "cookie", host: "test.com", data: "deleted" }],
observances: [{ type: "cookie", origin: "http://test.com", data: "deleted" }],
},
{
test: function(params) {
@ -61,7 +61,7 @@ var testRunner = {
is(params.tree.view.rowCount, 0, "adding unrelated permission should not change display");
params.btnApplyChanges.doCommand();
},
observances: [{ type: "popup", host: "test.com", data: "added",
observances: [{ type: "popup", origin: "http://test.com", data: "added",
capability: Ci.nsIPermissionManager.DENY_ACTION }],
cleanUp: function(params) {
let uri = params.ioService.newURI("http://test.com", null, null);
@ -160,12 +160,17 @@ var testRunner = {
let expected = testRunner.tests[testRunner._currentTest].observances.shift();
is(aData, expected.data, "type of message should be the same");
for each (let prop in ["type", "host", "capability"]) {
for each (let prop in ["type", "capability"]) {
if (expected[prop])
is(permission[prop], expected[prop],
"property: \"" + prop + "\" should be equal");
}
if (expected.origin) {
is(permission.principal.origin, expected.origin,
"property: \"origin\" should be equal");
}
os.removeObserver(permObserver, "perm-changed");
if (testRunner.tests[testRunner._currentTest].cleanup) {

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

@ -115,8 +115,8 @@ var tests = [
is(gSitesList.firstChild.id, "all-sites-item",
"all sites is the first item in the sites list");
ok(getSiteItem(TEST_URI_1.host), "site item from places db exists");
ok(getSiteItem(TEST_URI_2.host), "site item from enumerating services exists");
ok(getSiteItem(TEST_URI_1.prePath), "site item from places db exists");
ok(getSiteItem(TEST_URI_2.prePath), "site item from enumerating services exists");
runNextTest();
},
@ -128,9 +128,9 @@ var tests = [
sitesFilter.doCommand();
// make sure correct sites are collapsed/showing
let testSite1 = getSiteItem(TEST_URI_1.host);
let testSite1 = getSiteItem(TEST_URI_1.prePath);
ok(!testSite1.collapsed, "test site 1 is not collapsed");
let testSite2 = getSiteItem(TEST_URI_2.host);
let testSite2 = getSiteItem(TEST_URI_2.prePath);
ok(testSite2.collapsed, "test site 2 is collapsed");
// clear filter
@ -202,13 +202,13 @@ var tests = [
function test_select_site() {
// select the site that has the permissions we set at the beginning of the test
let testSiteItem = getSiteItem(TEST_URI_2.host);
let testSiteItem = getSiteItem(TEST_URI_2.prePath);
gSitesList.selectedItem = testSiteItem;
let siteHeader = gBrowser.contentDocument.getElementById("site-header");
is(siteHeader, gHeaderDeck.selectedPanel,
"correct header shown for a specific site");
is(gSiteLabel.value, TEST_URI_2.host, "header updated for selected site");
is(gSiteLabel.value, TEST_URI_2.prePath, "header updated for selected site");
ok(!gBrowser.contentDocument.getElementById("passwords-count").hidden,
"passwords count is not hidden");
@ -283,7 +283,7 @@ var tests = [
"all sites item selected after forgetting selected site");
// check to make sure site is gone from sites list
let testSiteItem = getSiteItem(TEST_URI_2.host);
let testSiteItem = getSiteItem(TEST_URI_2.prePath);
ok(!testSiteItem, "site removed from sites list");
// check to make sure we forgot all permissions corresponding to site

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

@ -9,6 +9,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "gLangBundle", () =>
Services.strings.createBundle("chrome://global/locale/languageNames.properties"));
@ -83,7 +84,7 @@ let gTranslationExceptions = {
if (perm.type == kPermissionType &&
perm.capability == Services.perms.DENY_ACTION) {
this._sites.push(perm.host);
this._sites.push(perm.principal.origin);
}
}
Services.obs.addObserver(this, "perm-changed", false);
@ -126,14 +127,14 @@ let gTranslationExceptions = {
if (aData == "added") {
if (perm.capability != Services.perms.DENY_ACTION)
return;
this._sites.push(perm.host);
this._sites.push(perm.principal.origin);
this._sites.sort();
let boxObject = this._siteTree.boxObject;
boxObject.rowCountChanged(0, 1);
boxObject.invalidate();
}
else if (aData == "deleted") {
let index = this._sites.indexOf(perm.host);
let index = this._sites.indexOf(perm.principal.origin);
if (index == -1)
return;
this._sites.splice(index, 1);
@ -188,9 +189,9 @@ let gTranslationExceptions = {
onSiteDeleted: function() {
let removedSites = this._siteTree.getSelectedItems();
for (let host of removedSites) {
let uri = Services.io.newURI("http://" + host, null, null);
Services.perms.remove(uri, kPermissionType);
for (let origin of removedSites) {
let principal = BrowserUtils.principalFromOrigin(origin);
Services.perms.removeFromPrincipal(principal, kPermissionType);
}
},
@ -201,9 +202,9 @@ let gTranslationExceptions = {
let removedSites = this._sites.splice(0, this._sites.length);
this._siteTree.boxObject.rowCountChanged(0, -removedSites.length);
for (let host of removedSites) {
let uri = Services.io.newURI("http://" + host, null, null);
Services.perms.remove(uri, kPermissionType);
for (let origin of removedSites) {
let principal = BrowserUtils.principalFromOrigin(origin);
Services.perms.removeFromPrincipal(principal, kPermissionType);
}
this.onSiteSelected();

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

@ -51,7 +51,7 @@ function getDomainExceptions() {
if (perm.type == "translate" &&
perm.capability == Services.perms.DENY_ACTION)
results.push(perm.host);
results.push(perm.principal);
}
return results;
@ -181,7 +181,7 @@ let gTests = [
// Check this has been saved to the exceptions list.
let sites = getDomainExceptions();
is(sites.length, 1, "one site in the exception list");
is(sites[0], "example.com", "correct site in the exception list");
is(sites[0].origin, "http://example.com", "correct site in the exception list");
ok(!ui.shouldShowInfoBar(uri, "fr"),
"the infobar wouldn't be shown anymore");

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

@ -198,8 +198,10 @@ function loadUITourTestPage(callback, host = "https://example.com/") {
function UITourTest() {
Services.prefs.setBoolPref("browser.uitour.enabled", true);
let testUri = Services.io.newURI("http://example.com", null, null);
Services.perms.add(testUri, "uitour", Services.perms.ALLOW_ACTION);
let testHttpsUri = Services.io.newURI("https://example.com", null, null);
let testHttpUri = Services.io.newURI("http://example.com", null, null);
Services.perms.add(testHttpsUri, "uitour", Services.perms.ALLOW_ACTION);
Services.perms.add(testHttpUri, "uitour", Services.perms.ALLOW_ACTION);
waitForExplicitFinish();
@ -210,7 +212,8 @@ function UITourTest() {
gBrowser.removeTab(gTestTab);
delete window.gTestTab;
Services.prefs.clearUserPref("browser.uitour.enabled", true);
Services.perms.remove(testUri, "uitour");
Services.perms.remove(testHttpsUri, "uitour");
Services.perms.remove(testHttpUri, "uitour");
});
function done() {

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

@ -224,7 +224,7 @@ function test() {
"The first source should be currently selected.");
let window = gEditor.container.contentWindow;
executeSoon(() => window.mozRequestAnimationFrame(onReadyForClick));
executeSoon(() => window.requestAnimationFrame(onReadyForClick));
}
function onReadyForClick() {

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

@ -453,6 +453,7 @@ TiltVisualizer.Presenter.prototype = {
_loop: function TVP__loop()
{
let renderer = this._renderer;
let frameStartTime = this.chromeWindow.performance.now();
// if the renderer was destroyed, don't continue rendering
if (!renderer || !renderer.context) {
@ -460,7 +461,7 @@ TiltVisualizer.Presenter.prototype = {
}
// prepare for the next frame of the animation loop
this.chromeWindow.mozRequestAnimationFrame(this._loop);
this.chromeWindow.requestAnimationFrame(this._loop);
// only redraw if we really have to
if (this._redraw) {
@ -473,17 +474,17 @@ TiltVisualizer.Presenter.prototype = {
this._controllerUpdate(this._time, this._delta);
}
this._handleFrameDelta();
this._handleFrameDelta(frameStartTime);
this._handleKeyframeNotifications();
},
/**
* Calculates the current frame delta time.
*/
_handleFrameDelta: function TVP__handleFrameDelta()
_handleFrameDelta: function TVP__handleFrameDelta(frameStartTime)
{
this._prevFrameTime = this._currFrameTime;
this._currFrameTime = this.chromeWindow.mozAnimationStartTime;
this._currFrameTime = frameStartTime;
this._delta = this._currFrameTime - this._prevFrameTime;
},

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

@ -31,7 +31,7 @@ function test() {
loadTab(TEST_URI2).then((tab) => {
tabs.push(tab.tab);
openConsole().then((hud) => {
hud.iframeWindow.mozRequestAnimationFrame(startTest);
hud.iframeWindow.requestAnimationFrame(startTest);
});
});
}
@ -40,7 +40,7 @@ function test() {
loadTab(TEST_URI1).then((tab) => {
tabs.push(tab.tab);
openConsole().then((hud) => {
hud.iframeWindow.mozRequestAnimationFrame(() => {
hud.iframeWindow.requestAnimationFrame(() => {
info("iframe1 root height " + hud.ui.rootElement.clientHeight);
openTab();

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

@ -9,15 +9,13 @@ include $(topsrcdir)/config/rules.mk
MOZ_PKG_REMOVALS = $(srcdir)/removed-files.in
MOZ_PKG_MANIFEST_P = $(srcdir)/package-manifest.in
ifdef MOZ_MULET
MOZ_PKG_MANIFEST_P += $(topsrcdir)/b2g/installer/package-manifest.in
endif
MOZ_PKG_MANIFEST = $(srcdir)/package-manifest.in
# Some files have been already bundled with xulrunner
ifndef MOZ_MULET
MOZ_PKG_FATAL_WARNINGS = 1
else
DEFINES += -DMOZ_MULET
endif
DEFINES += -DMOZ_APP_NAME=$(MOZ_APP_NAME) -DPREF_DIR=$(PREF_DIR)
@ -98,15 +96,6 @@ ifdef MAKENSISU
DEFINES += -DHAVE_MAKENSISU=1
endif
ifdef MOZ_PKG_MANIFEST_P
MOZ_PKG_MANIFEST = package-manifest
$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS)
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $(MOZ_PKG_MANIFEST_P) -o $@)
GARBAGE += $(MOZ_PKG_MANIFEST)
endif
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
MOZ_PKG_MAC_DSSTORE=branding/dsstore
MOZ_PKG_MAC_BACKGROUND=branding/background.png
@ -180,13 +169,11 @@ else
FINDPATH=bin
endif
package-compare:: $(MOZ_PKG_MANIFEST)
ifdef MOZ_PKG_MANIFEST_P
package-compare::
cd $(DIST); find $(PKGCOMP_FIND_OPTS) $(FINDPATH) -type f | sort > bin-list.txt
grep '^$(BINPATH)' $(MOZ_PKG_MANIFEST) | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $(MOZ_PKG_MANIFEST)) | grep '^$(BINPATH)' | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt
-diff -u $(DIST)/pack-list.txt $(DIST)/bin-list.txt
rm -f $(DIST)/pack-list.txt $(DIST)/bin-list.txt
endif
installer::
ifdef INSTALLER_DIR

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

@ -917,3 +917,7 @@ bin/libfreebl_32int64_3.so
@RESPATH@/components/GfxSanityTest.manifest
@RESPATH@/components/SanityTest.js
#endif
#ifdef MOZ_MULET
#include ../../b2g/installer/package-manifest.in
#endif

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

@ -199,6 +199,9 @@ PluginContent.prototype = {
*/
setVisibility : function (plugin, overlay, shouldShow) {
overlay.classList.toggle("visible", shouldShow);
if (shouldShow) {
overlay.removeAttribute("dismissed");
}
},
/**
@ -434,8 +437,8 @@ PluginContent.prototype = {
}
// Show the in-content UI if it's not too big. The crashed plugin handler already did this.
let overlay = this.getPluginUI(plugin, "main");
if (eventType != "PluginCrashed") {
let overlay = this.getPluginUI(plugin, "main");
if (overlay != null) {
this.setVisibility(plugin, overlay,
this.shouldShowOverlay(plugin, overlay));
@ -452,8 +455,10 @@ PluginContent.prototype = {
let closeIcon = this.getPluginUI(plugin, "closeIcon");
if (closeIcon) {
closeIcon.addEventListener("click", event => {
if (event.button == 0 && event.isTrusted)
if (event.button == 0 && event.isTrusted) {
this.hideClickToPlayOverlay(plugin);
overlay.setAttribute("dismissed", "true");
}
}, true);
}
@ -627,7 +632,7 @@ PluginContent.prototype = {
// Have to check that the target is not the link to update the plugin
if (!(event.originalTarget instanceof contentWindow.HTMLAnchorElement) &&
(event.originalTarget.getAttribute('anonid') != 'closeIcon') &&
overlay.classList.contains('visible') &&
!overlay.hasAttribute('dismissed') &&
event.button == 0 &&
event.isTrusted) {
this._showClickToPlayNotification(plugin, true);
@ -695,20 +700,6 @@ PluginContent.prototype = {
this._showClickToPlayNotification(null, false);
},
// Match the behaviour of nsPermissionManager
_getHostFromPrincipal: function (principal) {
if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) {
return "(null)";
}
try {
if (principal.URI.host)
return principal.URI.host;
} catch (e) {}
return principal.origin;
},
/**
* Activate the plugins that the user has specified.
*/
@ -776,7 +767,6 @@ PluginContent.prototype = {
let pluginData = this.pluginData;
let principal = this.content.document.nodePrincipal;
let principalHost = this._getHostFromPrincipal(principal);
let location = this.content.document.location.href;
for (let p of plugins) {
@ -792,11 +782,11 @@ PluginContent.prototype = {
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
pluginInfo.pluginPermissionHost = permissionObj.host;
pluginInfo.pluginPermissionPrePath = permissionObj.principal.originNoSuffix;
pluginInfo.pluginPermissionType = permissionObj.expireType;
}
else {
pluginInfo.pluginPermissionHost = principalHost;
pluginInfo.pluginPermissionPrePath = principal.originNoSuffix;
pluginInfo.pluginPermissionType = undefined;
}
@ -806,7 +796,6 @@ PluginContent.prototype = {
this.global.sendAsyncMessage("PluginContent:ShowClickToPlayNotification", {
plugins: [... this.pluginData.values()],
showNow: showNow,
host: principalHost,
location: location,
}, null, principal);
},
@ -889,7 +878,6 @@ PluginContent.prototype = {
this.global.sendAsyncMessage("PluginContent:UpdateHiddenPluginUI", {
haveInsecure: haveInsecure,
actions: [... actions.values()],
host: this._getHostFromPrincipal(principal),
location: location,
}, null, principal);
},

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

@ -122,6 +122,13 @@ processor
Always defined.
release_build
Whether this is a release build.
Values are ``true`` and ``false``.
Always defined.
tests_enabled
Whether tests are enabled for this build.

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

@ -17,7 +17,7 @@ import traceback
import zipfile
from automation import Automation
from mozlog.structured import get_default_logger
from mozlog import get_default_logger
from mozprocess import ProcessHandlerMixin

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

@ -14,7 +14,7 @@ import sys
from automation import Automation
from devicemanager import DMError, DeviceManager
from mozlog.structured import get_default_logger
from mozlog import get_default_logger
import mozcrash
# signatures for logcat messages that we don't care about much

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

@ -51,7 +51,7 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
params->Serialize(value);
if (!value.IsEmpty()) {
aStr.AppendLiteral("!");
aStr.AppendLiteral("^");
aStr.Append(NS_ConvertUTF16toUTF8(value));
}
}
@ -117,7 +117,7 @@ OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
return true;
}
if (aStr[0] != '!') {
if (aStr[0] != '^') {
return false;
}
@ -134,7 +134,7 @@ OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
{
// RFindChar is only available on nsCString.
nsCString origin(aOrigin);
int32_t pos = origin.RFindChar('!');
int32_t pos = origin.RFindChar('^');
if (pos == kNotFound) {
aOriginNoSuffix = origin;
@ -156,6 +156,15 @@ BasePrincipal::GetOrigin(nsACString& aOrigin)
{
nsresult rv = GetOriginInternal(aOrigin);
NS_ENSURE_SUCCESS(rv, rv);
// OriginAttributes::CreateSuffix asserts against UNKNOWN_APP_ID. It's trivial
// to trigger this getter from script on such a principal, so we handle it
// here at the API entry point.
if (mOriginAttributes.mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
NS_WARNING("Refusing to provide canonical origin string to principal with UNKNOWN_APP_ID");
return NS_ERROR_FAILURE;
}
nsAutoCString suffix;
mOriginAttributes.CreateSuffix(suffix);
aOrigin.Append(suffix);

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

@ -62,7 +62,7 @@ DomainPolicy::~DomainPolicy()
NS_IMETHODIMP
DomainPolicy::GetBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mBlacklist;
nsCOMPtr<nsIDomainSet> set = mBlacklist.get();
set.forget(aSet);
return NS_OK;
}
@ -70,7 +70,7 @@ DomainPolicy::GetBlacklist(nsIDomainSet** aSet)
NS_IMETHODIMP
DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperBlacklist;
nsCOMPtr<nsIDomainSet> set = mSuperBlacklist.get();
set.forget(aSet);
return NS_OK;
}
@ -78,7 +78,7 @@ DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet)
NS_IMETHODIMP
DomainPolicy::GetWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mWhitelist;
nsCOMPtr<nsIDomainSet> set = mWhitelist.get();
set.forget(aSet);
return NS_OK;
}
@ -86,7 +86,7 @@ DomainPolicy::GetWhitelist(nsIDomainSet** aSet)
NS_IMETHODIMP
DomainPolicy::GetSuperWhitelist(nsIDomainSet** aSet)
{
nsCOMPtr<nsIDomainSet> set = mSuperWhitelist;
nsCOMPtr<nsIDomainSet> set = mSuperWhitelist.get();
set.forget(aSet);
return NS_OK;
}
@ -122,10 +122,10 @@ void
DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone)
{
aClone->active() = true;
static_cast<DomainSet*>(mBlacklist.get())->CloneSet(&aClone->blacklist());
static_cast<DomainSet*>(mSuperBlacklist.get())->CloneSet(&aClone->superBlacklist());
static_cast<DomainSet*>(mWhitelist.get())->CloneSet(&aClone->whitelist());
static_cast<DomainSet*>(mSuperWhitelist.get())->CloneSet(&aClone->superWhitelist());
mBlacklist->CloneSet(&aClone->blacklist());
mSuperBlacklist->CloneSet(&aClone->superBlacklist());
mWhitelist->CloneSet(&aClone->whitelist());
mSuperWhitelist->CloneSet(&aClone->superWhitelist());
}
static
@ -246,24 +246,17 @@ DomainSet::GetType(uint32_t* aType)
return NS_OK;
}
static
PLDHashOperator
DomainEnumerator(nsURIHashKey* aEntry, void* aUserArg)
{
InfallibleTArray<URIParams>* uris = static_cast<InfallibleTArray<URIParams>*>(aUserArg);
nsIURI* key = aEntry->GetKey();
URIParams uri;
SerializeURI(key, uri);
uris->AppendElement(uri);
return PL_DHASH_NEXT;
}
void
DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains)
{
mHashTable.EnumerateEntries(DomainEnumerator, aDomains);
for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
nsIURI* key = iter.Get()->GetKey();
URIParams uri;
SerializeURI(key, uri);
aDomains->AppendElement(uri);
}
}
} /* namespace mozilla */

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

@ -33,23 +33,7 @@ enum DomainSetType{
SUPER_WHITELIST
};
class DomainPolicy : public nsIDomainPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINPOLICY
DomainPolicy();
private:
virtual ~DomainPolicy();
nsCOMPtr<nsIDomainSet> mBlacklist;
nsCOMPtr<nsIDomainSet> mSuperBlacklist;
nsCOMPtr<nsIDomainSet> mWhitelist;
nsCOMPtr<nsIDomainSet> mSuperWhitelist;
};
class DomainSet : public nsIDomainSet
class DomainSet final : public nsIDomainSet
{
public:
NS_DECL_ISUPPORTS
@ -67,6 +51,22 @@ protected:
DomainSetType mType;
};
class DomainPolicy final : public nsIDomainPolicy
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMAINPOLICY
DomainPolicy();
private:
virtual ~DomainPolicy();
nsRefPtr<DomainSet> mBlacklist;
nsRefPtr<DomainSet> mSuperBlacklist;
nsRefPtr<DomainSet> mWhitelist;
nsRefPtr<DomainSet> mSuperWhitelist;
};
} /* namespace mozilla */
#endif /* DomainPolicy_h__ */

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

@ -14,6 +14,7 @@
#include "pratom.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIStandardURL.h"
#include "nsIURIWithPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsIEffectiveTLDService.h"
@ -127,6 +128,31 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
}
}
// We want the invariant that prinA.origin == prinB.origin i.f.f.
// prinA.equals(prinB). However, this requires that we impose certain constraints
// on the behavior and origin semantics of principals, and in particular, forbid
// creating origin strings for principals whose equality constraints are not
// expressible as strings (i.e. object equality). Moreover, we want to forbid URIs
// containing the magic "^" we use as a separating character for origin
// attributes.
//
// These constraints can generally be achieved by restricting .origin to
// nsIStandardURL-based URIs, but there are a few other URI schemes that we need
// to handle.
bool isBehaved;
if ((NS_SUCCEEDED(origin->SchemeIs("about", &isBehaved)) && isBehaved) ||
(NS_SUCCEEDED(origin->SchemeIs("moz-safe-about", &isBehaved)) && isBehaved) ||
(NS_SUCCEEDED(origin->SchemeIs("indexeddb", &isBehaved)) && isBehaved)) {
rv = origin->GetAsciiSpec(aOrigin);
NS_ENSURE_SUCCESS(rv, rv);
// These URIs could technically contain a '^', but they never should.
if (NS_WARN_IF(aOrigin.FindChar('^', 0) != -1)) {
aOrigin.Truncate();
return NS_ERROR_FAILURE;
}
return NS_OK;
}
int32_t port;
if (NS_SUCCEEDED(rv) && !isChrome) {
rv = origin->GetPort(&port);
@ -144,6 +170,14 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
aOrigin.Append(hostPort);
}
else {
// If we reached this branch, we can only create an origin if we have a nsIStandardURL.
// So, we query to a nsIStandardURL, and fail if we aren't an instance of an nsIStandardURL
// nsIStandardURLs have the good property of escaping the '^' character in their specs,
// which means that we can be sure that the caret character (which is reserved for delimiting
// the end of the spec, and the beginning of the origin attributes) is not present in the
// origin string
nsCOMPtr<nsIStandardURL> standardURL = do_QueryInterface(origin);
NS_ENSURE_TRUE(standardURL, NS_ERROR_FAILURE);
rv = origin->GetAsciiSpec(aOrigin);
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -65,33 +65,37 @@ function run_test() {
// Just app.
var exampleOrg_app = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 42});
var nullPrin_app = ssm.createNullPrincipal({appId: 42});
checkOriginAttributes(exampleOrg_app, {appId: 42}, '!appId=42');
checkOriginAttributes(nullPrin_app, {appId: 42}, '!appId=42');
do_check_eq(exampleOrg_app.origin, 'http://example.org!appId=42');
checkOriginAttributes(exampleOrg_app, {appId: 42}, '^appId=42');
checkOriginAttributes(nullPrin_app, {appId: 42}, '^appId=42');
do_check_eq(exampleOrg_app.origin, 'http://example.org^appId=42');
// Just browser.
var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true});
var nullPrin_browser = ssm.createNullPrincipal({inBrowser: true});
checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '!inBrowser=1');
checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '!inBrowser=1');
do_check_eq(exampleOrg_browser.origin, 'http://example.org!inBrowser=1');
checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '^inBrowser=1');
checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '^inBrowser=1');
do_check_eq(exampleOrg_browser.origin, 'http://example.org^inBrowser=1');
// App and browser.
var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true, appId: 42});
var nullPrin_appBrowser = ssm.createNullPrincipal({inBrowser: true, appId: 42});
checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1');
checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1');
do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org!appId=42&inBrowser=1');
checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org^appId=42&inBrowser=1');
// App and browser, different domain.
var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inBrowser: true});
checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '!appId=42&inBrowser=1');
do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123!appId=42&inBrowser=1');
checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123^appId=42&inBrowser=1');
// Addon.
var exampleOrg_addon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy'});
checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '!addonId=dummy');
do_check_eq(exampleOrg_addon.origin, 'http://example.org!addonId=dummy');
checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy');
do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy');
// Make sure that we refuse to create .origin for principals with UNKNOWN_APP_ID.
var simplePrin = ssm.getSimpleCodebasePrincipal(makeURI('http://example.com'));
try { simplePrin.origin; do_check_true(false); } catch (e) { do_check_true(true); }
// Check that all of the above are cross-origin.
checkCrossOrigin(exampleOrg_app, exampleOrg);

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

@ -1607,12 +1607,20 @@ nsDocShell::LoadURI(nsIURI* aURI,
if (owner && mItemType != typeChrome) {
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
if (nsContentUtils::IsSystemOrExpandedPrincipal(ownerPrincipal)) {
if (nsContentUtils::IsSystemPrincipal(ownerPrincipal)) {
if (ownerIsExplicit) {
return NS_ERROR_DOM_SECURITY_ERR;
}
owner = nullptr;
inheritOwner = true;
} else if (nsContentUtils::IsExpandedPrincipal(ownerPrincipal)) {
if (ownerIsExplicit) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// Don't inherit from the current page. Just do the safe thing
// and pretend that we were loaded by a nullprincipal.
owner = nsNullPrincipal::Create();
inheritOwner = false;
}
}
if (!owner && !inheritOwner && !ownerIsExplicit) {
@ -3711,12 +3719,10 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
static bool
ItemIsActive(nsIDocShellTreeItem* aItem)
{
nsCOMPtr<nsIDOMWindow> window = aItem->GetWindow();
if (window) {
bool isClosed;
if (NS_SUCCEEDED(window->GetClosed(&isClosed)) && !isClosed) {
if (nsCOMPtr<nsIDOMWindow> window = aItem->GetWindow()) {
auto* win = static_cast<nsGlobalWindow*>(window.get());
MOZ_ASSERT(win->IsOuterWindow());
if (!win->GetClosedOuter()) {
return true;
}
}

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

@ -143,6 +143,12 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"browser:universalxss": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
bluetooth: {
app: DENY_ACTION,
trusted: DENY_ACTION,

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

@ -51,7 +51,7 @@ add_test(() => {
});
Assert.ok(mozapp.principal, "app principal should exist");
let expectedPrincipalOrigin = app.origin + "!appId=" + app.localId;
let expectedPrincipalOrigin = app.origin + "^appId=" + app.localId;
Assert.equal(mozapp.principal.origin, expectedPrincipalOrigin,
"app principal origin ok");
Assert.equal(mozapp.principal.appId, app.localId, "app principal appId ok");

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

@ -83,10 +83,8 @@ nsDOMWindowList::GetLength(uint32_t* aLength)
}
already_AddRefed<nsIDOMWindow>
nsDOMWindowList::IndexedGetter(uint32_t aIndex, bool& aFound)
nsDOMWindowList::IndexedGetter(uint32_t aIndex)
{
aFound = false;
nsCOMPtr<nsIDocShellTreeItem> item = GetDocShellTreeItemAt(aIndex);
if (!item) {
return nullptr;
@ -95,15 +93,13 @@ nsDOMWindowList::IndexedGetter(uint32_t aIndex, bool& aFound)
nsCOMPtr<nsIDOMWindow> window = item->GetWindow();
MOZ_ASSERT(window);
aFound = true;
return window.forget();
}
NS_IMETHODIMP
nsDOMWindowList::Item(uint32_t aIndex, nsIDOMWindow** aReturn)
{
bool found;
nsCOMPtr<nsIDOMWindow> window = IndexedGetter(aIndex, found);
nsCOMPtr<nsIDOMWindow> window = IndexedGetter(aIndex);
window.forget(aReturn);
return NS_OK;
}

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

@ -23,7 +23,7 @@ public:
NS_DECL_NSIDOMWINDOWCOLLECTION
uint32_t GetLength();
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex);
//local methods
NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);

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

@ -2343,6 +2343,19 @@ GK_ATOM(toolbarspring, "toolbarspring")
GK_ATOM(treegrid, "treegrid")
GK_ATOM(_undefined, "undefined")
GK_ATOM(xmlroles, "xml-roles")
// MathML xml roles
GK_ATOM(close_fence, "close-fence")
GK_ATOM(denominator, "denominator")
GK_ATOM(numerator, "numerator")
GK_ATOM(open_fence, "open-fence")
GK_ATOM(overscript, "overscript")
GK_ATOM(presubscript, "presubscript")
GK_ATOM(presuperscript, "presuperscript")
GK_ATOM(root_index, "root-index")
GK_ATOM(subscript, "subscript")
GK_ATOM(superscript, "superscript")
GK_ATOM(underscript, "underscript")
#endif
#ifdef MOZ_WEBSPEECH

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -27,7 +27,6 @@
#include "nsIBrowserDOMWindow.h"
#include "nsIDOMEventTarget.h"
#include "nsIInterfaceRequestor.h"
#include "nsIDOMJSWindow.h"
#include "nsIDOMChromeWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
@ -325,7 +324,6 @@ class nsGlobalWindow : public mozilla::dom::EventTarget,
public nsPIDOMWindow,
public nsIScriptGlobalObject,
public nsIScriptObjectPrincipal,
public nsIDOMJSWindow,
public nsSupportsWeakReference,
public nsIInterfaceRequestor,
public PRCListStr
@ -385,8 +383,15 @@ public:
// nsIDOMWindow
NS_DECL_NSIDOMWINDOW
// nsIDOMJSWindow
NS_DECL_NSIDOMJSWINDOW
nsresult
OpenJS(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, nsIDOMWindow **_retval);
void CaptureEvents();
void ReleaseEvents();
void Dump(const nsAString& aStr);
void SetResizable(bool aResizable) const;
nsresult GetScriptableContent(JSContext* aCx,
JS::MutableHandle<JS::Value> aVal);
// nsIDOMEventTarget
NS_DECL_NSIDOMEVENTTARGET
@ -501,7 +506,8 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
// WebIDL interface.
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
already_AddRefed<nsIDOMWindow> IndexedGetterOuter(uint32_t aIndex);
already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex);
void GetSupportedNames(nsTArray<nsString>& aNames);
@ -857,7 +863,9 @@ public:
{
return GetDoc();
}
void GetNameOuter(nsAString& aName);
void GetName(nsAString& aName, mozilla::ErrorResult& aError);
void SetNameOuter(const nsAString& aName, mozilla::ErrorResult& aError);
void SetName(const nsAString& aName, mozilla::ErrorResult& aError);
nsLocation* GetLocation(mozilla::ErrorResult& aError);
nsHistory* GetHistory(mozilla::ErrorResult& aError);
@ -867,23 +875,28 @@ public:
mozilla::dom::BarProp* GetScrollbars(mozilla::ErrorResult& aError);
mozilla::dom::BarProp* GetStatusbar(mozilla::ErrorResult& aError);
mozilla::dom::BarProp* GetToolbar(mozilla::ErrorResult& aError);
void GetStatusOuter(nsAString& aStatus);
void GetStatus(nsAString& aStatus, mozilla::ErrorResult& aError);
void SetStatusOuter(const nsAString& aStatus);
void SetStatus(const nsAString& aStatus, mozilla::ErrorResult& aError);
void CloseOuter();
void Close(mozilla::ErrorResult& aError);
bool GetClosedOuter();
bool GetClosed(mozilla::ErrorResult& aError);
void StopOuter(mozilla::ErrorResult& aError);
void Stop(mozilla::ErrorResult& aError);
void FocusOuter(mozilla::ErrorResult& aError);
void Focus(mozilla::ErrorResult& aError);
void BlurOuter();
void Blur(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> GetFramesOuter();
already_AddRefed<nsIDOMWindow> GetFrames(mozilla::ErrorResult& aError);
uint32_t Length();
already_AddRefed<nsIDOMWindow> GetTop(mozilla::ErrorResult& aError)
{
nsCOMPtr<nsIDOMWindow> top;
aError = GetScriptableTop(getter_AddRefs(top));
return top.forget();
}
already_AddRefed<nsIDOMWindow> GetTopOuter(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> GetTop(mozilla::ErrorResult& aError);
protected:
explicit nsGlobalWindow(nsGlobalWindow *aOuterWindow);
nsIDOMWindow* GetOpenerWindowOuter();
nsIDOMWindow* GetOpenerWindow(mozilla::ErrorResult& aError);
// Initializes the mWasOffline member variable
void InitWasOffline();
@ -893,8 +906,14 @@ public:
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
mozilla::ErrorResult& aError);
using nsIDOMWindow::GetParent;
already_AddRefed<nsIDOMWindow> GetParentOuter(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> GetParent(mozilla::ErrorResult& aError);
mozilla::dom::Element* GetFrameElementOuter();
mozilla::dom::Element* GetFrameElement(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> OpenOuter(const nsAString& aUrl,
const nsAString& aName,
const nsAString& aOptions,
mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> Open(const nsAString& aUrl,
const nsAString& aName,
const nsAString& aOptions,
@ -921,14 +940,19 @@ protected:
public:
void Alert(mozilla::ErrorResult& aError);
void AlertOuter(const nsAString& aMessage, mozilla::ErrorResult& aError);
void Alert(const nsAString& aMessage, mozilla::ErrorResult& aError);
already_AddRefed<mozilla::dom::cache::CacheStorage> GetCaches(mozilla::ErrorResult& aRv);
bool ConfirmOuter(const nsAString& aMessage, mozilla::ErrorResult& aError);
bool Confirm(const nsAString& aMessage, mozilla::ErrorResult& aError);
already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrUSVString& aInput,
const mozilla::dom::RequestInit& aInit,
mozilla::ErrorResult& aRv);
void PromptOuter(const nsAString& aMessage, const nsAString& aInitial,
nsAString& aReturn, mozilla::ErrorResult& aError);
void Prompt(const nsAString& aMessage, const nsAString& aInitial,
nsAString& aReturn, mozilla::ErrorResult& aError);
void PrintOuter(mozilla::ErrorResult& aError);
void Print(mozilla::ErrorResult& aError);
void ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
JS::Handle<JS::Value> aArgument,
@ -963,18 +987,24 @@ public:
mozilla::ErrorResult& aError);
mozilla::dom::DOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
mozilla::dom::DOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
mozilla::dom::Selection* GetSelectionOuter();
mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
mozilla::dom::indexedDB::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
already_AddRefed<nsICSSDeclaration>
GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
mozilla::ErrorResult& aError);
already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(const nsAString& aQuery);
already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(const nsAString& aQuery,
mozilla::ErrorResult& aError);
nsScreen* GetScreen(mozilla::ErrorResult& aError);
void MoveToOuter(int32_t aXPos, int32_t aYPos, mozilla::ErrorResult& aError);
void MoveTo(int32_t aXPos, int32_t aYPos, mozilla::ErrorResult& aError);
void MoveByOuter(int32_t aXDif, int32_t aYDif, mozilla::ErrorResult& aError);
void MoveBy(int32_t aXDif, int32_t aYDif, mozilla::ErrorResult& aError);
void ResizeToOuter(int32_t aWidth, int32_t aHeight, mozilla::ErrorResult& aError);
void ResizeTo(int32_t aWidth, int32_t aHeight,
mozilla::ErrorResult& aError);
void ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif, mozilla::ErrorResult& aError);
void ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
mozilla::ErrorResult& aError);
void Scroll(double aXScroll, double aYScroll);
@ -996,11 +1026,13 @@ public:
mozilla::ErrorResult& aError);
void SetInnerHeight(JSContext* aCx, JS::Handle<JS::Value> aValue,
mozilla::ErrorResult& aError);
int32_t GetScrollXOuter();
int32_t GetScrollX(mozilla::ErrorResult& aError);
int32_t GetPageXOffset(mozilla::ErrorResult& aError)
{
return GetScrollX(aError);
}
int32_t GetScrollYOuter();
int32_t GetScrollY(mozilla::ErrorResult& aError);
int32_t GetPageYOffset(mozilla::ErrorResult& aError)
{
@ -1026,7 +1058,6 @@ public:
int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback,
mozilla::ErrorResult& aError);
void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError);
nsPerformance* GetPerformance();
#ifdef MOZ_WEBSPEECH
mozilla::dom::SpeechSynthesis*
GetSpeechSynthesis(mozilla::ErrorResult& aError);
@ -1047,35 +1078,59 @@ public:
return CancelAnimationFrame(aHandle, aError);
}
int64_t GetMozAnimationStartTime(mozilla::ErrorResult& aError);
void SizeToContentOuter(mozilla::ErrorResult& aError);
void SizeToContent(mozilla::ErrorResult& aError);
mozilla::dom::Crypto* GetCrypto(mozilla::ErrorResult& aError);
nsIControllers* GetControllersOuter(mozilla::ErrorResult& aError);
nsIControllers* GetControllers(mozilla::ErrorResult& aError);
mozilla::dom::Element* GetRealFrameElementOuter();
mozilla::dom::Element* GetRealFrameElement(mozilla::ErrorResult& aError);
float GetMozInnerScreenXOuter();
float GetMozInnerScreenX(mozilla::ErrorResult& aError);
float GetMozInnerScreenYOuter();
float GetMozInnerScreenY(mozilla::ErrorResult& aError);
float GetDevicePixelRatioOuter();
float GetDevicePixelRatio(mozilla::ErrorResult& aError);
int32_t GetScrollMaxX(mozilla::ErrorResult& aError);
int32_t GetScrollMaxY(mozilla::ErrorResult& aError);
bool GetFullScreenOuter();
bool GetFullScreen(mozilla::ErrorResult& aError);
void SetFullScreenOuter(bool aFullScreen, mozilla::ErrorResult& aError);
void SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError);
void BackOuter(mozilla::ErrorResult& aError);
void Back(mozilla::ErrorResult& aError);
void ForwardOuter(mozilla::ErrorResult& aError);
void Forward(mozilla::ErrorResult& aError);
void HomeOuter(mozilla::ErrorResult& aError);
void Home(mozilla::ErrorResult& aError);
bool FindOuter(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
bool aShowDialog, mozilla::ErrorResult& aError);
bool Find(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
bool aShowDialog, mozilla::ErrorResult& aError);
uint64_t GetMozPaintCountOuter();
uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
bool ShouldResistFingerprinting();
mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> OpenDialogOuter(JSContext* aCx,
const nsAString& aUrl,
const nsAString& aName,
const nsAString& aOptions,
const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
const nsAString& aUrl,
const nsAString& aName,
const nsAString& aOptions,
const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
mozilla::ErrorResult& aError);
void GetContentOuter(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
mozilla::ErrorResult& aError);
void GetContent(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval,
mozilla::ErrorResult& aError);
@ -1092,12 +1147,15 @@ public:
// ChromeWindow bits. Do NOT call these unless your window is in
// fact an nsGlobalChromeWindow.
uint16_t WindowState();
nsIBrowserDOMWindow* GetBrowserDOMWindowOuter();
nsIBrowserDOMWindow* GetBrowserDOMWindow(mozilla::ErrorResult& aError);
void SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow);
void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow,
mozilla::ErrorResult& aError);
void GetAttention(mozilla::ErrorResult& aError);
void GetAttentionWithCycleCount(int32_t aCycleCount,
mozilla::ErrorResult& aError);
void SetCursorOuter(const nsAString& aCursor, mozilla::ErrorResult& aError);
void SetCursor(const nsAString& aCursor, mozilla::ErrorResult& aError);
void Maximize(mozilla::ErrorResult& aError);
void Minimize(mozilla::ErrorResult& aError);
@ -1111,10 +1169,16 @@ public:
mozilla::dom::Element* aPanel,
mozilla::ErrorResult& aError);
void GetDialogArgumentsOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
void GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
void GetReturnValueOuter(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue,
mozilla::ErrorResult& aError);
void GetReturnValue(JSContext* aCx, JS::MutableHandle<JS::Value> aReturnValue,
mozilla::ErrorResult& aError);
void SetReturnValueOuter(JSContext* aCx, JS::Handle<JS::Value> aReturnValue,
mozilla::ErrorResult& aError);
void SetReturnValue(JSContext* aCx, JS::Handle<JS::Value> aReturnValue,
mozilla::ErrorResult& aError);
@ -1122,6 +1186,7 @@ public:
JS::MutableHandle<JS::Value> aRetval,
mozilla::ErrorResult& aError);
already_AddRefed<nsWindowRoot> GetWindowRootOuter();
already_AddRefed<nsWindowRoot> GetWindowRoot(mozilla::ErrorResult& aError);
protected:
@ -1147,17 +1212,29 @@ protected:
const char* aPropName,
mozilla::ErrorResult& aError);
// And the implementations of WindowCoordGetter/WindowCoordSetter.
int32_t GetInnerWidthOuter(mozilla::ErrorResult& aError);
int32_t GetInnerWidth(mozilla::ErrorResult& aError);
void SetInnerWidthOuter(int32_t aInnerWidth, mozilla::ErrorResult& aError);
void SetInnerWidth(int32_t aInnerWidth, mozilla::ErrorResult& aError);
int32_t GetInnerHeightOuter(mozilla::ErrorResult& aError);
int32_t GetInnerHeight(mozilla::ErrorResult& aError);
void SetInnerHeightOuter(int32_t aInnerHeight, mozilla::ErrorResult& aError);
void SetInnerHeight(int32_t aInnerHeight, mozilla::ErrorResult& aError);
int32_t GetScreenXOuter(mozilla::ErrorResult& aError);
int32_t GetScreenX(mozilla::ErrorResult& aError);
void SetScreenXOuter(int32_t aScreenX, mozilla::ErrorResult& aError);
void SetScreenX(int32_t aScreenX, mozilla::ErrorResult& aError);
int32_t GetScreenYOuter(mozilla::ErrorResult& aError);
int32_t GetScreenY(mozilla::ErrorResult& aError);
void SetScreenYOuter(int32_t aScreenY, mozilla::ErrorResult& aError);
void SetScreenY(int32_t aScreenY, mozilla::ErrorResult& aError);
int32_t GetOuterWidthOuter(mozilla::ErrorResult& aError);
int32_t GetOuterWidth(mozilla::ErrorResult& aError);
void SetOuterWidthOuter(int32_t aOuterWidth, mozilla::ErrorResult& aError);
void SetOuterWidth(int32_t aOuterWidth, mozilla::ErrorResult& aError);
int32_t GetOuterHeightOuter(mozilla::ErrorResult& aError);
int32_t GetOuterHeight(mozilla::ErrorResult& aError);
void SetOuterHeightOuter(int32_t aOuterHeight, mozilla::ErrorResult& aError);
void SetOuterHeight(int32_t aOuterHeight, mozilla::ErrorResult& aError);
// Array of idle observers that are notified of idle events.
@ -1405,6 +1482,7 @@ public:
// Outer windows only.
mozilla::CSSIntPoint GetScrollXY(bool aDoFlush);
void GetScrollMaxXYOuter(int32_t* aScrollMaxX, int32_t* aScrollMaxY);
void GetScrollMaxXY(int32_t* aScrollMaxX, int32_t* aScrollMaxY,
mozilla::ErrorResult& aError);
@ -1500,6 +1578,10 @@ protected:
nsDOMWindowList* GetWindowList();
// Helper for getComputedStyle and getDefaultComputedStyle
already_AddRefed<nsICSSDeclaration>
GetComputedStyleHelperOuter(mozilla::dom::Element& aElt,
const nsAString& aPseudoElt,
bool aDefaultStylesOnly);
already_AddRefed<nsICSSDeclaration>
GetComputedStyleHelper(mozilla::dom::Element& aElt,
const nsAString& aPseudoElt,
@ -1521,11 +1603,19 @@ protected:
nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);
void PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin,
JS::Handle<JS::Value> aTransfer,
mozilla::ErrorResult& aError);
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin,
JS::Handle<JS::Value> aTransfer,
mozilla::ErrorResult& aError);
already_AddRefed<nsIVariant>
ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgument,
const nsAString& aOptions, mozilla::ErrorResult& aError);
already_AddRefed<nsIVariant>
ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
const nsAString& aOptions, mozilla::ErrorResult& aError);
@ -1647,6 +1737,7 @@ protected:
nsRefPtr<mozilla::dom::Navigator> mNavigator;
nsRefPtr<nsScreen> mScreen;
nsRefPtr<nsDOMWindowList> mFrames;
// All BarProps are inner window only.
nsRefPtr<mozilla::dom::BarProp> mMenubar;
nsRefPtr<mozilla::dom::BarProp> mToolbar;
nsRefPtr<mozilla::dom::BarProp> mLocationbar;

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

@ -46,6 +46,7 @@ NS_INTERFACE_MAP_END
nsHistory::nsHistory(nsPIDOMWindow* aInnerWindow)
: mInnerWindow(do_GetWeakReference(aInnerWindow))
{
MOZ_ASSERT(aInnerWindow->IsInnerWindow());
}
nsHistory::~nsHistory()

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

@ -25,6 +25,7 @@ using namespace mozilla::dom;
nsScreen::Create(nsPIDOMWindow* aWindow)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
if (!aWindow->GetDocShell()) {
return nullptr;

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

@ -2415,7 +2415,7 @@ EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
}
bool
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[])
CheckAnyPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[])
{
JS::Rooted<JSObject*> rootedObj(aCx, aObj);
nsPIDOMWindow* window = xpc::WindowGlobalOrNull(rootedObj);
@ -2436,6 +2436,28 @@ CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[
return false;
}
bool
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[])
{
JS::Rooted<JSObject*> rootedObj(aCx, aObj);
nsPIDOMWindow* window = xpc::WindowGlobalOrNull(rootedObj);
if (!window) {
return false;
}
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
NS_ENSURE_TRUE(permMgr, false);
do {
uint32_t permission = nsIPermissionManager::DENY_ACTION;
permMgr->TestPermissionFromWindow(window, *aPermissions, &permission);
if (permission != nsIPermissionManager::ALLOW_ACTION) {
return false;
}
} while (*(++aPermissions));
return true;
}
void
HandlePrerenderingViolation(nsPIDOMWindow* aWindow)
{

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

@ -3094,7 +3094,12 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
// Returns true if aObj's global has any of the permissions named in aPermissions
// set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
bool
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
CheckAnyPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
// Returns true if aObj's global has all of the permissions named in aPermissions
// set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
bool
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
// This function is called by the bindings layer for methods/getters/setters
// that are not safe to be called in prerendering mode. It checks to make sure

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

@ -1895,11 +1895,12 @@ class MemberCondition:
None, they should be strings that have the pref name (for "pref")
or function name (for "func" and "available").
"""
def __init__(self, pref, func, available=None, checkPermissions=None):
def __init__(self, pref, func, available=None, checkAnyPermissions=None, checkAllPermissions=None):
assert pref is None or isinstance(pref, str)
assert func is None or isinstance(func, str)
assert available is None or isinstance(available, str)
assert checkPermissions is None or isinstance(checkPermissions, int)
assert checkAnyPermissions is None or isinstance(checkAnyPermissions, int)
assert checkAllPermissions is None or isinstance(checkAllPermissions, int)
self.pref = pref
def toFuncPtr(val):
@ -1908,15 +1909,20 @@ class MemberCondition:
return "&" + val
self.func = toFuncPtr(func)
self.available = toFuncPtr(available)
if checkPermissions is None:
self.checkPermissions = "nullptr"
if checkAnyPermissions is None:
self.checkAnyPermissions = "nullptr"
else:
self.checkPermissions = "permissions_%i" % checkPermissions
self.checkAnyPermissions = "anypermissions_%i" % checkAnyPermissions
if checkAllPermissions is None:
self.checkAllPermissions = "nullptr"
else:
self.checkAllPermissions = "allpermissions_%i" % checkAllPermissions
def __eq__(self, other):
return (self.pref == other.pref and self.func == other.func and
self.available == other.available and
self.checkPermissions == other.checkPermissions)
self.checkAnyPermissions == other.checkAnyPermissions and
self.checkAllPermissions == other.checkAllPermissions)
def __ne__(self, other):
return not self.__eq__(other)
@ -1984,7 +1990,8 @@ class PropertyDefiner:
PropertyDefiner.getStringAttr(interfaceMember,
"Func"),
getAvailableInTestFunc(interfaceMember),
descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
descriptor.checkAnyPermissionsIndicesForMembers.get(interfaceMember.identifier.name),
descriptor.checkAllPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
def generatePrefableArray(self, array, name, specFormatter, specTerminator,
specType, getCondition, getDataTuple, doIdArrays):
@ -2022,7 +2029,7 @@ class PropertyDefiner:
specs = []
prefableSpecs = []
prefableTemplate = ' { true, %s, %s, %s, &%s[%d] }'
prefableTemplate = ' { true, %s, %s, %s, %s, &%s[%d] }'
prefCacheTemplate = '&%s[%d].enabled'
def switchToCondition(props, condition):
@ -2036,7 +2043,8 @@ class PropertyDefiner:
prefableSpecs.append(prefableTemplate %
(condition.func,
condition.available,
condition.checkPermissions,
condition.checkAnyPermissions,
condition.checkAllPermissions,
name + "_specs", len(specs)))
switchToCondition(self, lastCondition)
@ -3167,9 +3175,12 @@ class CGConstructorEnabled(CGAbstractMethod):
availableIn = getAvailableInTestFunc(iface)
if availableIn:
conditions.append("%s(aCx, aObj)" % availableIn)
checkPermissions = self.descriptor.checkPermissionsIndex
if checkPermissions is not None:
conditions.append("CheckPermissions(aCx, aObj, permissions_%i)" % checkPermissions)
checkAnyPermissions = self.descriptor.checkAnyPermissionsIndex
if checkAnyPermissions is not None:
conditions.append("CheckAnyPermissions(aCx, aObj, anypermissions_%i)" % checkAnyPermissions)
checkAllPermissions = self.descriptor.checkAllPermissionsIndex
if checkAllPermissions is not None:
conditions.append("CheckAllPermissions(aCx, aObj, allpermissions_%i)" % checkAllPermissions)
# We should really have some conditions
assert len(body) or len(conditions)
@ -5575,13 +5586,13 @@ def convertConstIDLValueToJSVal(value):
IDLType.Tags.uint16, IDLType.Tags.int32]:
return "JS::Int32Value(%s)" % (value.value)
if tag == IDLType.Tags.uint32:
return "UINT_TO_JSVAL(%sU)" % (value.value)
return "JS::NumberValue(%sU)" % (value.value)
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
return "DOUBLE_TO_JSVAL(%s)" % numericValue(tag, value.value)
return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag, value.value)
if tag == IDLType.Tags.bool:
return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
if tag in [IDLType.Tags.float, IDLType.Tags.double]:
return "DOUBLE_TO_JSVAL(%s)" % (value.value)
return "JS::CanonicalizedDoubleValue(%s)" % (value.value)
raise TypeError("Const value of unhandled type: %s" % value.type)
@ -11436,14 +11447,16 @@ class CGDescriptor(CGThing):
if descriptor.concrete and descriptor.wrapperCache:
cgThings.append(CGClassObjectMovedHook(descriptor))
if len(descriptor.permissions):
for (k, v) in sorted(descriptor.permissions.items()):
perms = CGList((CGGeneric('"%s",' % p) for p in k), joiner="\n")
perms.append(CGGeneric("nullptr"))
cgThings.append(CGWrapper(CGIndenter(perms),
pre="static const char* const permissions_%i[] = {\n" % v,
post="\n};\n",
defineOnly=True))
for name in ["anypermissions", "allpermissions"]:
permissions = getattr(descriptor, name)
if len(permissions):
for (k, v) in sorted(permissions.items()):
perms = CGList((CGGeneric('"%s",' % p) for p in k), joiner="\n")
perms.append(CGGeneric("nullptr"))
cgThings.append(CGWrapper(CGIndenter(perms),
pre="static const char* const %s_%i[] = {\n" % (name, v),
post="\n};\n",
defineOnly=True))
# Generate the _ClearCachedFooValue methods before the property arrays that use them.
if descriptor.interface.isJSImplemented():

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

@ -546,11 +546,17 @@ class Descriptor(DescriptorProvider):
self._binaryNames.setdefault('__stringifier', 'Stringify')
if not self.interface.isExternal():
self.permissions = dict()
self.anypermissions = dict()
self.allpermissions = dict()
# Adds a permission list to this descriptor and returns the index to use.
def addPermissions(ifaceOrMember):
checkPermissions = ifaceOrMember.getExtendedAttribute("CheckPermissions")
def addPermissions(ifaceOrMember, attribute):
if attribute == "CheckAllPermissions":
permissions = self.allpermissions
else:
permissions = self.anypermissions
checkPermissions = ifaceOrMember.getExtendedAttribute(attribute)
if checkPermissions is None:
return None
@ -560,17 +566,22 @@ class Descriptor(DescriptorProvider):
checkPermissions = checkPermissions[0]
permissionsList = checkPermissions.split()
if len(permissionsList) == 0:
raise TypeError("Need at least one permission name for CheckPermissions")
raise TypeError("Need at least one permission name for %s" % attribute)
permissionsList = tuple(sorted(set(permissionsList)))
return self.permissions.setdefault(permissionsList, len(self.permissions))
return permissions.setdefault(permissionsList, len(permissions))
self.checkPermissionsIndex = addPermissions(self.interface)
self.checkPermissionsIndicesForMembers = dict()
self.checkAnyPermissionsIndex = addPermissions(self.interface, "CheckAnyPermissions")
self.checkAnyPermissionsIndicesForMembers = dict()
self.checkAllPermissionsIndex = addPermissions(self.interface, "CheckAllPermissions")
self.checkAllPermissionsIndicesForMembers = dict()
for m in self.interface.members:
permissionsIndex = addPermissions(m)
permissionsIndex = addPermissions(m, "CheckAnyPermissions")
if permissionsIndex is not None:
self.checkPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex
self.checkAnyPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex
allpermissionsIndex = addPermissions(m, "CheckAllPermissions")
if allpermissionsIndex is not None:
self.checkAllPermissionsIndicesForMembers[m.identifier.name] = allpermissionsIndex
def isTestInterface(iface):
return (iface.identifier.name in ["TestInterface",
@ -579,7 +590,8 @@ class Descriptor(DescriptorProvider):
self.featureDetectibleThings = set()
if not isTestInterface(self.interface):
if (self.interface.getExtendedAttribute("CheckPermissions") or
if (self.interface.getExtendedAttribute("CheckAnyPermissions") or
self.interface.getExtendedAttribute("CheckAllPermissions") or
self.interface.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
if self.interface.getNavigatorProperty():
self.featureDetectibleThings.add("Navigator.%s" % self.interface.getNavigatorProperty())
@ -590,7 +602,8 @@ class Descriptor(DescriptorProvider):
self.featureDetectibleThings.add("%s.%s" % (iface, m.identifier.name))
for m in self.interface.members:
if (m.getExtendedAttribute("CheckPermissions") or
if (m.getExtendedAttribute("CheckAnyPermissions") or
m.getExtendedAttribute("CheckAllPermissions") or
m.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
self.featureDetectibleThings.add("%s.%s" % (self.interface.identifier.name, m.identifier.name))

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

@ -40,7 +40,10 @@ typedef bool
JS::AutoIdVector& props);
bool
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
CheckAnyPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
bool
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
struct ConstantSpec
{
@ -56,7 +59,7 @@ struct Prefable {
if (!enabled) {
return false;
}
if (!enabledFunc && !availableFunc && !checkPermissions) {
if (!enabledFunc && !availableFunc && !checkAnyPermissions && !checkAllPermissions) {
return true;
}
if (enabledFunc &&
@ -67,9 +70,14 @@ struct Prefable {
!availableFunc(cx, js::GetGlobalForObjectCrossCompartment(obj))) {
return false;
}
if (checkPermissions &&
!CheckPermissions(cx, js::GetGlobalForObjectCrossCompartment(obj),
checkPermissions)) {
if (checkAnyPermissions &&
!CheckAnyPermissions(cx, js::GetGlobalForObjectCrossCompartment(obj),
checkAnyPermissions)) {
return false;
}
if (checkAllPermissions &&
!CheckAllPermissions(cx, js::GetGlobalForObjectCrossCompartment(obj),
checkAllPermissions)) {
return false;
}
return true;
@ -86,7 +94,8 @@ struct Prefable {
// is basically a hack to avoid having to codegen PropertyEnabled
// implementations in case when we need to do two separate checks.
PropertyEnabled availableFunc;
const char* const* checkPermissions;
const char* const* checkAnyPermissions;
const char* const* checkAllPermissions;
// Array of specs, terminated in whatever way is customary for T.
// Null to indicate a end-of-array for Prefable, when such an
// indicator is needed.

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

@ -1134,7 +1134,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
member.getExtendedAttribute("Pref") or
member.getExtendedAttribute("Func") or
member.getExtendedAttribute("AvailableIn") or
member.getExtendedAttribute("CheckPermissions")):
member.getExtendedAttribute("CheckAnyPermissions") or
member.getExtendedAttribute("CheckAllPermissions")):
raise WebIDLError("[Alias] must not be used on a "
"conditionally exposed operation",
[member.location])
@ -1166,12 +1167,13 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
self.parentScope.primaryGlobalName,
[self.location])
if (self.getExtendedAttribute("CheckPermissions") and
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
raise WebIDLError("[CheckPermissions] used on an interface that is "
"not %s-only" %
self.parentScope.primaryGlobalName,
[self.location])
for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
if (self.getExtendedAttribute(attribute) and
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
raise WebIDLError("[%s] used on an interface that is "
"not %s-only" %
(attribute, self.parentScope.primaryGlobalName),
[self.location])
# Conditional exposure makes no sense for interfaces with no
# interface object, unless they're navigator properties.
@ -1385,7 +1387,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
identifier == "NavigatorProperty" or
identifier == "AvailableIn" or
identifier == "Func" or
identifier == "CheckPermissions"):
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions"):
# Known extended attributes that take a string value
if not attr.hasValue():
raise WebIDLError("[%s] must have a value" % identifier,
@ -1513,7 +1516,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
self.getExtendedAttribute("ChromeOnly") or
self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckPermissions"))
self.getExtendedAttribute("CheckAnyPermissions") or
self.getExtendedAttribute("CheckAllPermissions"))
class IDLDictionary(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members):
@ -3361,12 +3365,13 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
"%s-only" % self._globalScope.primaryGlobalName,
[self.location])
if (self.getExtendedAttribute("CheckPermissions") and
self.exposureSet != set([self._globalScope.primaryGlobalName])):
raise WebIDLError("[CheckPermissions] used on an interface member "
"that is not %s-only" %
self._globalScope.primaryGlobalName,
[self.location])
for attribute in ["CheckAnyPermissions", "CheckAllPermissions"]:
if (self.getExtendedAttribute(attribute) and
self.exposureSet != set([self._globalScope.primaryGlobalName])):
raise WebIDLError("[%s] used on an interface member that is "
"not %s-only" %
(attribute, self.parentScope.primaryGlobalName),
[self.location])
if self.isAttr() or self.isMethod():
if self.affects == "Everything" and self.dependsOn != "Everything":
@ -3707,7 +3712,8 @@ class IDLConst(IDLInterfaceMember):
identifier == "ChromeOnly" or
identifier == "Func" or
identifier == "AvailableIn" or
identifier == "CheckPermissions"):
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions"):
# Known attributes that we don't need to do anything with here
pass
else:
@ -3974,7 +3980,8 @@ class IDLAttribute(IDLInterfaceMember):
identifier == "AvailableIn" or
identifier == "NewObject" or
identifier == "UnsafeInPrerendering" or
identifier == "CheckPermissions" or
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions" or
identifier == "BinaryName"):
# Known attributes that we don't need to do anything with here
pass
@ -4649,7 +4656,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
identifier == "Deprecated" or
identifier == "Func" or
identifier == "AvailableIn" or
identifier == "CheckPermissions" or
identifier == "CheckAnyPermissions" or
identifier == "CheckAllPermissions" or
identifier == "BinaryName" or
identifier == "MethodIdentityTestable" or
identifier == "StaticClassOverride"):

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

@ -77,77 +77,6 @@ BroadcastChannelService::UnregisterActor(BroadcastChannelParent* aParent)
mAgents.RemoveEntry(aParent);
}
namespace {
struct MOZ_STACK_CLASS PostMessageData final
{
PostMessageData(BroadcastChannelParent* aParent,
const ClonedMessageData& aData,
const nsACString& aOrigin,
uint64_t aAppId,
bool aIsInBrowserElement,
const nsAString& aChannel,
bool aPrivateBrowsing)
: mParent(aParent)
, mData(aData)
, mOrigin(aOrigin)
, mChannel(aChannel)
, mAppId(aAppId)
, mIsInBrowserElement(aIsInBrowserElement)
, mPrivateBrowsing(aPrivateBrowsing)
{
MOZ_ASSERT(aParent);
MOZ_COUNT_CTOR(PostMessageData);
// We need to keep the array alive for the life-time of this
// PostMessageData.
if (!aData.blobsParent().IsEmpty()) {
mBlobs.SetCapacity(aData.blobsParent().Length());
for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) {
nsRefPtr<BlobImpl> impl =
static_cast<BlobParent*>(aData.blobsParent()[i])->GetBlobImpl();
MOZ_ASSERT(impl);
mBlobs.AppendElement(impl);
}
}
}
~PostMessageData()
{
MOZ_COUNT_DTOR(PostMessageData);
}
BroadcastChannelParent* mParent;
const ClonedMessageData& mData;
nsTArray<nsRefPtr<BlobImpl>> mBlobs;
const nsCString mOrigin;
const nsString mChannel;
uint64_t mAppId;
bool mIsInBrowserElement;
bool mPrivateBrowsing;
};
PLDHashOperator
PostMessageEnumerator(nsPtrHashKey<BroadcastChannelParent>* aKey, void* aPtr)
{
AssertIsOnBackgroundThread();
auto* data = static_cast<PostMessageData*>(aPtr);
BroadcastChannelParent* parent = aKey->GetKey();
MOZ_ASSERT(parent);
if (parent != data->mParent) {
parent->CheckAndDeliver(data->mData, data->mOrigin, data->mAppId,
data->mIsInBrowserElement, data->mChannel,
data->mPrivateBrowsing);
}
return PL_DHASH_NEXT;
}
} // namespace
void
BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent,
const ClonedMessageData& aData,
@ -161,9 +90,29 @@ BroadcastChannelService::PostMessage(BroadcastChannelParent* aParent,
MOZ_ASSERT(aParent);
MOZ_ASSERT(mAgents.Contains(aParent));
PostMessageData data(aParent, aData, aOrigin, aAppId, aIsInBrowserElement,
aChannel, aPrivateBrowsing);
mAgents.EnumerateEntries(PostMessageEnumerator, &data);
// We need to keep the array alive for the life-time of this operation.
nsTArray<nsRefPtr<BlobImpl>> blobs;
if (!aData.blobsParent().IsEmpty()) {
blobs.SetCapacity(aData.blobsParent().Length());
for (uint32_t i = 0, len = aData.blobsParent().Length(); i < len; ++i) {
nsRefPtr<BlobImpl> impl =
static_cast<BlobParent*>(aData.blobsParent()[i])->GetBlobImpl();
MOZ_ASSERT(impl);
blobs.AppendElement(impl);
}
}
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
BroadcastChannelParent* parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
if (parent != aParent) {
parent->CheckAndDeliver(aData, PromiseFlatCString(aOrigin),
aAppId, aIsInBrowserElement,
PromiseFlatString(aChannel), aPrivateBrowsing);
}
}
}
} // namespace dom

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

@ -238,6 +238,7 @@ BrowserElementChild.prototype = {
"find-all": this._recvFindAll.bind(this),
"find-next": this._recvFindNext.bind(this),
"clear-match": this._recvClearMatch.bind(this),
"execute-script": this._recvExecuteScript,
"get-audio-channel-volume": this._recvGetAudioChannelVolume,
"set-audio-channel-volume": this._recvSetAudioChannelVolume,
"get-audio-channel-muted": this._recvGetAudioChannelMuted,
@ -984,6 +985,90 @@ BrowserElementChild.prototype = {
takeScreenshotClosure, maxDelayMS);
},
_recvExecuteScript: function(data) {
debug("Received executeScript message: (" + data.json.id + ")");
let domRequestID = data.json.id;
let sendError = errorMsg => sendAsyncMsg("execute-script-done", {
errorMsg,
id: domRequestID
});
let sendSuccess = successRv => sendAsyncMsg("execute-script-done", {
successRv,
id: domRequestID
});
let isJSON = obj => {
try {
JSON.stringify(obj);
} catch(e) {
return false;
}
return true;
}
let expectedOrigin = data.json.args.options.origin;
let expectedUrl = data.json.args.options.url;
if (expectedOrigin) {
if (expectedOrigin != content.location.origin) {
sendError("Origin mismatches");
return;
}
}
if (expectedUrl) {
let expectedURI
try {
expectedURI = Services.io.newURI(expectedUrl, null, null);
} catch(e) {
sendError("Malformed URL");
return;
}
let currentURI = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
if (!currentURI.equalsExceptRef(expectedURI)) {
sendError("URL mismatches");
return;
}
}
let sandbox = new Cu.Sandbox([content], {
sandboxPrototype: content,
sandboxName: "browser-api-execute-script",
allowWaivers: false,
sameZoneAs: content
});
try {
let sandboxRv = Cu.evalInSandbox(data.json.args.script, sandbox, "1.8");
if (sandboxRv instanceof Promise) {
sandboxRv.then(rv => {
if (isJSON(rv)) {
sendSuccess(rv);
} else {
sendError("Value returned (resolve) by promise is not a valid JSON object");
}
}, error => {
if (isJSON(error)) {
sendError(error);
} else {
sendError("Value returned (reject) by promise is not a valid JSON object");
}
});
} else {
if (isJSON(sandboxRv)) {
sendSuccess(sandboxRv);
} else {
sendError("Script last expression must be a promise or a JSON object");
}
}
} catch(e) {
sendError(e.toString());
}
},
_recvGetContentDimensions: function(data) {
debug("Received getContentDimensions message: (" + data.json.id + ")");
sendAsyncMsg('got-contentdimensions', {

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

@ -207,6 +207,7 @@ BrowserElementParent.prototype = {
"scrollviewchange": this._handleScrollViewChange,
"caretstatechanged": this._handleCaretStateChanged,
"findchange": this._handleFindChange,
"execute-script-done": this._gotDOMRequestResult,
"got-audio-channel-volume": this._gotDOMRequestResult,
"got-set-audio-channel-volume": this._gotDOMRequestResult,
"got-audio-channel-muted": this._gotDOMRequestResult,
@ -692,6 +693,19 @@ BrowserElementParent.prototype = {
this._sendAsyncMsg('stop');
}),
executeScript: function(script, options) {
if (!this._isAlive()) {
throw Components.Exception("Dead content process",
Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
}
// Enforcing options.url or options.origin
if (!options.url && !options.origin) {
throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
}
return this._sendDOMRequest('execute-script', {script, options});
},
/*
* The valid range of zoom scale is defined in preference "zoom.maxPercent" and "zoom.minPercent".
*/

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

@ -0,0 +1,119 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 1174733 - Browser API: iframe.executeScript
'use strict';
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
function runTest() {
const origin = 'http://example.org';
const url = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_ExecuteScript.html';
// Test if all key=>value pairs in o1 are present in o2.
const c = (o1, o2) => Object.keys(o1).every(k => o1[k] == o2[k]);
let scriptId = 0;
const bail = () => {
ok(false, `scriptId: ${scriptId++}`);
}
SpecialPowers.pushPermissions([
{type: 'browser', allow: 1, context: document},
{type: 'browser:universalxss', allow: 1, context: document}
], function() {
let iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.addEventListener('mozbrowserloadend', function onload() {
iframe.removeEventListener('mozbrowserloadend', onload);
onReady(iframe);
});
iframe.src = url;
document.body.appendChild(iframe);
});
function onReady(iframe) {
iframe.executeScript('4 + 4', {url}).then(rv => {
is(rv, 8, `scriptId: ${scriptId++}`);
return iframe.executeScript('(() => {return {a:42}})()', {url})
}, bail).then(rv => {
ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
return iframe.executeScript('(() => {return {a:42}})()', {origin})
}, bail).then(rv => {
ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
return iframe.executeScript('(() => {return {a:42}})()', {origin, url})
}, bail).then(rv => {
ok(c(rv, {a:42}), `scriptId: ${scriptId++}`);
return iframe.executeScript(`
new Promise((resolve, reject) => {
resolve(document.body.textContent.trim());
});
`, {url})
}, bail).then(rv => {
is(rv, 'foo', `scriptId: ${scriptId++}`);
return iframe.executeScript(`
new Promise((resolve, reject) => {
resolve({a:43,b:34});
});
`, {url})
}, bail).then(rv => {
ok(c(rv, {a:43,b:34}), `scriptId: ${scriptId++}`);
return iframe.executeScript(`
syntax error
`, {url});
}, bail).then(bail, (error) => {
is(error.name, 'SyntaxError: illegal character', `scriptId: ${scriptId++}`);
return iframe.executeScript(`
window
`, {url});
}).then(bail, (error) => {
is(error.name, 'Script last expression must be a promise or a JSON object', `scriptId: ${scriptId++}`);
return iframe.executeScript(`
new Promise((resolve, reject) => {
reject('BOOM');
});
`, {url});
}).then(bail, (error) => {
is(error.name, 'BOOM', `scriptId: ${scriptId++}`);
return iframe.executeScript(`
new Promise((resolve, reject) => {
resolve(window);
});
`, {url});
}).then(bail, (error) => {
is(error.name, 'Value returned (resolve) by promise is not a valid JSON object', `scriptId: ${scriptId++}`);
return iframe.executeScript('window.btoa("a")', {url})
}, bail).then(rv => {
ok(c(rv, 'YQ=='), `scriptId: ${scriptId++}`);
return iframe.executeScript('window.wrappedJSObject.btoa("a")', {url})
}, bail).then(bail, (error) => {
is(error.name, 'TypeError: window.wrappedJSObject is undefined', `scriptId: ${scriptId++}`);
return iframe.executeScript('42', {})
}).then(bail, error => {
is(error.name, 'InvalidAccessError', `scriptId: ${scriptId++}`);
return iframe.executeScript('42');
}).then(bail, error => {
is(error.name, 'InvalidAccessError', `scriptId: ${scriptId++}`);
return iframe.executeScript('43', { url: 'http://foo.com' });
}).then(bail, (error) => {
is(error.name, 'URL mismatches', `scriptId: ${scriptId++}`);
return iframe.executeScript('43', { url: '_' });
}, bail).then(bail, (error) => {
is(error.name, 'Malformed URL', `scriptId: ${scriptId++}`);
return iframe.executeScript('43', { origin: 'http://foo.com' });
}, bail).then(bail, (error) => {
is(error.name, 'Origin mismatches', `scriptId: ${scriptId++}`);
return iframe.executeScript('43', { origin: 'https://example.org' });
}, bail).then(bail, (error) => {
is(error.name, 'Origin mismatches', `scriptId: ${scriptId++}`);
SimpleTest.finish();
});
}
}
addEventListener('testready', runTest);

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

@ -0,0 +1,8 @@
<html>
<head>
<script>
window.btoa = () => "fake btoa";
</script>
</head>
<body>foo</body>
</html>

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

@ -6,7 +6,9 @@
skip-if = os == "android" || (toolkit == "cocoa" && debug) || buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
support-files =
browserElement_OpenMixedProcess.js
file_browserElement_ExecuteScript.html
file_browserElement_OpenMixedProcess.html
browserElement_ExecuteScript.js
browserElement_Find.js
browserElement_OpenTab.js
@ -42,6 +44,7 @@ skip-if = (toolkit == 'gonk' && !debug)
disabled = bug 1022281
[test_browserElement_oop_ErrorSecurity.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_ExecuteScript.html]
[test_browserElement_oop_Find.html]
[test_browserElement_oop_FirstPaint.html]
[test_browserElement_oop_ForwardName.html]

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

@ -28,6 +28,7 @@ support-files =
browserElement_DocumentFirstPaint.js
browserElement_Download.js
browserElement_ErrorSecurity.js
browserElement_ExecuteScript.js
browserElement_ExposableURI.js
browserElement_Find.js
browserElement_FirstPaint.js
@ -88,6 +89,7 @@ support-files =
file_browserElement_CloseFromOpener.html
file_browserElement_CookiesNotThirdParty.html
file_browserElement_DisallowEmbedAppsInOOP.html
file_browserElement_ExecuteScript.html
file_browserElement_ForwardName.html
file_browserElement_FrameWrongURI.html
file_browserElement_LoadEvents.html
@ -163,6 +165,7 @@ skip-if = os == "android" || toolkit == 'gonk' # embed-apps doesn't work in the
[test_browserElement_inproc_DocumentFirstPaint.html]
[test_browserElement_inproc_Download.html]
disabled = bug 1022281
[test_browserElement_inproc_ExecuteScript.html]
[test_browserElement_inproc_ExposableURI.html]
[test_browserElement_inproc_Find.html]
[test_browserElement_inproc_FirstPaint.html]

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

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1174733
-->
<head>
<title>Test for Bug 1163961</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1174733">Mozilla Bug 1174733</a>
<script type="application/javascript;version=1.7" src="browserElement_ExecuteScript.js">
</script>
</body>
</html>

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

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1174733
-->
<head>
<title>Test for Bug 1163961</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1174733">Mozilla Bug 1174733</a>
<script type="application/javascript;version=1.7" src="browserElement_ExecuteScript.js">
</script>
</body>
</html>

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

@ -26,7 +26,7 @@ interface nsIBrowserElementNextPaintListener : nsISupports
* Interface to the BrowserElementParent implementation. All methods
* but setFrameLoader throw when the remote process is dead.
*/
[scriptable, uuid(daa264b2-54df-4fc7-89b7-c9d02167c5d4)]
[scriptable, uuid(26a832d1-9d71-43ef-9d46-9d7c8ec33f00)]
interface nsIBrowserElementAPI : nsISupports
{
const long FIND_CASE_SENSITIVE = 0;
@ -91,4 +91,6 @@ interface nsIBrowserElementAPI : nsISupports
nsIDOMDOMRequest isAudioChannelActive(in uint32_t audioChannel);
void setNFCFocus(in boolean isFocus);
nsIDOMDOMRequest executeScript(in DOMString script, in jsval options);
};

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

@ -805,18 +805,8 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_SELECTION_SET:
{
WidgetSelectionEvent* selectionEvent = aEvent->AsSelectionEvent();
if (IsTargetCrossProcess(selectionEvent)) {
// Will not be handled locally, remote the event
if (GetCrossProcessTarget()->SendSelectionEvent(*selectionEvent)) {
selectionEvent->mSucceeded = true;
}
break;
}
ContentEventHandler handler(mPresContext);
handler.OnSelectionEvent(selectionEvent);
}
IMEStateManager::HandleSelectionEvent(aPresContext, GetFocusedContent(),
aEvent->AsSelectionEvent());
break;
case NS_CONTENT_COMMAND_CUT:
case NS_CONTENT_COMMAND_COPY:

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

@ -95,6 +95,7 @@ IMEContentObserver::IMEContentObserver()
, mIsFocusEventPending(false)
, mIsSelectionChangeEventPending(false)
, mSelectionChangeCausedOnlyByComposition(false)
, mSelectionChangeCausedOnlyBySelectionEvent(false)
, mIsPositionChangeEventPending(false)
, mIsFlushingPendingNotifications(false)
{
@ -418,7 +419,9 @@ IMEContentObserver::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
nsresult rv = aSelection->GetRangeCount(&count);
NS_ENSURE_SUCCESS(rv, rv);
if (count > 0 && mWidget) {
MaybeNotifyIMEOfSelectionChange(causedByComposition);
bool causedBySelectionEvent = TextComposition::IsHandlingSelectionEvent();
MaybeNotifyIMEOfSelectionChange(causedByComposition,
causedBySelectionEvent);
}
return NS_OK;
}
@ -828,7 +831,9 @@ IMEContentObserver::PostTextChangeNotification(
}
void
IMEContentObserver::PostSelectionChangeNotification(bool aCausedByComposition)
IMEContentObserver::PostSelectionChangeNotification(
bool aCausedByComposition,
bool aCausedBySelectionEvent)
{
if (!mIsSelectionChangeEventPending) {
mSelectionChangeCausedOnlyByComposition = aCausedByComposition;
@ -836,6 +841,12 @@ IMEContentObserver::PostSelectionChangeNotification(bool aCausedByComposition)
mSelectionChangeCausedOnlyByComposition =
mSelectionChangeCausedOnlyByComposition && aCausedByComposition;
}
if (!mSelectionChangeCausedOnlyBySelectionEvent) {
mSelectionChangeCausedOnlyBySelectionEvent = aCausedBySelectionEvent;
} else {
mSelectionChangeCausedOnlyBySelectionEvent =
mSelectionChangeCausedOnlyBySelectionEvent && aCausedBySelectionEvent;
}
mIsSelectionChangeEventPending = true;
}
@ -939,7 +950,8 @@ IMEContentObserver::FlushMergeableNotifications()
if (mIsSelectionChangeEventPending) {
mIsSelectionChangeEventPending = false;
nsContentUtils::AddScriptRunner(
new SelectionChangeEvent(this, mSelectionChangeCausedOnlyByComposition));
new SelectionChangeEvent(this, mSelectionChangeCausedOnlyByComposition,
mSelectionChangeCausedOnlyBySelectionEvent));
}
if (mIsPositionChangeEventPending) {
@ -1041,7 +1053,8 @@ IMEContentObserver::SelectionChangeEvent::Run()
}
if (!IsSafeToNotifyIME()) {
mIMEContentObserver->PostSelectionChangeNotification(mCausedByComposition);
mIMEContentObserver->PostSelectionChangeNotification(
mCausedByComposition, mCausedBySelectionEvent);
return NS_OK;
}
@ -1070,6 +1083,8 @@ IMEContentObserver::SelectionChangeEvent::Run()
notification.mSelectionChangeData.mReversed = selection.mReply.mReversed;
notification.mSelectionChangeData.mCausedByComposition =
mCausedByComposition;
notification.mSelectionChangeData.mCausedBySelectionEvent =
mCausedBySelectionEvent;
IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget);
return NS_OK;
}

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

@ -132,10 +132,13 @@ private:
PostTextChangeNotification(aTextChangeData);
FlushMergeableNotifications();
}
void PostSelectionChangeNotification(bool aCausedByComposition);
void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition)
void PostSelectionChangeNotification(bool aCausedByComposition,
bool aCausedBySelectionEvent);
void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition,
bool aCausedBySelectionEvent)
{
PostSelectionChangeNotification(aCausedByComposition);
PostSelectionChangeNotification(aCausedByComposition,
aCausedBySelectionEvent);
FlushMergeableNotifications();
}
void PostPositionChangeNotification();
@ -239,6 +242,7 @@ private:
bool mIsFocusEventPending;
bool mIsSelectionChangeEventPending;
bool mSelectionChangeCausedOnlyByComposition;
bool mSelectionChangeCausedOnlyBySelectionEvent;
bool mIsPositionChangeEventPending;
bool mIsFlushingPendingNotifications;
@ -295,15 +299,20 @@ private:
{
public:
SelectionChangeEvent(IMEContentObserver* aIMEContentObserver,
bool aCausedByComposition)
bool aCausedByComposition,
bool aCausedBySelectionEvent)
: AChangeEvent(eChangeEventType_Selection, aIMEContentObserver)
, mCausedByComposition(aCausedByComposition)
, mCausedBySelectionEvent(aCausedBySelectionEvent)
{
aIMEContentObserver->mSelectionChangeCausedOnlyByComposition = false;
aIMEContentObserver->mSelectionChangeCausedOnlyBySelectionEvent = false;
}
NS_IMETHOD Run() override;
private:
bool mCausedByComposition;
bool mCausedBySelectionEvent;
};
class TextChangeEvent : public AChangeEvent

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

@ -149,6 +149,8 @@ GetEventMessageName(uint32_t aMessage)
return "NS_COMPOSITION_COMMIT_AS_IS";
case NS_COMPOSITION_COMMIT:
return "NS_COMPOSITION_COMMIT";
case NS_SELECTION_SET:
return "NS_SELECTION_SET";
default:
return "unacceptable event message";
}
@ -1205,6 +1207,56 @@ IMEStateManager::DispatchCompositionEvent(
}
}
// static
nsIContent*
IMEStateManager::GetRootContent(nsPresContext* aPresContext)
{
nsIDocument* doc = aPresContext->Document();
if (NS_WARN_IF(!doc)) {
return nullptr;
}
return doc->GetRootElement();
}
// static
void
IMEStateManager::HandleSelectionEvent(nsPresContext* aPresContext,
nsIContent* aEventTargetContent,
WidgetSelectionEvent* aSelectionEvent)
{
nsIContent* eventTargetContent =
aEventTargetContent ? aEventTargetContent :
GetRootContent(aPresContext);
nsRefPtr<TabParent> tabParent =
eventTargetContent ? TabParent::GetFrom(eventTargetContent) : nullptr;
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::HandleSelectionEvent(aPresContext=0x%p, "
"aEventTargetContent=0x%p, aSelectionEvent={ message=%s, "
"mFlags={ mIsTrusted=%s } }), tabParent=%p",
aPresContext, aEventTargetContent,
GetEventMessageName(aSelectionEvent->message),
GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
tabParent.get()));
if (!aSelectionEvent->mFlags.mIsTrusted) {
return;
}
nsRefPtr<TextComposition> composition = sTextCompositions ?
sTextCompositions->GetCompositionFor(aSelectionEvent->widget) : nullptr;
if (composition) {
// When there is a composition, TextComposition should guarantee that the
// selection event will be handled in same target as composition events.
composition->HandleSelectionEvent(aSelectionEvent);
} else {
// When there is no composition, the selection event should be handled
// in the aPresContext or tabParent.
TextComposition::HandleSelectionEvent(aPresContext, tabParent,
aSelectionEvent);
}
}
// static
void
IMEStateManager::OnCompositionEventDiscarded(

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

@ -152,6 +152,15 @@ public:
EventDispatchingCallback* aCallBack,
bool aIsSynthesized = false);
/**
* All selection events must be handled via HandleSelectionEvent()
* because they must be handled by same target as composition events when
* there is a composition.
*/
static void HandleSelectionEvent(nsPresContext* aPresContext,
nsIContent* aEventTargetContent,
WidgetSelectionEvent* aSelectionEvent);
/**
* This is called when PresShell ignores a composition event due to not safe
* to dispatch events.
@ -212,6 +221,8 @@ protected:
static bool IsIMEObserverNeeded(const IMEState& aState);
static nsIContent* GetRootContent(nsPresContext* aPresContext);
static StaticRefPtr<nsIContent> sContent;
static nsPresContext* sPresContext;
static StaticRefPtr<nsIWidget> sFocusedIMEWidget;

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

@ -30,6 +30,8 @@ namespace mozilla {
* TextComposition
******************************************************************************/
bool TextComposition::sHandlingSelectionEvent = false;
TextComposition::TextComposition(nsPresContext* aPresContext,
nsINode* aNode,
TabParent* aTabParent,
@ -374,6 +376,30 @@ TextComposition::DispatchCompositionEvent(
NotityUpdateComposition(aCompositionEvent);
}
// static
void
TextComposition::HandleSelectionEvent(nsPresContext* aPresContext,
TabParent* aTabParent,
WidgetSelectionEvent* aSelectionEvent)
{
// If the content is a container of TabParent, composition should be in the
// remote process.
if (aTabParent) {
unused << aTabParent->SendSelectionEvent(*aSelectionEvent);
aSelectionEvent->mFlags.mPropagationStopped = true;
return;
}
ContentEventHandler handler(aPresContext);
AutoRestore<bool> saveHandlingSelectionEvent(sHandlingSelectionEvent);
sHandlingSelectionEvent = true;
// XXX During setting selection, a selection listener may change selection
// again. In such case, sHandlingSelectionEvent doesn't indicate if
// the selection change is caused by a selection event. However, it
// must be non-realistic scenario.
handler.OnSelectionEvent(aSelectionEvent);
}
void
TextComposition::NotityUpdateComposition(
const WidgetCompositionEvent* aCompositionEvent)

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

@ -41,6 +41,8 @@ class TextComposition final
public:
typedef dom::TabParent TabParent;
static bool IsHandlingSelectionEvent() { return sHandlingSelectionEvent; }
TextComposition(nsPresContext* aPresContext,
nsINode* aNode,
TabParent* aTabParent,
@ -171,6 +173,10 @@ private:
// WARNING: mPresContext may be destroying, so, be careful if you touch it.
}
// sHandlingSelectionEvent is true while TextComposition sends a selection
// event to ContentEventHandler.
static bool sHandlingSelectionEvent;
// This class holds nsPresContext weak. This instance shouldn't block
// destroying it. When the presContext is being destroyed, it's notified to
// IMEStateManager::OnDestroyPresContext(), and then, it destroy
@ -284,6 +290,18 @@ private:
EventDispatchingCallback* aCallBack,
bool aIsSynthesized);
/**
* HandleSelectionEvent() sends the selection event to ContentEventHandler
* or dispatches it to the focused child process.
*/
void HandleSelectionEvent(WidgetSelectionEvent* aSelectionEvent)
{
HandleSelectionEvent(mPresContext, mTabParent, aSelectionEvent);
}
static void HandleSelectionEvent(nsPresContext* aPresContext,
TabParent* aTabParent,
WidgetSelectionEvent* aSelectionEvent);
/**
* MaybeDispatchCompositionUpdate() may dispatch a compositionupdate event
* if aCompositionEvent changes composition string.

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

@ -1831,7 +1831,7 @@ void HTMLMediaElement::SetMutedInternal(uint32_t aMuted)
void HTMLMediaElement::SetVolumeInternal()
{
float effectiveVolume = mMuted ? 0.0f : float(mVolume * mAudioChannelVolume);
float effectiveVolume = ComputedVolume();
if (mDecoder) {
mDecoder->SetVolume(effectiveVolume);
@ -3569,6 +3569,12 @@ HTMLMediaElement::UpdateReadyStateInternal()
// We are playing a stream that has video and a video frame is now set.
// This means we have all metadata needed to change ready state.
MediaInfo mediaInfo = mMediaInfo;
if (hasAudio) {
mediaInfo.EnableAudio();
}
if (hasVideo) {
mediaInfo.EnableVideo();
}
MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
}
@ -4040,7 +4046,7 @@ HTMLMediaElement::NotifyOwnerDocumentActivityChangedInternal()
mDecoder->NotifyOwnerActivityChanged();
}
bool pauseElement = !IsActive() || (mMuted & MUTED_BY_AUDIO_CHANNEL);
bool pauseElement = !IsActive() || ComputedMuted();
SuspendOrResumeElement(pauseElement, !IsActive());
@ -4470,19 +4476,21 @@ nsresult HTMLMediaElement::UpdateChannelMuteState(float aVolume, bool aMuted)
}
// We have to mute this channel.
if (aMuted && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
if (aMuted && !ComputedMuted()) {
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
}
} else if (!aMuted && (mMuted & MUTED_BY_AUDIO_CHANNEL)) {
} else if (!aMuted && ComputedMuted()) {
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
if (UseAudioChannelAPI()) {
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
}
}
SuspendOrResumeElement(mMuted & MUTED_BY_AUDIO_CHANNEL, false);
#ifdef MOZ_B2G
SuspendOrResumeElement(ComputedMuted(), false);
#endif
return NS_OK;
}
@ -4546,7 +4554,11 @@ NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted)
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
UpdateChannelMuteState(aVolume, aMuted);
#ifdef MOZ_B2G
mPaused.SetCanPlay(!aMuted);
#endif
return NS_OK;
}
@ -4768,5 +4780,17 @@ HTMLMediaElement::NextFrameStatus()
return NEXT_FRAME_UNINITIALIZED;
}
float
HTMLMediaElement::ComputedVolume() const
{
return mMuted ? 0.0f : float(mVolume * mAudioChannelVolume);
}
bool
HTMLMediaElement::ComputedMuted() const
{
return (mMuted & MUTED_BY_AUDIO_CHANNEL);
}
} // namespace dom
} // namespace mozilla

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

@ -22,7 +22,7 @@
#ifdef MOZ_EME
#include "mozilla/dom/MediaKeys.h"
#endif
#include "StateWatching.h"
#include "mozilla/StateWatching.h"
#include "nsGkAtoms.h"
// X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
@ -646,6 +646,13 @@ public:
// that will soon be gone.
bool IsBeingDestroyed();
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
// This is for testing only
float ComputedVolume() const;
bool ComputedMuted() const;
protected:
virtual ~HTMLMediaElement();

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

@ -478,29 +478,9 @@ nsBrowserElement::SetInputMethodActive(bool aIsActive,
{
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
nsCOMPtr<nsIDOMElement> ownerElement;
nsresult rv = frameLoader->GetOwnerElement(getter_AddRefs(ownerElement));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
nsCOMPtr<nsINode> node = do_QueryInterface(ownerElement);
nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
if (!nsContentUtils::IsExactSitePermAllow(principal, "input-manage")) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
nsCOMPtr<nsIDOMDOMRequest> req;
rv = mBrowserElementAPI->SetInputMethodActive(aIsActive,
getter_AddRefs(req));
nsresult rv = mBrowserElementAPI->SetInputMethodActive(aIsActive,
getter_AddRefs(req));
if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv == NS_ERROR_INVALID_ARG) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
@ -652,30 +632,44 @@ nsBrowserElement::SetNFCFocus(bool aIsFocus,
{
NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
nsCOMPtr<nsIDOMElement> ownerElement;
nsresult rv = frameLoader->GetOwnerElement(getter_AddRefs(ownerElement));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return;
}
nsCOMPtr<nsINode> node = do_QueryInterface(ownerElement);
nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
if (!nsContentUtils::IsExactSitePermAllow(principal, "nfc-manager")) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
rv = mBrowserElementAPI->SetNFCFocus(aIsFocus);
nsresult rv = mBrowserElementAPI->SetNFCFocus(aIsFocus);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
}
}
already_AddRefed<DOMRequest>
nsBrowserElement::ExecuteScript(const nsAString& aScript,
const BrowserElementExecuteScriptOptions& aOptions,
ErrorResult& aRv)
{
NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
nsCOMPtr<nsIDOMDOMRequest> req;
nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI);
MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component.");
AutoJSAPI jsapi;
jsapi.Init(wrappedObj->GetJSObject());
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> options(cx);
if (!ToJSValue(cx, aOptions, &options)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
nsresult rv = mBrowserElementAPI->ExecuteScript(aScript, options, getter_AddRefs(req));
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_INVALID_ARG) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
} else {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
}
return nullptr;
}
return req.forget().downcast<DOMRequest>();
}
} // namespace mozilla

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

@ -19,6 +19,7 @@ namespace mozilla {
namespace dom {
struct BrowserElementDownloadOptions;
struct BrowserElementExecuteScriptOptions;
class BrowserElementNextPaintEventCallback;
class DOMRequest;
enum class BrowserFindCaseSensitivity: uint32_t;
@ -100,6 +101,10 @@ public:
already_AddRefed<dom::DOMRequest> SetInputMethodActive(bool isActive,
ErrorResult& aRv);
already_AddRefed<dom::DOMRequest> ExecuteScript(const nsAString& aScript,
const dom::BrowserElementExecuteScriptOptions& aOptions,
ErrorResult& aRv);
void SetNFCFocus(bool isFocus,
ErrorResult& aRv);

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

@ -103,7 +103,6 @@
#include "nsIRequest.h"
#include "nsHtml5TreeOpExecutor.h"
#include "nsHtml5Parser.h"
#include "nsIDOMJSWindow.h"
#include "nsSandboxFlags.h"
#include "nsIImageDocument.h"
#include "mozilla/dom/HTMLBodyElement.h"
@ -1376,12 +1375,17 @@ nsHTMLDocument::Open(JSContext* /* unused */,
NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
"XOW should have caught this!");
nsCOMPtr<nsIDOMWindow> window = GetInnerWindow();
nsCOMPtr<nsPIDOMWindow> window = GetInnerWindow();
if (!window) {
rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
nsCOMPtr<nsIDOMJSWindow> win = do_QueryInterface(window);
window = nsPIDOMWindow::GetOuterFromCurrentInner(window);
if (!window) {
rv.Throw(NS_ERROR_NOT_INITIALIZED);
return nullptr;
}
nsRefPtr<nsGlobalWindow> win = static_cast<nsGlobalWindow*>(window.get());
nsCOMPtr<nsIDOMWindow> newWindow;
// XXXbz We ignore aReplace for now.
rv = win->OpenJS(aURL, aName, aFeatures, getter_AddRefs(newWindow));
@ -2319,21 +2323,16 @@ nsHTMLDocument::NameIsEnumerable(const nsAString& aName)
return true;
}
static PLDHashOperator
IdentifierMapEntryAddNames(nsIdentifierMapEntry* aEntry, void* aArg)
{
nsTArray<nsString>* aNames = static_cast<nsTArray<nsString>*>(aArg);
if (aEntry->HasNameElement() ||
aEntry->HasIdElementExposedAsHTMLDocumentProperty()) {
aNames->AppendElement(aEntry->GetKey());
}
return PL_DHASH_NEXT;
}
void
nsHTMLDocument::GetSupportedNames(unsigned, nsTArray<nsString>& aNames)
{
mIdentifierMap.EnumerateEntries(IdentifierMapEntryAddNames, &aNames);
for (auto iter = mIdentifierMap.Iter(); !iter.Done(); iter.Next()) {
nsIdentifierMapEntry* entry = iter.Get();
if (entry->HasNameElement() ||
entry->HasIdElementExposedAsHTMLDocumentProperty()) {
aNames.AppendElement(entry->GetKey());
}
}
}
//----------------------------

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

@ -0,0 +1,106 @@
<!DOCTYPE HTML>
<html>
<body>
<div id="content" style="display: none">
<audio id="audio1" />
<audio id="audio2" mozaudiochannel="foo" />
<audio id="audio3" mozaudiochannel="content" />
</div>
<script type="application/javascript">
function is(a, b, msg) {
parent.postMessage({ status: a === b, msg: msg }, '*');
}
function ok(a, msg) {
parent.postMessage({ status: !!a, msg: msg }, '*');
}
function finish() {
parent.postMessage({ finish: true }, '*');
}
function test_basic() {
var audio1 = document.getElementById("audio1");
ok(audio1, "Audio Element exists");
is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
try {
audio1.mozAudioChannelType = "foo";
} catch(e) {}
is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
audio1.mozAudioChannelType = "alarm";
is(audio1.mozAudioChannelType, "alarm", "Default audio1 channel == 'alarm'");
var audio2 = document.getElementById("audio2");
ok(audio2, "Audio Element exists");
is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
try {
audio2.mozAudioChannelType = "foo";
} catch(e) {}
is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
audio2.mozAudioChannelType = "alarm";
is(audio2.mozAudioChannelType, "alarm", "Default audio2 channel == 'alarm'");
var audio3 = document.getElementById("audio3");
ok(audio3, "Audio Element exists");
is(audio3.mozAudioChannelType, "content", "Default audio3 channel == 'content'");
try {
audio3.mozAudioChannelType = "foo";
} catch(e) {}
is(audio3.mozAudioChannelType, "content", "audio3 channel == 'content'");
audio3.mozAudioChannelType = "alarm";
is(audio3.mozAudioChannelType, "alarm", "audio3 channel == 'alarm'");
runTest();
}
function test_preferences(aChannel) {
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", aChannel ]]},
function() {
var audio = document.createElement('audio');
ok(audio, "Audio Element created");
is(audio.mozAudioChannelType, aChannel, "Default audio channel == '" + aChannel + "'");
runTest();
}
);
}
function test_wrong_preferences() {
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", 'foobar' ]]},
function() {
var audio = document.createElement('audio');
ok(audio, "Audio Element created");
is(audio.mozAudioChannelType, 'normal', "Default audio channel == 'normal'");
runTest();
}
);
}
var tests = [
test_basic,
function() { test_preferences("content"); },
function() { test_preferences("notification"); },
function() { test_preferences("alarm"); },
function() { test_preferences("telephony"); },
function() { test_preferences("ringer"); },
function() { test_preferences("publicnotification"); },
test_wrong_preferences,
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
runTest();
</script>
</body>
</html>

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

@ -193,6 +193,7 @@ support-files =
wakelock.ogv
file_ignoreuserfocus.html
simpleFileOpener.js
file_mozaudiochannel.html
[test_a_text.html]
[test_anchor_href_cache_invalidation.html]

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

@ -7,96 +7,24 @@
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<audio id="audio1" />
<audio id="audio2" mozaudiochannel="foo" />
<audio id="audio3" mozaudiochannel="content" />
</div>
<pre id="test">
<script type="application/javascript">
function test_basic() {
var audio1 = document.getElementById("audio1");
ok(audio1, "Audio Element exists");
is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
try {
audio1.mozAudioChannelType = "foo";
} catch(e) {}
is(audio1.mozAudioChannelType, "normal", "Default audio1 channel == 'normal'");
audio1.mozAudioChannelType = "alarm";
is(audio1.mozAudioChannelType, "alarm", "Default audio1 channel == 'alarm'");
var audio2 = document.getElementById("audio2");
ok(audio2, "Audio Element exists");
is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
try {
audio2.mozAudioChannelType = "foo";
} catch(e) {}
is(audio2.mozAudioChannelType, "normal", "Default audio2 channel == 'normal'");
audio2.mozAudioChannelType = "alarm";
is(audio2.mozAudioChannelType, "alarm", "Default audio2 channel == 'alarm'");
var audio3 = document.getElementById("audio3");
ok(audio3, "Audio Element exists");
is(audio3.mozAudioChannelType, "content", "Default audio3 channel == 'content'");
try {
audio3.mozAudioChannelType = "foo";
} catch(e) {}
is(audio3.mozAudioChannelType, "content", "audio3 channel == 'content'");
audio3.mozAudioChannelType = "alarm";
is(audio3.mozAudioChannelType, "alarm", "audio3 channel == 'alarm'");
runTest();
}
function test_preferences(aChannel) {
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", aChannel ]]},
function() {
var audio = document.createElement('audio');
ok(audio, "Audio Element created");
is(audio.mozAudioChannelType, aChannel, "Default audio channel == '" + aChannel + "'");
runTest();
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelAPI", true]]}, function() {
var ifr = document.createElement('iframe');
ifr.src = 'file_mozaudiochannel.html';
onmessage = function(e) {
if ("finish" in e.data) {
SimpleTest.finish();
} else {
ok(e.data.status, e.data.msg);
}
);
}
function test_wrong_preferences() {
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", 'foobar' ]]},
function() {
var audio = document.createElement('audio');
ok(audio, "Audio Element created");
is(audio.mozAudioChannelType, 'normal', "Default audio channel == 'normal'");
runTest();
}
);
}
var tests = [
test_basic,
function() { test_preferences("content"); },
function() { test_preferences("notification"); },
function() { test_preferences("alarm"); },
function() { test_preferences("telephony"); },
function() { test_preferences("ringer"); },
function() { test_preferences("publicnotification"); },
test_wrong_preferences,
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
runTest();
document.body.appendChild(ifr);
});
</script>
</pre>
</body>

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

@ -6025,6 +6025,7 @@ private:
Atomic<bool> mInvalidatedOnAnyThread;
const Mode mMode;
bool mHasBeenActive;
bool mHasBeenActiveOnConnectionThread;
bool mActorDestroyed;
bool mInvalidated;
@ -6077,6 +6078,13 @@ public:
mHasBeenActive = true;
}
void
SetActiveOnConnectionThread()
{
AssertIsOnConnectionThread();
mHasBeenActiveOnConnectionThread = true;
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(
mozilla::dom::indexedDB::TransactionBase)
@ -12913,6 +12921,8 @@ StartTransactionOp::DoDatabaseWork(DatabaseConnection* aConnection)
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
Transaction()->SetActiveOnConnectionThread();
if (Transaction()->GetMode() != IDBTransaction::READ_ONLY) {
nsresult rv = aConnection->BeginWriteTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -12967,6 +12977,7 @@ TransactionBase::TransactionBase(Database* aDatabase, Mode aMode)
, mInvalidatedOnAnyThread(false)
, mMode(aMode)
, mHasBeenActive(false)
, mHasBeenActiveOnConnectionThread(false)
, mActorDestroyed(false)
, mInvalidated(false)
, mResultCode(NS_OK)
@ -20069,6 +20080,8 @@ VersionChangeOp::DoDatabaseWork(DatabaseConnection* aConnection)
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mLoggingSerialNumber);
Transaction()->SetActiveOnConnectionThread();
nsresult rv = aConnection->BeginWriteTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -21180,7 +21193,8 @@ CommitOp::Run()
mTransaction->LoggingSerialNumber(),
mLoggingSerialNumber);
if (mTransaction->GetMode() != IDBTransaction::READ_ONLY) {
if (mTransaction->GetMode() != IDBTransaction::READ_ONLY &&
mTransaction->mHasBeenActiveOnConnectionThread) {
Database* database = mTransaction->GetDatabase();
MOZ_ASSERT(database);

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

@ -18,7 +18,6 @@ XPIDL_SOURCES += [
'nsIDOMCrypto.idl',
'nsIDOMGlobalPropertyInitializer.idl',
'nsIDOMHistory.idl',
'nsIDOMJSWindow.idl',
'nsIDOMLocation.idl',
'nsIDOMModalContentWindow.idl',
'nsIDOMNavigator.idl',

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

@ -1,70 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "domstubs.idl"
[scriptable, uuid(e0f739e3-47e2-4007-af30-181939e97a51)]
interface nsIDOMJSWindow : nsISupports
{
void dump(in DOMString str);
/**
* These methods take one optional argument that's the timer ID to
* clear. Often in existing code these methods are passed undefined,
* which is a nop so we need to support that as well.
*/
void clearTimeout([optional] in long handle);
void clearInterval([optional] in long handle);
/**
* This method is here for backwards compatibility with 4.x only,
* its implementation is a no-op
*/
void setResizable(in boolean resizable);
/**
* @deprecated These are old Netscape 4 methods. Do not use,
* the implementation is no-op.
*/
void captureEvents();
void releaseEvents();
/**
* This is the scriptable version of nsIDOMWindow::open()
* that takes 3 optional arguments. Its binary name is OpenJS to
* avoid colliding with nsIDOMWindow::open(), which has the
* same signature. The reason we can't have that collision is that
* the implementation needs to know whether it was called from JS or
* not.
*
* IOW, DO NOT CALL THIS FROM C++
*/
[binaryname(OpenJS)] nsIDOMWindow open([optional] in DOMString url,
[optional] in DOMString name,
[optional] in DOMString options);
/**
* This is the scriptable version of
* nsIDOMWindow::openDialog() that takes 3 optional
* arguments, plus any additional arguments are passed on as
* arguments on the dialog's window object (window.arguments).
*/
nsIDOMWindow openDialog([optional] in DOMString url,
[optional] in DOMString name,
[optional] in DOMString options);
/**
* window.frames in Netscape 4.x and IE is just a reference to the
* window itself (i.e. window.frames === window), but this doesn't
* make sense from a generic API point of view so that's why this is
* JS specific.
*
* This property is "replaceable" in JavaScript.
*/
readonly attribute nsIDOMWindow frames;
[implicit_jscontext, binaryname(ScriptableContent)]
readonly attribute jsval content;
};

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

@ -53,6 +53,7 @@
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/widget/WidgetMessageUtils.h"
#include "mozilla/media/MediaChild.h"
#include "mozilla/BasePrincipal.h"
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_WIN)
@ -2112,19 +2113,16 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission)
MOZ_ASSERT(permissionManager,
"We have no permissionManager in the Content process !");
nsAutoCString originNoSuffix;
OriginAttributes attrs;
attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + nsCString(permission.host));
NS_ENSURE_TRUE(uri, true);
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
MOZ_ASSERT(secMan);
nsCOMPtr<nsIPrincipal> principal;
nsresult rv = secMan->GetAppCodebasePrincipal(uri, permission.appId,
permission.isInBrowserElement,
getter_AddRefs(principal));
nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
NS_ENSURE_SUCCESS(rv, true);
nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
// child processes don't care about modification time.
int64_t modificationTime = 0;

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

@ -2559,12 +2559,12 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
enumerator->GetNext(getter_AddRefs(supp));
nsCOMPtr<nsIPermission> perm = do_QueryInterface(supp);
nsCString host;
perm->GetHost(host);
uint32_t appId;
perm->GetAppId(&appId);
bool isInBrowserElement;
perm->GetIsInBrowserElement(&isInBrowserElement);
nsCOMPtr<nsIPrincipal> principal;
perm->GetPrincipal(getter_AddRefs(principal));
nsCString origin;
if (principal) {
principal->GetOrigin(origin);
}
nsCString type;
perm->GetType(type);
uint32_t capability;
@ -2574,8 +2574,7 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
int64_t expireTime;
perm->GetExpireTime(&expireTime);
aPermissions->AppendElement(IPC::Permission(host, appId,
isInBrowserElement, type,
aPermissions->AppendElement(IPC::Permission(origin, type,
capability, expireType,
expireTime));
}

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

@ -182,12 +182,12 @@ parent:
* Notifies chrome that there is a focus change involving an editable
* object (input, textarea, document, contentEditable. etc.)
*
* focus PR_TRUE if editable object is receiving focus
* PR_FALSE if losing focus
* contentCache Cache of content
* notification Whole data of the notification
* preference Native widget preference for IME updates
*/
prio(urgent) sync NotifyIMEFocus(bool focus, ContentCache contentCache)
prio(urgent) sync NotifyIMEFocus(ContentCache contentCache,
IMENotification notification)
returns (nsIMEUpdatePreference preference);
/**
@ -196,35 +196,28 @@ parent:
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
*
* contentCache Cache of content
* offset Starting offset of the change
* removedEnd Ending offset of the range deleted
* addedEnd New ending offset after insertion
* causedByComposition true if the change is caused by composition
*
* for insertion, offset == end
* for deletion, offset == newEnd
* notification Whole data of the notification
*/
prio(urgent) async NotifyIMETextChange(ContentCache contentCache,
uint32_t offset, uint32_t removedEnd,
uint32_t addedEnd,
bool causedByComposition);
IMENotification notification);
/**
* Notifies chrome that there is a IME compostion rect updated
*
* contentCache Cache of content
*/
prio(urgent) async NotifyIMESelectedCompositionRect(ContentCache contentCache);
prio(urgent) async NotifyIMECompositionUpdate(ContentCache contentCache,
IMENotification notification);
/**
* Notifies chrome that there has been a change in selection
* Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
*
* contentCache Cache of content
* causedByComposition true if the change is caused by composition
* notification Whole data of the notification
*/
prio(urgent) async NotifyIMESelection(ContentCache contentCache,
bool causedByComposition);
IMENotification notification);
/**
* Notifies chrome of updating its content cache.
@ -247,7 +240,8 @@ parent:
*
* contentCache Cache of content
*/
prio(urgent) async NotifyIMEPositionChange(ContentCache contentCache);
prio(urgent) async NotifyIMEPositionChange(ContentCache contentCache,
IMENotification notification);
/**
* Instructs chrome to end any pending composition

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

@ -1952,8 +1952,8 @@ TabParent::RecvHideTooltip()
}
bool
TabParent::RecvNotifyIMEFocus(const bool& aFocus,
const ContentCache& aContentCache,
TabParent::RecvNotifyIMEFocus(const ContentCache& aContentCache,
const IMENotification& aIMENotification,
nsIMEUpdatePreference* aPreference)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
@ -1962,12 +1962,10 @@ TabParent::RecvNotifyIMEFocus(const bool& aFocus,
return true;
}
IMENotification notification(aFocus ? NOTIFY_IME_OF_FOCUS :
NOTIFY_IME_OF_BLUR);
mContentCache.AssignContent(aContentCache, &notification);
IMEStateManager::NotifyIME(notification, widget, true);
mContentCache.AssignContent(aContentCache, &aIMENotification);
IMEStateManager::NotifyIME(aIMENotification, widget, true);
if (aFocus) {
if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
*aPreference = widget->GetIMEUpdatePreference();
}
return true;
@ -1975,10 +1973,7 @@ TabParent::RecvNotifyIMEFocus(const bool& aFocus,
bool
TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
const uint32_t& aStart,
const uint32_t& aRemovedEnd,
const uint32_t& aAddedEnd,
const bool& aCausedByComposition)
const IMENotification& aIMENotification)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
@ -1988,56 +1983,47 @@ TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
nsIMEUpdatePreference updatePreference = widget->GetIMEUpdatePreference();
NS_ASSERTION(updatePreference.WantTextChange(),
"Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE");
MOZ_ASSERT(!aCausedByComposition ||
MOZ_ASSERT(!aIMENotification.mTextChangeData.mCausedByComposition ||
updatePreference.WantChangesCausedByComposition(),
"The widget doesn't want text change notification caused by composition");
#endif
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
notification.mTextChangeData.mStartOffset = aStart;
notification.mTextChangeData.mRemovedEndOffset = aRemovedEnd;
notification.mTextChangeData.mAddedEndOffset = aAddedEnd;
notification.mTextChangeData.mCausedByComposition = aCausedByComposition;
mContentCache.AssignContent(aContentCache, &notification);
mContentCache.MaybeNotifyIME(widget, notification);
mContentCache.AssignContent(aContentCache, &aIMENotification);
mContentCache.MaybeNotifyIME(widget, aIMENotification);
return true;
}
bool
TabParent::RecvNotifyIMESelectedCompositionRect(
const ContentCache& aContentCache)
TabParent::RecvNotifyIMECompositionUpdate(
const ContentCache& aContentCache,
const IMENotification& aIMENotification)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
IMENotification notification(NOTIFY_IME_OF_COMPOSITION_UPDATE);
mContentCache.AssignContent(aContentCache, &notification);
mContentCache.MaybeNotifyIME(widget, notification);
mContentCache.AssignContent(aContentCache, &aIMENotification);
mContentCache.MaybeNotifyIME(widget, aIMENotification);
return true;
}
bool
TabParent::RecvNotifyIMESelection(const ContentCache& aContentCache,
const bool& aCausedByComposition)
const IMENotification& aIMENotification)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return true;
IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
mContentCache.AssignContent(aContentCache, &notification);
mContentCache.AssignContent(aContentCache, &aIMENotification);
const nsIMEUpdatePreference updatePreference =
widget->GetIMEUpdatePreference();
if (updatePreference.WantSelectionChange() &&
(updatePreference.WantChangesCausedByComposition() ||
!aCausedByComposition)) {
notification.mSelectionChangeData.mCausedByComposition =
aCausedByComposition;
mContentCache.MaybeNotifyIME(widget, notification);
!aIMENotification.mSelectionChangeData.mCausedByComposition)) {
mContentCache.MaybeNotifyIME(widget, aIMENotification);
}
return true;
}
@ -2071,20 +2057,20 @@ TabParent::RecvNotifyIMEMouseButtonEvent(
}
bool
TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache)
TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
const IMENotification& aIMENotification)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
IMENotification notification(NOTIFY_IME_OF_POSITION_CHANGE);
mContentCache.AssignContent(aContentCache, &notification);
mContentCache.AssignContent(aContentCache, &aIMENotification);
const nsIMEUpdatePreference updatePreference =
widget->GetIMEUpdatePreference();
if (updatePreference.WantPositionChanged()) {
IMEStateManager::NotifyIME(notification, widget, true);
IMEStateManager::NotifyIME(aIMENotification, widget, true);
}
return true;
}
@ -2298,7 +2284,11 @@ TabParent::SendSelectionEvent(WidgetSelectionEvent& event)
return true;
}
mContentCache.OnSelectionEvent(event);
return PBrowserParent::SendSelectionEvent(event);
if (NS_WARN_IF(!PBrowserParent::SendSelectionEvent(event))) {
return false;
}
event.mSucceeded = true;
return true;
}
/*static*/ TabParent*

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

@ -162,22 +162,21 @@ public:
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) override;
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
const ContentCache& aContentCache,
virtual bool RecvNotifyIMEFocus(const ContentCache& aContentCache,
const widget::IMENotification& aEventMessage,
nsIMEUpdatePreference* aPreference)
override;
virtual bool RecvNotifyIMETextChange(const ContentCache& aContentCache,
const uint32_t& aStart,
const uint32_t& aRemovedEnd,
const uint32_t& aAddedEnd,
const bool& aCausedByComposition) override;
virtual bool RecvNotifyIMESelectedCompositionRect(const ContentCache& aContentCache) override;
const widget::IMENotification& aEventMessage) override;
virtual bool RecvNotifyIMECompositionUpdate(const ContentCache& aContentCache,
const widget::IMENotification& aEventMessage) override;
virtual bool RecvNotifyIMESelection(const ContentCache& aContentCache,
const bool& aCausedByComposition) override;
const widget::IMENotification& aEventMessage) override;
virtual bool RecvUpdateContentCache(const ContentCache& aContentCache) override;
virtual bool RecvNotifyIMEMouseButtonEvent(const widget::IMENotification& aEventMessage,
bool* aConsumedByIME) override;
virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache) override;
virtual bool RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
const widget::IMENotification& aEventMessage) override;
virtual bool RecvOnEventNeedingAckReceived(const uint32_t& aMessage) override;
virtual bool RecvEndIMEComposition(const bool& aCancel,
bool* aNoCompositionEvent,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше