Merge m-c to fx-team, a=merge

This commit is contained in:
Wes Kocher 2015-10-30 17:00:16 -07:00
commit db3aaf2c33
241 changed files with 8134 additions and 2422 deletions

View File

@ -324,8 +324,14 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
Accessible*
IDRefsIterator::Next()
{
nsIContent* nextElm = NextElem();
return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
nsIContent* nextEl = nullptr;
while ((nextEl = NextElem())) {
Accessible* acc = mDoc->GetAccessible(nextEl);
if (acc) {
return acc;
}
}
return nullptr;
}

View File

@ -295,12 +295,16 @@ EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
if (eventType == nsIAccessibleEvent::EVENT_SHOW)
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
tailReorder->DoNotEmitAll();
else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
}
else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
NS_ERROR("Accessible tree was modified after it was removed! Huh?");
else
}
else {
aTailEvent->mEventRule = AccEvent::eDoNotEmit;
mEvents[index].swap(mEvents[count - 1]);
}
return;
}

View File

@ -54,6 +54,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
@ -86,6 +87,7 @@ NotificationController::Shutdown()
mContentInsertions.Clear();
mNotifications.Clear();
mEvents.Clear();
mRelocations.Clear();
}
void
@ -351,6 +353,16 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// modification are done.
mDocument->ProcessInvalidationList();
// We cannot rely on DOM tree to keep aria-owns relations updated. Make
// a validation to remove dead links.
mDocument->ValidateARIAOwned();
// Process relocation list.
for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
}
mRelocations.Clear();
// If a generic notification occurs after this point then we may be allowed to
// process it synchronously. However we do not want to reenter if fireing
// events causes script to run.

View File

@ -133,6 +133,16 @@ public:
nsIContent* aStartChildNode,
nsIContent* aEndChildNode);
/**
* Pend an accessible subtree relocation.
*/
void ScheduleRelocation(Accessible* aOwner)
{
if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
ScheduleProcessing();
}
}
/**
* Start to observe refresh to make notifications and events processing after
* layout.
@ -303,6 +313,11 @@ private:
* use SwapElements() on it.
*/
nsTArray<RefPtr<Notification> > mNotifications;
/**
* Holds all scheduled relocations.
*/
nsTArray<RefPtr<Accessible> > mRelocations;
};
} // namespace a11y

View File

@ -116,7 +116,7 @@ TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
// Ignore the accessible and its subtree if it was repositioned by means of
// aria-owns.
if (accessible) {
if (accessible->IsRepositioned()) {
if (accessible->IsRelocated()) {
*aSkipSubtree = true;
} else {
*aAccesible = accessible;

View File

@ -910,13 +910,13 @@ public:
* Get/set repositioned bit indicating that the accessible was moved in
* the accessible tree, i.e. the accessible tree structure differs from DOM.
*/
bool IsRepositioned() const { return mStateFlags & eRepositioned; }
void SetRepositioned(bool aRepositioned)
bool IsRelocated() const { return mStateFlags & eRelocated; }
void SetRelocated(bool aRelocated)
{
if (aRepositioned)
mStateFlags |= eRepositioned;
if (aRelocated)
mStateFlags |= eRelocated;
else
mStateFlags &= ~eRepositioned;
mStateFlags &= ~eRelocated;
}
/**
@ -1009,9 +1009,9 @@ protected:
eSubtreeMutating = 1 << 6, // subtree is being mutated
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
eRepositioned = 1 << 9, // accessible was moved in tree
eRelocated = 1 << 9, // accessible was moved in tree
eLastStateFlag = eRepositioned
eLastStateFlag = eRelocated
};
/**

View File

@ -130,9 +130,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DocAccessible, Accessible)
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
for (uint32_t i = 0; i < tmp->mARIAOwnsInvalidationList.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mARIAOwnsInvalidationList[i].mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mARIAOwnsInvalidationList[i].mChild)
for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
nsTArray<RefPtr<Accessible> >* ar = it.UserData();
for (uint32_t i = 0; i < ar->Length(); i++) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
"mARIAOwnsHash entry item");
cb.NoteXPCOMChild(ar->ElementAt(i));
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -144,10 +148,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
tmp->mNodeToAccessibleMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
for (uint32_t i = 0; i < tmp->mARIAOwnsInvalidationList.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mARIAOwnsInvalidationList[i].mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mARIAOwnsInvalidationList[i].mChild)
}
tmp->mARIAOwnsHash.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
@ -731,6 +732,10 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
if (aModType != nsIDOMMutationEvent::ADDITION)
RemoveDependentIDsFor(accessible, aAttribute);
if (aAttribute == nsGkAtoms::id) {
RelocateARIAOwnedIfNeeded(aElement);
}
// Store the ARIA attribute old value so that it can be used after
// attribute change. Note, we assume there's no nested ARIA attribute
// changes. If this happens then we should end up with keeping a stack of
@ -906,6 +911,10 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
return;
}
if (aAttribute == nsGkAtoms::id) {
RelocateARIAOwnedIfNeeded(elm);
}
// ARIA or XUL selection
if ((aAccessible->GetContent()->IsXULElement() &&
aAttribute == nsGkAtoms::selected) ||
@ -1040,6 +1049,10 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
return;
}
if (aAttribute == nsGkAtoms::aria_owns) {
mNotificationController->ScheduleRelocation(aAccessible);
}
}
void
@ -1271,6 +1284,15 @@ DocAccessible::BindToDocument(Accessible* aAccessible,
aAccessible->SetRoleMapEntry(aRoleMapEntry);
AddDependentIDsFor(aAccessible);
if (aAccessible->HasOwnContent()) {
nsIContent* el = aAccessible->GetContent();
if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
mNotificationController->ScheduleRelocation(aAccessible);
}
RelocateARIAOwnedIfNeeded(el);
}
}
void
@ -1365,67 +1387,6 @@ DocAccessible::ProcessInvalidationList()
}
mInvalidationList.Clear();
// Alter the tree according to aria-owns (seize the trees).
for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length(); idx++) {
Accessible* owner = mARIAOwnsInvalidationList[idx].mOwner;
if (!owner->IsInDocument()) { // eventually died before we've got here
continue;
}
Accessible* child = GetAccessible(mARIAOwnsInvalidationList[idx].mChild);
if (!child || !child->IsInDocument()) {
continue;
}
Accessible* oldParent = child->Parent();
if (!oldParent) {
NS_ERROR("The accessible is in document but doesn't have a parent");
continue;
}
int32_t idxInParent = child->IndexInParent();
// XXX: update context flags
{
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
RefPtr<AccMutationEvent> hideEvent =
new AccHideEvent(child, child->GetContent(), false);
FireDelayedEvent(hideEvent);
reorderEvent->AddSubMutationEvent(hideEvent);
AutoTreeMutation mut(oldParent);
oldParent->RemoveChild(child);
MaybeNotifyOfValueChange(oldParent);
FireDelayedEvent(reorderEvent);
}
bool isReinserted = false;
{
AutoTreeMutation mut(owner);
isReinserted = owner->AppendChild(child);
}
Accessible* newParent = owner;
if (!isReinserted) {
AutoTreeMutation mut(oldParent);
oldParent->InsertChildAt(idxInParent, child);
newParent = oldParent;
}
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(newParent);
RefPtr<AccMutationEvent> showEvent =
new AccShowEvent(child, child->GetContent());
FireDelayedEvent(showEvent);
reorderEvent->AddSubMutationEvent(showEvent);
MaybeNotifyOfValueChange(newParent);
FireDelayedEvent(reorderEvent);
child->SetRepositioned(isReinserted);
}
mARIAOwnsInvalidationList.Clear();
}
Accessible*
@ -1635,31 +1596,6 @@ DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
if (!HasAccessible(dependentContent)) {
mInvalidationList.AppendElement(dependentContent);
}
// Update ARIA owns cache.
if (relAttr == nsGkAtoms::aria_owns) {
// ARIA owns cannot refer to itself or a parent. Ignore
// the element if so.
nsIContent* parentEl = relProviderEl;
while (parentEl && parentEl != dependentContent) {
parentEl = parentEl->GetParent();
}
if (!parentEl) {
// ARIA owns element cannot refer to an element in parents chain
// of other ARIA owns element (including that ARIA owns element)
// if it's inside of a dependent element subtree of that
// ARIA owns element. Applied recursively.
if (!IsInARIAOwnsLoop(relProviderEl, dependentContent)) {
nsTArray<nsIContent*>* list =
mARIAOwnsHash.LookupOrAdd(aRelProvider);
list->AppendElement(dependentContent);
mARIAOwnsInvalidationList.AppendElement(
ARIAOwnsPair(aRelProvider, dependentContent));
}
}
}
}
}
}
@ -1709,59 +1645,6 @@ DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
}
}
// aria-owns has gone, put the children back.
if (relAttr == nsGkAtoms::aria_owns) {
nsTArray<nsIContent*>* children = mARIAOwnsHash.Get(aRelProvider);
if (children) {
nsTArray<Accessible*> containers;
// Remove ARIA owned elements from where they belonged.
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aRelProvider);
{
AutoTreeMutation mut(aRelProvider);
for (uint32_t idx = 0; idx < children->Length(); idx++) {
nsIContent* childEl = children->ElementAt(idx);
Accessible* child = GetAccessible(childEl);
if (child && child->IsRepositioned()) {
{
RefPtr<AccMutationEvent> hideEvent =
new AccHideEvent(child, childEl, false);
FireDelayedEvent(hideEvent);
reorderEvent->AddSubMutationEvent(hideEvent);
aRelProvider->RemoveChild(child);
}
// Collect DOM-order containers to update their trees.
child->SetRepositioned(false);
Accessible* container = GetContainerAccessible(childEl);
if (!containers.Contains(container)) {
containers.AppendElement(container);
}
}
}
}
mARIAOwnsHash.Remove(aRelProvider);
for (uint32_t idx = 0; idx < mARIAOwnsInvalidationList.Length();) {
if (mARIAOwnsInvalidationList[idx].mOwner == aRelProvider) {
mARIAOwnsInvalidationList.RemoveElementAt(idx);
continue;
}
idx++;
}
MaybeNotifyOfValueChange(aRelProvider);
FireDelayedEvent(reorderEvent);
// Reinserted previously ARIA owned elements into the tree
// (restore a DOM-like order).
for (uint32_t idx = 0; idx < containers.Length(); idx++) {
UpdateTreeOnInsertion(containers[idx]);
}
}
}
// If the relation attribute is given then we don't have anything else to
// check.
if (aRelAttr)
@ -1769,45 +1652,6 @@ DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
}
}
bool
DocAccessible::IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl)
{
// ARIA owns element cannot refer to an element in parents chain of other ARIA
// owns element (including that ARIA owns element) if it's inside of
// a dependent element subtree of that ARIA owns element.
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
Accessible* otherOwner = it.Key();
nsIContent* parentEl = otherOwner->GetContent();
while (parentEl && parentEl != aDependentEl) {
parentEl = parentEl->GetParent();
}
// The dependent element of this ARIA owns element contains some other ARIA
// owns element, make sure this ARIA owns element is not in a subtree of
// a dependent element of that other ARIA owns element. If not then
// continue a check recursively.
if (parentEl) {
nsTArray<nsIContent*>* childEls = it.UserData();
for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
nsIContent* childEl = childEls->ElementAt(idx);
nsIContent* parentEl = aOwnerEl;
while (parentEl && parentEl != childEl) {
parentEl = parentEl->GetParent();
}
if (parentEl) {
return true;
}
if (IsInARIAOwnsLoop(aOwnerEl, childEl)) {
return true;
}
}
}
}
return false;
}
bool
DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
nsIAtom* aAttribute)
@ -2023,11 +1867,6 @@ DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNod
}
}
// We may not have an integral DOM tree to remove all aria-owns relations
// from the tree. Validate all relations after timeout to workaround that.
mNotificationController->ScheduleNotification<DocAccessible>
(this, &DocAccessible::ValidateARIAOwned);
// Content insertion/removal is not cause of accessible tree change.
if (updateFlags == eNoAccessible)
return;
@ -2111,22 +1950,243 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
return updateFlags;
}
void
DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
{
if (!aElement->HasID())
return;
AttrRelProviderArray* list =
mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
if (list) {
for (uint32_t idx = 0; idx < list->Length(); idx++) {
if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
if (owner) {
mNotificationController->ScheduleRelocation(owner);
}
}
}
}
}
void
DocAccessible::ValidateARIAOwned()
{
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
nsTArray<nsIContent*>* childEls = it.UserData();
for (uint32_t idx = 0; idx < childEls->Length(); idx++) {
nsIContent* childEl = childEls->ElementAt(idx);
Accessible* child = GetAccessible(childEl);
if (child && child->IsInDocument() && !child->GetFrame()) {
if (!child->Parent()) {
NS_ERROR("An element in the document doesn't have a parent?");
continue;
}
UpdateTreeOnRemoval(child->Parent(), childEl);
Accessible* owner = it.Key();
nsTArray<RefPtr<Accessible> >* children = it.UserData();
// Owner is about to die, put children back if applicable.
if (!owner->IsInDocument()) {
PutChildrenBack(children, 0);
it.Remove();
continue;
}
for (uint32_t idx = 0; idx < children->Length(); idx++) {
Accessible* child = children->ElementAt(idx);
if (!child->IsInDocument()) {
children->RemoveElementAt(idx);
idx--;
continue;
}
NS_ASSERTION(child->Parent(), "No parent for ARIA owned?");
// If DOM node doesn't have a frame anymore then shutdown its accessible.
if (child->Parent() && !child->GetFrame()) {
UpdateTreeOnRemoval(child->Parent(), child->GetContent());
children->RemoveElementAt(idx);
idx--;
continue;
}
NS_ASSERTION(child->Parent() == owner,
"Illigally stolen ARIA owned child!");
}
if (children->Length() == 0) {
it.Remove();
}
}
}
void
DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
{
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
Accessible* child = nullptr;
uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
while ((child = iter.Next())) {
// Same child on same position, no change.
if (child->Parent() == aOwner &&
child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
NS_ASSERTION(child == children->ElementAt(arrayIdx), "Not in sync!");
insertIdx++; arrayIdx++;
continue;
}
NS_ASSERTION(children->SafeElementAt(arrayIdx) != child, "Already in place!");
nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
if (idx < arrayIdx) {
continue; // ignore second entry of same ID
}
// A new child is found, check for loops.
if (child->Parent() != aOwner) {
Accessible* parent = aOwner;
while (parent && parent != child && !parent->IsDoc()) {
parent = parent->Parent();
}
// A referred child cannot be a parent of the owner.
if (parent == child) {
continue;
}
}
if (child->Parent() == aOwner) {
MoveChild(child, insertIdx - 1);
children->InsertElementAt(arrayIdx, child);
arrayIdx++;
} else if (SeizeChild(aOwner, child, insertIdx)) {
children->InsertElementAt(arrayIdx, child);
insertIdx++; arrayIdx++;
}
}
// Put back children that are not seized anymore.
PutChildrenBack(children, arrayIdx);
if (children->Length() == 0) {
mARIAOwnsHash.Remove(aOwner);
}
}
bool
DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
int32_t aIdxInParent)
{
Accessible* oldParent = aChild->Parent();
NS_PRECONDITION(oldParent, "No parent?");
int32_t oldIdxInParent = aChild->IndexInParent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
RefPtr<AccMutationEvent> hideEvent =
new AccHideEvent(aChild, aChild->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent);
{
AutoTreeMutation mut(oldParent);
oldParent->RemoveChild(aChild);
}
bool isReinserted = false;
{
AutoTreeMutation mut(aNewParent);
isReinserted = aNewParent->InsertChildAt(aIdxInParent, aChild);
}
if (!isReinserted) {
AutoTreeMutation mut(oldParent);
oldParent->InsertChildAt(oldIdxInParent, aChild);
return false;
}
// The child may be stolen from other ARIA owns element.
if (aChild->IsRelocated()) {
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(oldParent);
children->RemoveElement(aChild);
}
FireDelayedEvent(hideEvent);
MaybeNotifyOfValueChange(oldParent);
FireDelayedEvent(reorderEvent);
reorderEvent = new AccReorderEvent(aNewParent);
RefPtr<AccMutationEvent> showEvent =
new AccShowEvent(aChild, aChild->GetContent());
reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent);
MaybeNotifyOfValueChange(aNewParent);
FireDelayedEvent(reorderEvent);
aChild->SetRelocated(true);
return true;
}
void
DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
{
NS_PRECONDITION(aChild->Parent(), "No parent?");
Accessible* parent = aChild->Parent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
RefPtr<AccMutationEvent> hideEvent =
new AccHideEvent(aChild, aChild->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent);
AutoTreeMutation mut(parent);
parent->RemoveChild(aChild);
parent->InsertChildAt(aIdxInParent, aChild);
aChild->SetRelocated(true);
FireDelayedEvent(hideEvent);
RefPtr<AccMutationEvent> showEvent =
new AccShowEvent(aChild, aChild->GetContent());
reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent);
MaybeNotifyOfValueChange(parent);
FireDelayedEvent(reorderEvent);
}
void
DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
uint32_t aStartIdx)
{
nsTArray<Accessible*> containers;
for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
Accessible* child = aChildren->ElementAt(idx);
// If the child is in the tree then remove it from the owner.
if (child->IsInDocument()) {
Accessible* owner = child->Parent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
RefPtr<AccMutationEvent> hideEvent =
new AccHideEvent(child, child->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent);
{
AutoTreeMutation mut(owner);
owner->RemoveChild(child);
child->SetRelocated(false);
}
FireDelayedEvent(hideEvent);
MaybeNotifyOfValueChange(owner);
FireDelayedEvent(reorderEvent);
}
Accessible* container = GetContainerAccessible(child->GetContent());
if (container &&
containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
containers.AppendElement(container);
}
}
// And put it back where it belongs to.
aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
for (uint32_t idx = 0; idx < containers.Length(); idx++) {
UpdateTreeOnInsertion(containers[idx]);
}
}

View File

@ -286,13 +286,9 @@ public:
*/
Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
{
nsTArray<nsIContent*>* childrenEl = mARIAOwnsHash.Get(aParent);
if (childrenEl) {
nsIContent* childEl = childrenEl->SafeElementAt(aIndex);
Accessible* child = GetAccessible(childEl);
if (child && child->IsRepositioned()) {
return child;
}
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
if (children) {
return children->SafeElementAt(aIndex);
}
return nullptr;
}
@ -436,12 +432,6 @@ protected:
void RemoveDependentIDsFor(Accessible* aRelProvider,
nsIAtom* aRelAttr = nullptr);
/**
* Return true if given ARIA owner element and its referred content make
* the loop closed.
*/
bool IsInARIAOwnsLoop(nsIContent* aOwnerEl, nsIContent* aDependentEl);
/**
* Update or recreate an accessible depending on a changed attribute.
*
@ -513,11 +503,38 @@ protected:
uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
AccReorderEvent* aReorderEvent);
/**
* Schedule ARIA owned element relocation if needed.
*/
void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
/**
* Validates all aria-owns connections and updates the tree accordingly.
*/
void ValidateARIAOwned();
/**
* Steals or puts back accessible subtrees.
*/
void DoARIAOwnsRelocation(Accessible* aOwner);
/**
* Moves the child from old parent under new one.
*/
bool SeizeChild(Accessible* aNewParent, Accessible* aChild,
int32_t aIdxInParent);
/**
* Move the child under same parent.
*/
void MoveChild(Accessible* aChild, int32_t aIdxInParent);
/**
* Moves children back under their original parents.
*/
void PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
uint32_t aStartIdx);
/**
* Create accessible tree.
*
@ -649,14 +666,12 @@ protected:
AttrRelProvider& operator =(const AttrRelProvider&);
};
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
typedef nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
DependentIDsHashtable;
/**
* The cache of IDs pointed by relation attributes.
*/
DependentIDsHashtable mDependentIDsHash;
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
mDependentIDsHash;
friend class RelatedAccIterator;
@ -669,24 +684,11 @@ protected:
nsTArray<nsIContent*> mInvalidationList;
/**
* Holds a list of aria-owns relations.
* Holds a list of aria-owns relocations.
*/
nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<nsIContent*> >
nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
mARIAOwnsHash;
struct ARIAOwnsPair {
ARIAOwnsPair(Accessible* aOwner, nsIContent* aChild) :
mOwner(aOwner), mChild(aChild) { }
ARIAOwnsPair(const ARIAOwnsPair& aPair) :
mOwner(aPair.mOwner), mChild(aPair.mChild) { }
ARIAOwnsPair& operator =(const ARIAOwnsPair& aPair)
{ mOwner = aPair.mOwner; mChild = aPair.mChild; return *this; }
RefPtr<Accessible> mOwner;
nsCOMPtr<nsIContent> mChild;
};
nsTArray<ARIAOwnsPair> mARIAOwnsInvalidationList;
/**
* Used to process notification from core and accessible events.
*/

View File

@ -51,9 +51,11 @@
{
this.menuNode = getNode(aMenuID);
// Because of aria-owns processing we may have menupopup start fired before
// related show event.
this.eventSeq = [
new invokerChecker(EVENT_SHOW, this.menuNode),
new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
new asyncInvokerChecker(EVENT_MENUPOPUP_START, this.menuNode),
new invokerChecker(EVENT_REORDER, getNode(aParentMenuID))
];

View File

@ -28,7 +28,7 @@
{
var tree =
{ SECTION: [ // t1_1
{ SECTION: [ // t1_2
{ HEADING: [ // t1_2
// no kids, no loop
] }
] };
@ -36,8 +36,8 @@
tree =
{ SECTION: [ // t2_1
{ SECTION: [ // t2_2
{ SECTION: [ // t2_3
{ GROUPING: [ // t2_2
{ HEADING: [ // t2_3
// no kids, no loop
] }
] }
@ -46,9 +46,9 @@
tree =
{ SECTION: [ // t3_3
{ SECTION: [ // t3_1
{ SECTION: [ // t3_2
{ SECTION: [ // DOM child of t3_2
{ GROUPING: [ // t3_1
{ NOTE: [ // t3_2
{ HEADING: [ // DOM child of t3_2
// no kids, no loop
] }
] }
@ -58,7 +58,7 @@
tree =
{ SECTION: [ // t4_1
{ SECTION: [ // DOM child of t4_1
{ GROUPING: [ // DOM child of t4_1, aria-owns ignored
// no kids, no loop
] }
] };
@ -66,11 +66,11 @@
tree =
{ SECTION: [ // t5_1
{ SECTION: [ // DOM child of t5_1
{ SECTION: [ // t5_2
{ SECTION: [ // DOM child of t5_2
{ SECTION: [ // t5_3
{ SECTION: [ // DOM child of t5_3
{ GROUPING: [ // DOM child of t5_1
{ NOTE: [ // t5_2
{ HEADING: [ // DOM child of t5_2
{ FORM: [ // t5_3
{ TOOLTIP: [ // DOM child of t5_3
// no kids, no loop
]}
]}
@ -80,6 +80,14 @@
] };
testAccessibleTree("t5_1", tree);
tree =
{ SECTION: [ // t6_1
{ RADIOBUTTON: [ ] },
{ CHECKBUTTON: [ ] }, // t6_3, rearranged by aria-owns
{ PUSHBUTTON: [ ] }, // t6_2, rearranged by aria-owns
] };
testAccessibleTree("t6_1", tree);
SimpleTest.finish();
}
@ -96,24 +104,37 @@
<pre id="test">
</pre>
<!-- simple loop -->
<div id="t1_1" aria-owns="t1_2"></div>
<div id="t1_2" aria-owns="t1_1"></div>
<div id="t1_2" aria-owns="t1_1" role="heading"></div>
<div id="t2_2" aria-owns="t2_3"></div>
<!-- loop -->
<div id="t2_2" aria-owns="t2_3" role="group"></div>
<div id="t2_1" aria-owns="t2_2"></div>
<div id="t2_3" aria-owns="t2_1"></div>
<div id="t2_3" aria-owns="t2_1" role="heading"></div>
<div id="t3_1" aria-owns="t3_2"></div>
<div id="t3_2">
<div aria-owns="t3_3"></div>
<!-- loop #2 -->
<div id="t3_1" aria-owns="t3_2" role="group"></div>
<div id="t3_2" role="note">
<div aria-owns="t3_3" role="heading"></div>
</div>
<div id="t3_3" aria-owns="t3_1"></div>
<div id="t4_1"><div aria-owns="t4_1"></div></div>
<!-- self loop -->
<div id="t4_1"><div aria-owns="t4_1" role="group"></div></div>
<!-- natural and aria-owns hierarchy -->
<div id="t5_1"><div aria-owns="t5_2" role="group"></div></div>
<div id="t5_2" role="note"><div aria-owns="t5_3" role="heading"></div></div>
<div id="t5_3" role="form"><div aria-owns="t5_1" role="tooltip"></div></div>
<!-- rearrange children -->
<div id="t6_1" aria-owns="t6_3 t6_2">
<div id="t6_2" role="button"></div>
<div id="t6_3" role="checkbox"></div>
<div role="radio"></div>
</div>
<div id="t5_1"><div aria-owns="t5_2"></div>
<div id="t5_2"><div aria-owns="t5_3"></div></div>
<div id="t5_3"><div aria-owns="t5_1"></div></div>
</body>
</html>

View File

@ -26,11 +26,11 @@
function removeARIAOwns()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t2_checkbox")),
new invokerChecker(EVENT_HIDE, getNode("t2_button")),
new invokerChecker(EVENT_SHOW, getNode("t2_button")),
new invokerChecker(EVENT_SHOW, getNode("t2_checkbox")),
new invokerChecker(EVENT_REORDER, getNode("container2"))
new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
new invokerChecker(EVENT_HIDE, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
];
this.invoke = function removeARIAOwns_invoke()
@ -43,9 +43,9 @@
] },
{ PUSHBUTTON: [ ] }
] };
testAccessibleTree("container2", tree);
testAccessibleTree("t1_container", tree);
getNode("container2").removeAttribute("aria-owns");
getNode("t1_container").removeAttribute("aria-owns");
}
this.finalCheck = function removeARIAOwns_finalCheck()
@ -58,7 +58,7 @@
{ SECTION: [] }
] }
] };
testAccessibleTree("container2", tree);
testAccessibleTree("t1_container", tree);
}
this.getID = function removeARIAOwns_getID()
@ -70,16 +70,17 @@
function setARIAOwns()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t2_button")),
new invokerChecker(EVENT_SHOW, getNode("t2_button")),
new invokerChecker(EVENT_HIDE, getNode("t2_subdiv")),
new invokerChecker(EVENT_SHOW, getNode("t2_subdiv")),
new invokerChecker(EVENT_REORDER, getNode("container2"))
new invokerChecker(EVENT_HIDE, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
];
this.invoke = function setARIAOwns_invoke()
{
getNode("container2").setAttribute("aria-owns", "t2_button t2_subdiv");
getNode("t1_container").
setAttribute("aria-owns", "t1_button t1_subdiv");
}
this.finalCheck = function setARIAOwns_finalCheck()
@ -88,11 +89,11 @@
// the children.
var tree =
{ SECTION: [
{ CHECKBUTTON: [ ] }, // div
{ PUSHBUTTON: [ ] }, // button
{ SECTION: [ ] } // subdiv
{ CHECKBUTTON: [ ] }, // checkbox
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
] };
testAccessibleTree("container2", tree);
testAccessibleTree("t1_container", tree);
}
this.getID = function setARIAOwns_getID()
@ -101,19 +102,53 @@
}
}
function addIdToARIAOwns()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_group")),
new invokerChecker(EVENT_SHOW, getNode("t1_group")),
new invokerChecker(EVENT_REORDER, document)
];
this.invoke = function addIdToARIAOwns_invoke()
{
getNode("t1_container").
setAttribute("aria-owns", "t1_button t1_subdiv t1_group");
}
this.finalCheck = function addIdToARIAOwns_finalCheck()
{
// children are swapped again, button and subdiv are appended to
// the children.
var tree =
{ SECTION: [
{ CHECKBUTTON: [ ] }, // t1_checkbox
{ PUSHBUTTON: [ ] }, // button, t1_button
{ SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
{ GROUPING: [ ] } // group from outside, t1_group
] };
testAccessibleTree("t1_container", tree);
}
this.getID = function addIdToARIAOwns_getID()
{
return "Add id to @aria-owns attribute value";
}
}
function appendEl()
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getNode, "child3"),
new invokerChecker(EVENT_REORDER, getNode("container2"))
new invokerChecker(EVENT_SHOW, getNode, "t1_child3"),
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
];
this.invoke = function appendEl_invoke()
{
var div = document.createElement("div");
div.setAttribute("id", "child3");
div.setAttribute("id", "t1_child3");
div.setAttribute("role", "radio")
getNode("container2").appendChild(div);
getNode("t1_container").appendChild(div);
}
this.finalCheck = function appendEl_finalCheck()
@ -124,10 +159,11 @@
{ SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] }, // ARIA owned
{ SECTION: [ ] } // ARIA owned
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ SECTION: [ ] }, // ARIA owned, t1_subdiv
{ GROUPING: [ ] } // ARIA owned, t1_group
] };
testAccessibleTree("container2", tree);
testAccessibleTree("t1_container", tree);
}
this.getID = function appendEl_getID()
@ -139,15 +175,15 @@
function removeEl()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode, "t2_checkbox"),
new invokerChecker(EVENT_SHOW, getNode, "t2_checkbox"),
new invokerChecker(EVENT_REORDER, getNode("container2"))
new invokerChecker(EVENT_HIDE, getNode, "t1_checkbox"),
new invokerChecker(EVENT_SHOW, getNode, "t1_checkbox"),
new invokerChecker(EVENT_REORDER, getNode("t1_container"))
];
this.invoke = function removeEl_invoke()
{
// remove a container of t2_subdiv
getNode("t2_span").parentNode.removeChild(getNode("t2_span"));
// remove a container of t1_subdiv
getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
}
this.finalCheck = function removeEl_finalCheck()
@ -157,14 +193,214 @@
{ SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] } // ARIA owned
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ GROUPING: [ ] } // ARIA owned, t1_group
] };
testAccessibleTree("container2", tree);
testAccessibleTree("t1_container", tree);
}
this.getID = function removeEl_getID()
{
return "Remove a container of ARIA ownded element";
return "Remove a container of ARIA owned element";
}
}
function removeId()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_group")),
new invokerChecker(EVENT_SHOW, getNode("t1_group")),
new invokerChecker(EVENT_REORDER, document)
];
this.invoke = function removeId_invoke()
{
getNode("t1_group").removeAttribute("id");
}
this.finalCheck = function removeId_finalCheck()
{
var tree =
{ SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] } // ARIA owned, t1_button
] };
testAccessibleTree("t1_container", tree);
}
this.getID = function removeId_getID()
{
return "Remove ID from ARIA owned element";
}
}
function setId()
{
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_grouptmp")),
new invokerChecker(EVENT_SHOW, getNode("t1_grouptmp")),
new invokerChecker(EVENT_REORDER, document)
];
this.invoke = function setId_invoke()
{
getNode("t1_grouptmp").setAttribute("id", "t1_group");
}
this.finalCheck = function setId_finalCheck()
{
var tree =
{ SECTION: [
{ CHECKBUTTON: [ ] },
{ RADIOBUTTON: [ ] },
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
{ GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
] };
testAccessibleTree("t1_container", tree);
}
this.getID = function setId_getID()
{
return "Set ID that is referred by ARIA owns";
}
}
/**
* Remove an accessible DOM element containing an element referred by
* ARIA owns.
*/
function removeA11eteiner()
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("t2_container1"))
];
this.invoke = function removeA11eteiner_invoke()
{
var tree =
{ SECTION: [
{ CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
] };
testAccessibleTree("t2_container1", tree);
getNode("t2_container2").removeChild(getNode("t2_container3"));
}
this.finalCheck = function removeA11eteiner_finalCheck()
{
var tree =
{ SECTION: [
] };
testAccessibleTree("t2_container1", tree);
}
this.getID = function removeA11eteiner_getID()
{
return "Remove an accessible DOM element containing an element referred by ARIA owns";
}
}
/**
* Steal an element from other ARIA owns element. This use case guarantees
* that result of setAttribute/removeAttribute doesn't depend on their order.
*/
function stealFromOtherARIAOwns()
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
];
this.invoke = function stealFromOtherARIAOwns_invoke()
{
getNode("t3_container2").setAttribute("aria-owns", "t3_child");
}
this.finalCheck = function stealFromOtherARIAOwns_finalCheck()
{
var tree =
{ SECTION: [
] };
testAccessibleTree("t3_container1", tree);
tree =
{ SECTION: [
{ CHECKBUTTON: [
] }
] };
testAccessibleTree("t3_container2", tree);
}
this.getID = function stealFromOtherARIAOwns_getID()
{
return "Steal an element from other ARIA owns element";
}
}
function appendElToRecacheChildren()
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
];
this.invoke = function appendElToRecacheChildren_invoke()
{
var div = document.createElement("div");
div.setAttribute("role", "radio")
getNode("t3_container2").appendChild(div);
}
this.finalCheck = function appendElToRecacheChildren_finalCheck()
{
var tree =
{ SECTION: [
] };
testAccessibleTree("t3_container1", tree);
tree =
{ SECTION: [
{ RADIOBUTTON: [ ] },
{ CHECKBUTTON: [ ] } // ARIA owned
] };
testAccessibleTree("t3_container2", tree);
}
this.getID = function appendElToRecacheChildren_getID()
{
return "Append a child under @aria-owns element to trigger children recache";
}
}
function showHiddenElement()
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("t4_container1"))
];
this.invoke = function showHiddenElement_invoke()
{
var tree =
{ SECTION: [
{ RADIOBUTTON: [] }
] };
testAccessibleTree("t4_container1", tree);
getNode("t4_child1").style.display = "block";
}
this.finalCheck = function showHiddenElement_finalCheck()
{
var tree =
{ SECTION: [
{ CHECKBUTTON: [] },
{ RADIOBUTTON: [] }
] };
testAccessibleTree("t4_container1", tree);
}
this.getID = function showHiddenElement_getID()
{
return "Show hidden ARIA owns referred element";
}
}
@ -181,10 +417,24 @@
{
gQueue = new eventQueue();
// test1
gQueue.push(new removeARIAOwns());
gQueue.push(new setARIAOwns());
gQueue.push(new addIdToARIAOwns());
gQueue.push(new appendEl());
gQueue.push(new removeEl());
gQueue.push(new removeId());
gQueue.push(new setId());
// test2
gQueue.push(new removeA11eteiner());
// test3
gQueue.push(new stealFromOtherARIAOwns());
gQueue.push(new appendElToRecacheChildren());
// test4
gQueue.push(new showHiddenElement());
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
@ -202,15 +452,31 @@
<pre id="test">
</pre>
<div id="container2" aria-owns="t2_checkbox t2_button">
<div role="button" id="t2_button"></div>
<div role="checkbox" id="t2_checkbox">
<span id="t2_span">
<div id="t2_subdiv"></div>
<div id="t1_container" aria-owns="t1_checkbox t1_button">
<div role="button" id="t1_button"></div>
<div role="checkbox" id="t1_checkbox">
<span id="t1_span">
<div id="t1_subdiv"></div>
</span>
</div>
</div>
<div id="t1_group" role="group"></div>
<div id="t1_grouptmp" role="group"></div>
<div id="t2_container1" aria-owns="t2_owned"></div>
<div id="t2_container2">
<div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div>
</div>
<div id="t3_container1" aria-owns="t3_child"></div>
<div id="t3_child" role="checkbox"></div>
<div id="t3_container2"></div>
<div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
<div id="t4_container2">
<div id="t4_child1" style="display:none" role="checkbox"></div>
<div id="t4_child2" role="radio"></div>
</div>
</body>
</html>

View File

@ -22,9 +22,9 @@
this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("child")),
new invokerChecker(EVENT_REORDER, this.containerNode),
new invokerChecker(EVENT_HIDE, getNode("childDoc")),
new invokerChecker(EVENT_SHOW, "newChildDoc")
new invokerChecker(EVENT_SHOW, "newChildDoc"),
new invokerChecker(EVENT_REORDER, this.containerNode)
];
this.invoke = function runTest_invoke()

View File

@ -22,7 +22,9 @@ file.mkpath(storeFile.path);
storeFile.append("store.json");
var storeFilename = storeFile.path;
function manager(loader) loader.sandbox("sdk/simple-storage").manager;
function manager(loader) {
return loader.sandbox("sdk/simple-storage").manager;
}
exports.testSetGet = function (assert, done) {
// Load the module once, set a value.

View File

@ -343,7 +343,6 @@ pref("image.mem.surfacecache.max_size_kb", 131072); // 128MB
pref("image.mem.surfacecache.size_factor", 8); // 1/8 of main memory
pref("image.mem.surfacecache.discard_factor", 2); // Discard 1/2 of the surface cache at a time.
pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook
pref("image.onload.decode.limit", 24); /* don't decode more than 24 images eagerly */
// XXX this isn't a good check for "are touch events supported", but
// we don't really have a better one at the moment.

View File

@ -24,7 +24,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>

View File

@ -24,7 +24,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>

View File

@ -20,7 +20,7 @@
<project name="gaia" path="gaia" remote="mozillaorg" revision="91cac94948094cfdcd00cba5c6483e27e80cb3b0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="27de93fe66c3e80e157d157bd52ca99565351669"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>

View File

@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>

View File

@ -24,7 +24,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>

View File

@ -24,7 +24,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>

View File

@ -21,7 +21,7 @@
<project name="gaia" path="gaia" remote="mozillaorg" revision="91cac94948094cfdcd00cba5c6483e27e80cb3b0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="27de93fe66c3e80e157d157bd52ca99565351669"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

View File

@ -24,7 +24,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
<project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="95bc959ff0e4ce73e1c9ed5e6916d84922d0a3cc"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="21f7fdaf4ee341022a0416e9186e7b07218cc4b1"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>

View File

@ -159,12 +159,14 @@ let RemoteDirectoryLinksProvider = {
*/
_newTabHasInadjacentSite: false,
get _observedPrefs() Object.freeze({
enhanced: PREF_NEWTAB_ENHANCED,
linksURL: PREF_DIRECTORY_SOURCE,
matchOSLocale: PREF_MATCH_OS_LOCALE,
prefSelectedLocale: PREF_SELECTED_LOCALE,
}),
get _observedPrefs() {
return Object.freeze({
enhanced: PREF_NEWTAB_ENHANCED,
linksURL: PREF_DIRECTORY_SOURCE,
matchOSLocale: PREF_MATCH_OS_LOCALE,
prefSelectedLocale: PREF_SELECTED_LOCALE,
});
},
get _linksURL() {
if (!this.__linksURL) {

View File

@ -7255,9 +7255,6 @@ if test -z "$MOZ_MEMORY"; then
esac
else
AC_DEFINE(MOZ_MEMORY)
if test -n "$NIGHTLY_BUILD"; then
MOZ_JEMALLOC4=1
fi
if test -n "$MOZ_JEMALLOC4"; then
AC_DEFINE(MOZ_JEMALLOC4)
fi

View File

@ -52,7 +52,9 @@ var Converter = Class({
"nsIRequestObserver"
],
get wrappedJSObject() this,
get wrappedJSObject() {
return this;
},
/**
* This component works as such:

View File

@ -39,7 +39,9 @@ var Sniffer = Class({
"nsIContentSniffer",
],
get wrappedJSObject() this,
get wrappedJSObject() {
return this;
},
getMIMETypeFromContent: function(aRequest, aData, aLength) {
// JSON View is enabled only for top level loads only.

View File

@ -82,6 +82,7 @@
#include "nsViewSourceHandler.h"
#include "nsWhitespaceTokenizer.h"
#include "nsICookieService.h"
#include "nsIConsoleReportCollector.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -5015,17 +5016,7 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
error.AssignLiteral("corruptedContentError");
break;
case NS_ERROR_INTERCEPTION_FAILED:
case NS_ERROR_OPAQUE_INTERCEPTION_DISABLED:
case NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE:
case NS_ERROR_INTERCEPTED_ERROR_RESPONSE:
case NS_ERROR_INTERCEPTED_USED_RESPONSE:
case NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION:
case NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION:
case NS_ERROR_INTERCEPTION_CANCELED:
case NS_ERROR_REJECTED_RESPONSE_INTERCEPTION:
// ServiceWorker intercepted request, but something went wrong.
nsContentUtils::MaybeReportInterceptionErrorToConsole(GetDocument(),
aError);
error.AssignLiteral("corruptedContentError");
break;
default:
@ -7357,6 +7348,11 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
if (reporter) {
reporter->FlushConsoleReports(GetDocument());
}
nsCOMPtr<nsIURI> url;
nsresult rv = aChannel->GetURI(getter_AddRefs(url));
if (NS_FAILED(rv)) {
@ -7683,13 +7679,6 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
aStatus == NS_ERROR_REMOTE_XUL ||
aStatus == NS_ERROR_INTERCEPTION_FAILED ||
aStatus == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED ||
aStatus == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE ||
aStatus == NS_ERROR_INTERCEPTED_ERROR_RESPONSE ||
aStatus == NS_ERROR_INTERCEPTED_USED_RESPONSE ||
aStatus == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION ||
aStatus == NS_ERROR_INTERCEPTION_CANCELED ||
aStatus == NS_ERROR_REJECTED_RESPONSE_INTERCEPTION ||
NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
// Errors to be shown for any frame
DisplayLoadError(aStatus, url, nullptr, aChannel);

View File

@ -67,15 +67,18 @@ ActivitiesDb.prototype = {
let self = this;
/**
* WARNING!! Before upgrading the Activities DB take into account that an
* OTA unregisters all the activities and reinstalls them during the first
* run process. Check Bug 1193503.
*/
function upgrade(currentVersion) {
let next = upgrade.bind(self, currentVersion + 1);
switch (currentVersion) {
case 0:
self.createSchema(aDb, next);
break;
case 1:
self.upgradeSchemaVersion2(aDb, aTransaction, next);
break;
}
}
@ -94,47 +97,6 @@ ActivitiesDb.prototype = {
aNext();
},
upgradeSchemaVersion2: function(aDb, aTransaction, aNext) {
debug("Upgrading DB to version 2");
// In order to be able to have multiple activities with same name
// but different descriptions, we need to update the keypath from
// a hash made from {manifest, name} to a hash made from {manifest,
// name, description}.
//
// Unfortunately, updating the keypath is not allowed by IDB, so we
// need to remove and recreate the activities object store.
let activities = [];
let objectStore = aTransaction.objectStore(STORE_NAME);
objectStore.openCursor().onsuccess = (event) => {
let cursor = event.target.result;
if (!cursor) {
aDb.deleteObjectStore(STORE_NAME);
let objectStore = aDb.createObjectStore(STORE_NAME, { keyPath: "id" });
// indexes
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("manifest", "manifest", { unique: false });
this.add(activities, () => {
debug("DB upgraded to version 2");
aNext();
}, () => {
dump("Error upgrading DB to version 2 " + error + "\n");
});
return;
}
let activity = cursor.value;
debug("Upgrading activity " + JSON.stringify(activity));
activity.id = this.createId(activity);
activities.push(activity);
cursor.continue();
};
},
// unique ids made of (uri, action)
createId: function actdb_createId(aObject) {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]

View File

@ -365,6 +365,11 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"audio-capture:3gpp2": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"nfc": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,

View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/ConsoleReportCollector.h"
#include "nsNetUtil.h"
namespace mozilla {
NS_IMPL_ISUPPORTS(ConsoleReportCollector, nsIConsoleReportCollector)
ConsoleReportCollector::ConsoleReportCollector()
: mMutex("mozilla::ConsoleReportCollector")
{
}
void
ConsoleReportCollector::AddConsoleReport(uint32_t aErrorFlags,
const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI,
uint32_t aLineNumber,
uint32_t aColumnNumber,
const nsACString& aMessageName,
const nsTArray<nsString>& aStringParams)
{
// any thread
MutexAutoLock lock(mMutex);
mPendingReports.AppendElement(PendingReport(aErrorFlags, aCategory,
aPropertiesFile, aSourceFileURI,
aLineNumber, aColumnNumber,
aMessageName, aStringParams));
}
void
ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<PendingReport> reports;
{
MutexAutoLock lock(mMutex);
mPendingReports.SwapElements(reports);
}
for (uint32_t i = 0; i < reports.Length(); ++i) {
PendingReport& report = reports[i];
// It would be nice if we did not have to do this since ReportToConsole()
// just turns around and converts it back to a spec.
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), report.mSourceFileURI);
if (NS_FAILED(rv)) {
continue;
}
// Convert back from nsTArray<nsString> to the char16_t** format required
// by our l10n libraries and ReportToConsole. (bug 1219762)
UniquePtr<const char16_t*[]> params;
uint32_t paramsLength = report.mStringParams.Length();
if (paramsLength > 0) {
params = MakeUnique<const char16_t*[]>(paramsLength);
for (uint32_t j = 0; j < paramsLength; ++j) {
params[j] = report.mStringParams[j].get();
}
}
nsContentUtils::ReportToConsole(report.mErrorFlags, report.mCategory,
aDocument, report.mPropertiesFile,
report.mMessageName.get(),
params.get(),
paramsLength, uri, EmptyString(),
report.mLineNumber, report.mColumnNumber);
}
}
ConsoleReportCollector::~ConsoleReportCollector()
{
}
} // namespace mozilla

View File

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_ConsoleReportCollector_h
#define mozilla_ConsoleReportCollector_h
#include "mozilla/Mutex.h"
#include "nsIConsoleReportCollector.h"
#include "nsTArray.h"
namespace mozilla {
class ConsoleReportCollector final : public nsIConsoleReportCollector
{
public:
ConsoleReportCollector();
void
AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI,
uint32_t aLineNumber, uint32_t aColumnNumber,
const nsACString& aMessageName,
const nsTArray<nsString>& aStringParams) override;
void
FlushConsoleReports(nsIDocument* aDocument) override;
private:
~ConsoleReportCollector();
struct PendingReport
{
PendingReport(uint32_t aErrorFlags, const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI, uint32_t aLineNumber,
uint32_t aColumnNumber, const nsACString& aMessageName,
const nsTArray<nsString>& aStringParams)
: mErrorFlags(aErrorFlags)
, mCategory(aCategory)
, mPropertiesFile(aPropertiesFile)
, mSourceFileURI(aSourceFileURI)
, mLineNumber(aLineNumber)
, mColumnNumber(aColumnNumber)
, mMessageName(aMessageName)
, mStringParams(aStringParams)
{ }
const uint32_t mErrorFlags;
const nsCString mCategory;
const nsContentUtils::PropertiesFile mPropertiesFile;
const nsCString mSourceFileURI;
const uint32_t mLineNumber;
const uint32_t mColumnNumber;
const nsCString mMessageName;
const nsTArray<nsString> mStringParams;
};
Mutex mMutex;
// protected by mMutex
nsTArray<PendingReport> mPendingReports;
public:
NS_DECL_THREADSAFE_ISUPPORTS
};
} // namespace mozilla
#endif // mozilla_ConsoleReportCollector_h

View File

@ -84,6 +84,7 @@ EXPORTS += [
'nsHostObjectURI.h',
'nsIAnimationObserver.h',
'nsIAttribute.h',
'nsIConsoleReportCollector.h',
'nsIContent.h',
'nsIContentInlines.h',
'nsIContentIterator.h',
@ -142,6 +143,7 @@ if CONFIG['MOZ_WEBRTC']:
]
EXPORTS.mozilla += [
'ConsoleReportCollector.h',
'CORSMode.h',
'FeedWriterEnabled.h',
'TextInputProcessor.h',
@ -222,6 +224,7 @@ UNIFIED_SOURCES += [
'ChromeUtils.cpp',
'Comment.cpp',
'Console.cpp',
'ConsoleReportCollector.cpp',
'Crypto.cpp',
'DirectionalityUtils.cpp',
'DocumentFragment.cpp',

View File

@ -36,6 +36,7 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/Element.h"
@ -188,6 +189,7 @@
#include "nsViewManager.h"
#include "nsViewportInfo.h"
#include "nsWidgetsCID.h"
#include "nsIWindowProvider.h"
#include "nsWrapperCacheInlines.h"
#include "nsXULPopupManager.h"
#include "xpcprivate.h" // nsXPConnect
@ -3477,42 +3479,6 @@ nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
aLineNumber, aColumnNumber);
}
/* static */ nsresult
nsContentUtils::MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument,
nsresult aError)
{
const char* messageName = nullptr;
if (aError == NS_ERROR_INTERCEPTION_FAILED) {
messageName = "InterceptionFailed";
} else if (aError == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED) {
messageName = "OpaqueInterceptionDisabled";
} else if (aError == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE) {
messageName = "BadOpaqueInterceptionRequestMode";
} else if (aError == NS_ERROR_INTERCEPTED_ERROR_RESPONSE) {
messageName = "InterceptedErrorResponse";
} else if (aError == NS_ERROR_INTERCEPTED_USED_RESPONSE) {
messageName = "InterceptedUsedResponse";
} else if (aError == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION) {
messageName = "ClientRequestOpaqueInterception";
} else if (aError == NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION) {
messageName = "BadOpaqueRedirectInterception";
} else if (aError == NS_ERROR_INTERCEPTION_CANCELED) {
messageName = "InterceptionCanceled";
} else if (aError == NS_ERROR_REJECTED_RESPONSE_INTERCEPTION) {
messageName = "InterceptionRejectedResponse";
}
if (messageName) {
return ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("Service Worker Interception"),
aDocument,
nsContentUtils::eDOM_PROPERTIES,
messageName);
}
return NS_OK;
}
/* static */ nsresult
nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
@ -5206,6 +5172,14 @@ nsContentUtils::RemoveScriptBlocker()
sBlockedScriptRunners->RemoveElementsAt(originalFirstBlocker, blockersCount);
}
/* static */
nsIWindowProvider*
nsContentUtils::GetWindowProviderForContentProcess()
{
MOZ_ASSERT(XRE_IsContentProcess());
return ContentChild::GetSingleton();
}
/* static */
void
nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument)

View File

@ -102,6 +102,7 @@ class nsWrapperCache;
class nsAttrValue;
class nsITransferable;
class nsPIWindowRoot;
class nsIWindowProvider;
struct JSPropertyDescriptor;
struct JSRuntime;
@ -900,9 +901,6 @@ public:
uint32_t aLineNumber = 0,
uint32_t aColumnNumber = 0);
static nsresult
MaybeReportInterceptionErrorToConsole(nsIDocument* aDocument, nsresult aError);
static void LogMessageToConsole(const char* aMsg, ...);
/**
@ -1640,6 +1638,11 @@ public:
return sScriptBlockerCount == 0;
}
// XXXcatalinb: workaround for weird include error when trying to reference
// ipdl types in WindowWatcher.
static nsIWindowProvider*
GetWindowProviderForContentProcess();
/**
* Call this function if !IsSafeToRunScript() and we fail to run the script
* (rather than using AddScriptRunner as we usually do). |aDocument| is

View File

@ -2117,9 +2117,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mInUnlinkOrDeletion = false;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
static bool sPrefsInitialized = false;
static uint32_t sOnloadDecodeLimit = 0;
nsresult
nsDocument::Init()
{
@ -2127,11 +2124,6 @@ nsDocument::Init()
return NS_ERROR_ALREADY_INITIALIZED;
}
if (!sPrefsInitialized) {
sPrefsInitialized = true;
Preferences::AddUintVarCache(&sOnloadDecodeLimit, "image.onload.decode.limit", 0);
}
// Force initialization.
nsINode::nsSlots* slots = Slots();
@ -10522,12 +10514,8 @@ nsDocument::AddImage(imgIRequest* aImage)
// If this is the first insertion and we're locking images, lock this image
// too.
if (oldCount == 0) {
if (mLockingImages)
rv = aImage->LockImage();
if (NS_SUCCEEDED(rv) && (!sOnloadDecodeLimit ||
mImageTracker.Count() < sOnloadDecodeLimit))
rv = aImage->StartDecoding();
if (oldCount == 0 && mLockingImages) {
rv = aImage->LockImage();
}
// If this is the first insertion and we're animating images, request
@ -10658,7 +10646,6 @@ PLDHashOperator LockEnumerator(imgIRequest* aKey,
void* userArg)
{
aKey->LockImage();
aKey->RequestDecode();
return PL_DHASH_NEXT;
}

View File

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsIConsoleReportCollector_h
#define nsIConsoleReportCollector_h
#include "nsContentUtils.h"
#include "nsISupports.h"
#include "nsTArrayForwardDeclare.h"
class nsACString;
class nsIDocument;
class nsString;
#define NS_NSICONSOLEREPORTCOLLECTOR_IID \
{0xdd98a481, 0xd2c4, 0x4203, {0x8d, 0xfa, 0x85, 0xbf, 0xd7, 0xdc, 0xd7, 0x05}}
// An interface for saving reports until we can flush them to the correct
// window at a later time.
class NS_NO_VTABLE nsIConsoleReportCollector : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NSICONSOLEREPORTCOLLECTOR_IID)
// Add a pending report to be later displayed on the console. This may be
// called from any thread.
//
// aErrorFlags A nsIScriptError flags value.
// aCategory Name of module reporting error.
// aPropertiesFile Properties file containing localized message.
// aSourceFileURI The URI of the script generating the error. Must be a URI
// spec.
// aLineNumber The line number where the error was generated. May be 0 if
// the line number is not known.
// aColumnNumber The column number where the error was generated. May be 0
// if the line number is not known.
// aMessageName The name of the localized message contained in the
// properties file.
// aStringParams An array of nsString parameters to use when localizing the
// message.
virtual void
AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI, uint32_t aLineNumber,
uint32_t aColumnNumber, const nsACString& aMessageName,
const nsTArray<nsString>& aStringParams) = 0;
// A version of AddConsoleReport() that accepts the message parameters
// as variable nsString arguments. Note, the parameters must be exactly
// nsString and not another string class. All other args the same as
// AddConsoleReport().
template<typename... Params>
void
AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
nsContentUtils::PropertiesFile aPropertiesFile,
const nsACString& aSourceFileURI, uint32_t aLineNumber,
uint32_t aColumnNumber, const nsACString& aMessageName,
Params... aParams)
{
nsTArray<nsString> params;
mozilla::dom::StringArrayAppender::Append(params, sizeof...(Params), aParams...);
AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile, aSourceFileURI,
aLineNumber, aColumnNumber, aMessageName, params);
}
// Flush all pending reports to the console.
//
// aDocument An optional document representing where to flush the
// reports. If provided, then the corresponding window's
// web console will get the reports. Otherwise the reports
// go to the browser console.
virtual void
FlushConsoleReports(nsIDocument* aDocument) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIConsoleReportCollector, NS_NSICONSOLEREPORTCOLLECTOR_IID)
#endif // nsIConsoleReportCollector_h

View File

@ -229,53 +229,6 @@ nsImageLoadingContent::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
MOZ_ASSERT(aRequest == mCurrentRequest,
"One way or another, we should be current by now");
// We just loaded all the data we're going to get. If we're visible and
// haven't done an initial paint (*), we want to make sure the image starts
// decoding immediately, for two reasons:
//
// 1) This image is sitting idle but might need to be decoded as soon as we
// start painting, in which case we've wasted time.
//
// 2) We want to block onload until all visible images are decoded. We do this
// by blocking onload until all in-progress decodes get at least one frame
// decoded. However, if all the data comes in while painting is suppressed
// (ie, before the initial paint delay is finished), we fire onload without
// doing a paint first. This means that decode-on-draw images don't start
// decoding, so we can't wait for them to finish. See bug 512435.
//
// (*) IsPaintingSuppressed returns false if we haven't gotten the initial
// reflow yet, so we have to test !DidInitialize || IsPaintingSuppressed.
// It's possible for painting to be suppressed for reasons other than the
// initial paint delay (for example, being in the bfcache), but we probably
// aren't loading images in those situations.
// XXXkhuey should this be GetOurCurrentDoc? Decoding if we're not in
// the document seems silly.
nsIDocument* doc = GetOurOwnerDoc();
nsIPresShell* shell = doc ? doc->GetShell() : nullptr;
if (shell && shell->IsVisible() &&
(!shell->DidInitialize() || shell->IsPaintingSuppressed())) {
nsIFrame* f = GetOurPrimaryFrame();
// If we haven't gotten a frame yet either we aren't going to (so don't
// bother kicking off a decode), or we will get very soon on the next
// refresh driver tick when it flushes. And it will most likely be a
// specific image type frame (we only create generic (ie inline) type
// frames for images that don't have a size, and since we have all the data
// we should have the size) which will check its own visibility on its
// first reflow.
if (f) {
// If we've gotten a frame and that frame has called FrameCreate and that
// frame has been reflowed then we know that it checked it's own visibility
// so we can trust our visible count and we don't start decode if we are not
// visible.
if (!mFrameCreateCalled || (f->GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
mVisibleCount > 0 || shell->AssumeAllImagesVisible()) {
mCurrentRequest->StartDecoding();
}
}
}
// Fire the appropriate DOM event.
if (NS_SUCCEEDED(aStatus)) {
FireEvent(NS_LITERAL_STRING("load"));

View File

@ -126,22 +126,24 @@ function setUp() {
['network.disable.ipc.security', true]]}, runNextTest);
}
function makeKillTest(isApp) function testKill() {
loadBrowser(isApp, function (iframe) {
// We want to make sure we get notified on both the frame and
// process message managers.
let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
prepareProcess(frameMM, function (processMM) {
// Let's kill the content process by asking for a permission
// that it doesn't have.
ok(!processMM.assertPermission("frobnaz"),
"Content child should not have this permission");
expectFrameProcessShutdown(iframe, frameMM, processMM, function () {
iframe.parentNode.removeChild(iframe);
runNextTest();
function makeKillTest(isApp) {
return function testKill() {
loadBrowser(isApp, function (iframe) {
// We want to make sure we get notified on both the frame and
// process message managers.
let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
prepareProcess(frameMM, function (processMM) {
// Let's kill the content process by asking for a permission
// that it doesn't have.
ok(!processMM.assertPermission("frobnaz"),
"Content child should not have this permission");
expectFrameProcessShutdown(iframe, frameMM, processMM, function () {
iframe.parentNode.removeChild(iframe);
runNextTest();
});
});
});
});
};
}
function tearDown() {

View File

@ -495,6 +495,7 @@ DOMInterfaces = {
'binaryNames': {
'request': 'request_'
},
'implicitJSContext': [ 'respondWith' ],
},
'FileReader': {

View File

@ -743,7 +743,7 @@ class CGInterfaceObjectJSClass(CGThing):
nullptr, /* unwatch */
nullptr, /* getElements */
nullptr, /* enumerate */
nullptr, /* thisObject */
nullptr, /* thisValue */
InterfaceObjectToString, /* funToString */
}
},

View File

@ -177,7 +177,7 @@ public:
// this method always sets Event.defaultPrevented true for web contents.
// If default action handler calls this, web applications meet wrong
// defaultPrevented value.
void PreventDefault(JSContext* aCx);
virtual void PreventDefault(JSContext* aCx);
// You MUST NOT call DefaultPrevented(JSContext*) from C++ code. This may
// return false even if PreventDefault() has been called.
@ -298,7 +298,8 @@ private:
} // namespace mozilla
#define NS_FORWARD_TO_EVENT \
NS_FORWARD_NSIDOMEVENT(Event::)
NS_FORWARD_NSIDOMEVENT(Event::) \
virtual void PreventDefault(JSContext* aCx) override { Event::PreventDefault(aCx); }
#define NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(_to) \
NS_IMETHOD GetType(nsAString& aType) override { return _to GetType(aType); } \
@ -326,7 +327,8 @@ private:
NS_IMETHOD_(Event*) InternalDOMEvent() override { return _to InternalDOMEvent(); }
#define NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION \
NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::)
NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::) \
virtual void PreventDefault(JSContext* aCx) override { Event::PreventDefault(aCx); }
inline nsISupports*
ToSupports(mozilla::dom::Event* e)

View File

@ -47,6 +47,7 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/PCompositorChild.h"
#include "mozilla/layers/SharedBufferManagerChild.h"
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/plugins/PluginInstanceParent.h"
#include "mozilla/plugins/PluginModuleParent.h"
@ -216,6 +217,7 @@ using namespace mozilla::gmp;
using namespace mozilla::hal_sandbox;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::net;
using namespace mozilla::jsipc;
using namespace mozilla::psm;
@ -608,7 +610,8 @@ ContentChild::~ContentChild()
NS_INTERFACE_MAP_BEGIN(ContentChild)
NS_INTERFACE_MAP_ENTRY(nsIContentChild)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentChild)
NS_INTERFACE_MAP_END
bool
@ -741,6 +744,176 @@ ContentChild::SetProcessName(const nsAString& aName, bool aDontOverride)
}
}
NS_IMETHODIMP
ContentChild::ProvideWindow(nsIDOMWindow* aParent,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn)
{
return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
aCalledFromJS, aPositionSpecified,
aSizeSpecified, aURI, aName, aFeatures,
aWindowIsNew, aReturn);
}
nsresult
ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
nsIDOMWindow* aParent,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn)
{
*aReturn = nullptr;
nsAutoPtr<IPCTabContext> ipcContext;
TabId openerTabId = TabId(0);
if (aTabOpener) {
PopupIPCTabContext context;
openerTabId = aTabOpener->GetTabId();
context.opener() = openerTabId;
context.isBrowserElement() = aTabOpener->IsBrowserElement();
ipcContext = new IPCTabContext(context);
} else {
// It's possible to not have a TabChild opener in the case
// of ServiceWorker::OpenWindow.
UnsafeIPCTabContext unsafeTabContext;
ipcContext = new IPCTabContext(unsafeTabContext);
}
MOZ_ASSERT(ipcContext);
TabId tabId;
SendAllocateTabId(openerTabId,
*ipcContext,
GetID(),
&tabId);
TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
RefPtr<TabChild> newChild = new TabChild(this, tabId,
newTabContext, aChromeFlags);
if (NS_FAILED(newChild->Init())) {
return NS_ERROR_ABORT;
}
if (aTabOpener) {
MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
}
unused << SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
RefPtr<TabChild>(newChild).forget().take(),
tabId, *ipcContext, aChromeFlags,
GetID(), IsForApp(), IsForBrowser());
nsAutoCString spec;
if (aURI) {
aURI->GetSpec(spec);
}
NS_ConvertUTF8toUTF16 url(spec);
nsString name(aName);
nsAutoCString features(aFeatures);
nsTArray<FrameScriptInfo> frameScripts;
nsCString urlToLoad;
if (aIframeMoz) {
MOZ_ASSERT(aTabOpener);
newChild->SendBrowserFrameOpenWindow(aTabOpener, url, name,
NS_ConvertUTF8toUTF16(features),
aWindowIsNew);
} else {
nsAutoCString baseURIString;
if (aTabOpener) {
nsCOMPtr<nsPIDOMWindow> opener = do_QueryInterface(aParent);
nsCOMPtr<nsIDocument> doc = opener->GetDoc();
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
baseURI->GetSpec(baseURIString);
}
nsresult rv;
if (!SendCreateWindow(aTabOpener, newChild,
aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, url,
name, features,
NS_ConvertUTF8toUTF16(baseURIString),
&rv,
aWindowIsNew,
&frameScripts,
&urlToLoad)) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_FAILED(rv)) {
return rv;
}
}
if (!*aWindowIsNew) {
PBrowserChild::Send__delete__(newChild);
return NS_ERROR_ABORT;
}
TextureFactoryIdentifier textureFactoryIdentifier;
uint64_t layersId = 0;
PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
newChild->SendGetRenderFrameInfo(renderFrame,
&textureFactoryIdentifier,
&layersId);
if (layersId == 0) { // if renderFrame is invalid.
PRenderFrameChild::Send__delete__(renderFrame);
renderFrame = nullptr;
}
ShowInfo showInfo(EmptyString(), false, false, true,
aTabOpener->mDPI, aTabOpener->mDefaultScale);
nsCOMPtr<nsPIDOMWindow> opener = do_QueryInterface(aParent);
nsIDocShell* openerShell;
if (opener && (openerShell = opener->GetDocShell())) {
nsCOMPtr<nsILoadContext> context = do_QueryInterface(openerShell);
showInfo = ShowInfo(EmptyString(), false,
context->UsePrivateBrowsing(), true,
aTabOpener->mDPI, aTabOpener->mDefaultScale);
}
// Unfortunately we don't get a window unless we've shown the frame. That's
// pretty bogus; see bug 763602.
newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame,
showInfo);
for (size_t i = 0; i < frameScripts.Length(); i++) {
FrameScriptInfo& info = frameScripts[i];
if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
MOZ_CRASH();
}
}
if (!urlToLoad.IsEmpty()) {
newChild->RecvLoadURL(urlToLoad, BrowserConfiguration(), showInfo);
}
nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
win.forget(aReturn);
return NS_OK;
}
void
ContentChild::GetProcessName(nsAString& aName)
{
@ -2748,7 +2921,8 @@ ContentChild::RecvShutdown()
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(this, "content-child-shutdown", nullptr);
os->NotifyObservers(static_cast<nsIContentChild*>(this),
"content-child-shutdown", nullptr);
}
GetIPCChannel()->SetAbortOnError(false);

View File

@ -17,6 +17,7 @@
#include "nsTHashtable.h"
#include "nsWeakPtr.h"
#include "nsIWindowProvider.h"
struct ChromePackage;
@ -47,6 +48,7 @@ class ClonedMessageData;
class TabChild;
class ContentChild final : public PContentChild
, public nsIWindowProvider
, public nsIContentChild
{
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
@ -55,6 +57,8 @@ class ContentChild final : public PContentChild
typedef mozilla::ipc::URIParams URIParams;
public:
NS_DECL_NSIWINDOWPROVIDER
ContentChild();
virtual ~ContentChild();
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
@ -71,6 +75,20 @@ public:
nsCString vendor;
};
nsresult
ProvideWindowCommon(TabChild* aTabOpener,
nsIDOMWindow* aOpener,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
bool Init(MessageLoop* aIOLoop,
base::ProcessId aParentPid,
IPC::Channel* aChannel);

View File

@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "ContentParent.h"
#include "TabParent.h"
#if defined(ANDROID) || defined(LINUX)
# include <sys/time.h>
@ -144,7 +145,13 @@
#include "nsISystemMessagesInternal.h"
#include "nsITimer.h"
#include "nsIURIFixup.h"
#include "nsIWindowMediator.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIXULWindow.h"
#include "nsIDOMChromeWindow.h"
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsWindowWatcher.h"
#include "nsIXULRuntime.h"
#include "gfxDrawable.h"
#include "ImageOps.h"
@ -166,6 +173,7 @@
#include "nsIWebBrowserChrome.h"
#include "nsIDocShell.h"
#include "nsDocShell.h"
#include "nsOpenURIInFrameParams.h"
#include "mozilla/net/NeckoMessageUtils.h"
#include "gfxPrefs.h"
#include "prio.h"
@ -5343,6 +5351,236 @@ ContentParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumen
return true;
}
static already_AddRefed<nsPIDOMWindow>
FindMostRecentOpenWindow()
{
nsCOMPtr<nsIWindowMediator> windowMediator =
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
windowMediator->GetEnumerator(MOZ_UTF16("navigator:browser"),
getter_AddRefs(windowEnumerator));
nsCOMPtr<nsPIDOMWindow> latest;
bool hasMore = false;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
while (hasMore) {
nsCOMPtr<nsISupports> item;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->GetNext(getter_AddRefs(item))));
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(item);
if (window && !window->Closed()) {
latest = window;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
}
return latest.forget();
}
bool
ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
PBrowserParent* aNewTab,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsCString& aFeatures,
const nsString& aBaseURI,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad)
{
// We always expect to open a new window here. If we don't, it's an error.
*aWindowIsNew = true;
// The content process should never be in charge of computing whether or
// not a window should be private or remote - the parent will do that.
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
TabParent* thisTabParent = nullptr;
if (aThisTab) {
thisTabParent = TabParent::GetFrom(aThisTab);
}
if (NS_WARN_IF(thisTabParent && thisTabParent->IsBrowserOrApp())) {
return false;
}
nsCOMPtr<nsPIWindowWatcher> pwwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
}
TabParent* newTab = TabParent::GetFrom(aNewTab);
MOZ_ASSERT(newTab);
// Content has requested that we open this new content window, so
// we must have an opener.
newTab->SetHasContentOpener(true);
nsCOMPtr<nsIContent> frame;
if (thisTabParent) {
frame = do_QueryInterface(thisTabParent->GetOwnerElement());
}
nsCOMPtr<nsPIDOMWindow> parent;
if (frame) {
parent = frame->OwnerDoc()->GetWindow();
// If our chrome window is in the process of closing, don't try to open a
// new tab in it.
if (parent && parent->Closed()) {
parent = nullptr;
}
}
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
if (thisTabParent) {
browserDOMWin = thisTabParent->GetBrowserDOMWindow();
}
// If we haven't found a chrome window to open in, just use the most recently
// opened one.
if (!parent) {
parent = FindMostRecentOpenWindow();
if (NS_WARN_IF(!parent)) {
*aResult = NS_ERROR_FAILURE;
return true;
}
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(parent);
if (rootChromeWin) {
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
}
}
int32_t openLocation =
nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
aPositionSpecified, aSizeSpecified);
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
// Opening new tabs is the easy case...
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
if (NS_WARN_IF(!browserDOMWin)) {
*aResult = NS_ERROR_FAILURE;
return true;
}
bool isPrivate = false;
if (thisTabParent) {
nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
loadContext->GetUsePrivateBrowsing(&isPrivate);
}
nsCOMPtr<nsIOpenURIInFrameParams> params = new nsOpenURIInFrameParams();
params->SetReferrer(aBaseURI);
params->SetIsPrivate(isPrivate);
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
browserDOMWin->OpenURIInFrame(nullptr, params,
openLocation,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (!frameLoaderOwner) {
*aWindowIsNew = false;
}
newTab->SwapFrameScriptsFrom(*aFrameScripts);
return true;
}
// WindowWatcher is going to expect a valid URI to open a window
// to. If it can't find one, it's going to attempt to figure one
// out on its own, which is problematic because it can't access
// the document for the remote browser we're opening. Luckily,
// TabChild has sent us a baseURI with which we can ensure that
// the URI we pass to WindowWatcher is valid.
nsCOMPtr<nsIURI> baseURI;
*aResult = NS_NewURI(getter_AddRefs(baseURI), aBaseURI);
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
}
nsAutoCString finalURIString;
if (!aURI.IsEmpty()) {
nsCOMPtr<nsIURI> finalURI;
*aResult = NS_NewURI(getter_AddRefs(finalURI), NS_ConvertUTF16toUTF8(aURI).get(), baseURI);
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
}
finalURI->GetSpec(finalURIString);
}
nsCOMPtr<nsIDOMWindow> window;
TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
const char* features = aFeatures.Length() ? aFeatures.get() : nullptr;
*aResult = pwwatch->OpenWindow2(parent, finalURIString.get(),
NS_ConvertUTF16toUTF8(aName).get(),
features, aCalledFromJS,
false, false, thisTabParent, nullptr, getter_AddRefs(window));
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
}
*aResult = NS_ERROR_FAILURE;
nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
if (NS_WARN_IF(!pwindow)) {
return true;
}
nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
if (NS_WARN_IF(!windowDocShell)) {
return true;
}
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
if (NS_WARN_IF(!xulWin)) {
return true;
}
nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
if (NS_WARN_IF(!xulBrowserWin)) {
return true;
}
nsCOMPtr<nsITabParent> newRemoteTab;
*aResult = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
}
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
newTab->SwapFrameScriptsFrom(*aFrameScripts);
return true;
}
/* static */ bool
ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
const TabId& aTabId)

View File

@ -434,6 +434,21 @@ public:
void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; }
void ForkNewProcess(bool aBlocking);
virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
PBrowserParent* aOpener,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsCString& aFeatures,
const nsString& aBaseURI,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad) override;
protected:
void OnChannelConnected(int32_t pid) override;
virtual void ActorDestroy(ActorDestroyReason why) override;

View File

@ -150,10 +150,9 @@ ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
struct RemoteFrameInfo info;
const IPCTabContextUnion& contextUnion = aContext.contextUnion();
// If it's a PopupIPCTabContext, it's the case that a TabChild want to
// open a new tab. aOpenerTabId has to be it's parent frame's opener id.
if (contextUnion.type() == IPCTabContextUnion::TPopupIPCTabContext) {
if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
@ -162,7 +161,7 @@ ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
const PopupIPCTabContext &ipcContext = contextUnion.get_PopupIPCTabContext();
const PopupIPCTabContext &ipcContext = aContext.get_PopupIPCTabContext();
MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());

View File

@ -90,16 +90,11 @@ struct ShowInfo
nsString name;
bool fullscreenAllowed;
bool isPrivate;
bool fakeShowInfo;
float dpi;
double defaultScale;
};
struct FrameScriptInfo
{
nsString url;
bool runInGlobalScope;
};
prio(normal upto urgent) sync protocol PBrowser
{
manager PContent or PContentBridge;
@ -165,20 +160,6 @@ parent:
Event(RemoteDOMEvent aEvent);
sync CreateWindow(PBrowser aNewTab,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsString aURI,
nsString aName,
nsCString aFeatures,
nsString aBaseURI)
returns (nsresult rv,
bool windowOpened,
FrameScriptInfo[] frameScripts,
nsCString urlToLoad);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (StructuredCloneData[] retval);
@ -573,7 +554,7 @@ child:
nullable PRenderFrame renderFrame,
bool parentIsActive);
LoadURL(nsCString uri, BrowserConfiguration config);
LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info);
CacheFileDescriptor(nsString path, FileDescriptor fd);

View File

@ -410,6 +410,12 @@ union GamepadChangeEvent {
GamepadButtonInformation;
};
struct FrameScriptInfo
{
nsString url;
bool runInGlobalScope;
};
prio(normal upto urgent) sync protocol PContent
{
parent spawns PPluginModule;
@ -1112,6 +1118,21 @@ parent:
sync GetGraphicsDeviceInitData()
returns (DeviceInitData aData);
sync CreateWindow(nullable PBrowser aThisTab,
PBrowser aNewTab,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsString aURI,
nsString aName,
nsCString aFeatures,
nsString aBaseURI)
returns (nsresult rv,
bool windowOpened,
FrameScriptInfo[] frameScripts,
nsCString urlToLoad);
sync GetDeviceStorageLocation(nsString type)
returns (nsString path);

View File

@ -44,22 +44,25 @@ struct FrameIPCTabContext
nsCString signedPkgOriginNoSuffix;
};
// XXXcatalinb: This is only used by ServiceWorkerClients::OpenWindow.
// Because service workers don't have an associated TabChild
// we can't satisfy the security constraints on b2g. As such, the parent
// process will accept this tab context only on desktop.
struct UnsafeIPCTabContext
{ };
// IPCTabContext is an analog to mozilla::dom::TabContext. Both specify an
// iframe/PBrowser's own and containing app-ids and tell you whether the
// iframe/PBrowser is a browser frame. But only IPCTabContext is allowed to
// travel over IPC.
//
// We need IPCTabContext (specifically, PopupIPCTabContext) to prevent a
// privilege escalation attack by a compromised child process. See the comment
// on AllocPBrowser for details.
union IPCTabContextUnion
// privilege escalation attack by a compromised child process.
union IPCTabContext
{
PopupIPCTabContext;
FrameIPCTabContext;
};
struct IPCTabContext {
IPCTabContextUnion contextUnion;
UnsafeIPCTabContext;
};
}

View File

@ -617,6 +617,7 @@ TabChild::TabChild(nsIContentChild* aManager,
, mDefaultScale(0)
, mIPCOpen(true)
, mParentIsActive(false)
, mDidSetRealShowInfo(false)
{
// In the general case having the TabParent tell us if APZ is enabled or not
// doesn't really work because the TabParent itself may not have a reference
@ -1115,145 +1116,19 @@ TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags,
// Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
// open window call was canceled. It's important that we pass this error
// code back to our caller.
return ProvideWindowCommon(aParent,
iframeMoz,
aChromeFlags,
aCalledFromJS,
aPositionSpecified,
aSizeSpecified,
aURI,
aName,
aFeatures,
aWindowIsNew,
aReturn);
}
nsresult
TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn)
{
*aReturn = nullptr;
ContentChild* cc = ContentChild::GetSingleton();
const TabId openerTabId = GetTabId();
// We must use PopupIPCTabContext here; ContentParent will not accept the
// result of this->AsIPCTabContext() (which will be a
// BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
// reasons.
PopupIPCTabContext context;
context.opener() = openerTabId;
context.isBrowserElement() = IsBrowserElement();
IPCTabContext ipcContext(context);
TabId tabId;
cc->SendAllocateTabId(openerTabId,
ipcContext,
cc->GetID(),
&tabId);
RefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
/* TabContext */ *this, aChromeFlags);
if (NS_FAILED(newChild->Init())) {
return NS_ERROR_ABORT;
}
context.opener() = this;
unused << Manager()->SendPBrowserConstructor(
// We release this ref in DeallocPBrowserChild
RefPtr<TabChild>(newChild).forget().take(),
tabId, IPCTabContext(context), aChromeFlags,
cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
nsAutoCString spec;
if (aURI) {
aURI->GetSpec(spec);
}
NS_ConvertUTF8toUTF16 url(spec);
nsString name(aName);
nsAutoCString features(aFeatures);
nsTArray<FrameScriptInfo> frameScripts;
nsCString urlToLoad;
if (aIframeMoz) {
newChild->SendBrowserFrameOpenWindow(this, url, name,
NS_ConvertUTF8toUTF16(features),
aWindowIsNew);
} else {
nsCOMPtr<nsPIDOMWindow> opener = do_QueryInterface(aOpener);
nsCOMPtr<nsIDocument> doc = opener->GetDoc();
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
if (!baseURI) {
NS_ERROR("nsIDocument didn't return a base URI");
return NS_ERROR_FAILURE;
}
nsAutoCString baseURIString;
baseURI->GetSpec(baseURIString);
nsresult rv;
if (!SendCreateWindow(newChild,
aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, url,
name, features,
NS_ConvertUTF8toUTF16(baseURIString),
&rv,
aWindowIsNew,
&frameScripts,
&urlToLoad)) {
return NS_ERROR_NOT_AVAILABLE;
}
if (NS_FAILED(rv)) {
return rv;
}
}
if (!*aWindowIsNew) {
PBrowserChild::Send__delete__(newChild);
return NS_ERROR_ABORT;
}
TextureFactoryIdentifier textureFactoryIdentifier;
uint64_t layersId = 0;
PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
newChild->SendGetRenderFrameInfo(renderFrame,
&textureFactoryIdentifier,
&layersId);
if (layersId == 0) { // if renderFrame is invalid.
PRenderFrameChild::Send__delete__(renderFrame);
renderFrame = nullptr;
}
// Unfortunately we don't get a window unless we've shown the frame. That's
// pretty bogus; see bug 763602.
newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame);
for (size_t i = 0; i < frameScripts.Length(); i++) {
FrameScriptInfo& info = frameScripts[i];
if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
MOZ_CRASH();
}
}
if (!urlToLoad.IsEmpty()) {
newChild->RecvLoadURL(urlToLoad, BrowserConfiguration());
}
nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
win.forget(aReturn);
return NS_OK;
ContentChild* cc = ContentChild::GetSingleton();
return cc->ProvideWindowCommon(this,
aParent,
iframeMoz,
aChromeFlags,
aCalledFromJS,
aPositionSpecified,
aSizeSpecified,
aURI,
aName,
aFeatures,
aWindowIsNew,
aReturn);
}
void
@ -1383,12 +1258,15 @@ TabChild::IsRootContentDocument()
bool
TabChild::RecvLoadURL(const nsCString& aURI,
const BrowserConfiguration& aConfiguration)
const BrowserConfiguration& aConfiguration,
const ShowInfo& aInfo)
{
if (!InitTabChildGlobal()) {
return false;
}
ApplyShowInfo(aInfo);
SetProcessNameToAppName();
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
@ -1560,10 +1438,9 @@ TabChild::CancelCachedFileDescriptorCallback(
void
TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
PRenderFrameChild* aRenderFrame)
PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo)
{
ShowInfo info(EmptyString(), false, false, 0, 0);
RecvShow(ScreenIntSize(0, 0), info, aTextureFactoryIdentifier,
RecvShow(ScreenIntSize(0, 0), aShowInfo, aTextureFactoryIdentifier,
aLayersId, aRenderFrame, mParentIsActive);
mDidFakeShow = true;
}
@ -1571,6 +1448,16 @@ TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
void
TabChild::ApplyShowInfo(const ShowInfo& aInfo)
{
if (mDidSetRealShowInfo) {
return;
}
if (!aInfo.fakeShowInfo()) {
// Once we've got one ShowInfo from parent, no need to update the values
// anymore.
mDidSetRealShowInfo = true;
}
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (docShell) {
nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
@ -1584,17 +1471,20 @@ TabChild::ApplyShowInfo(const ShowInfo& aInfo)
}
docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
if (aInfo.isPrivate()) {
bool nonBlank;
docShell->GetHasLoadedNonBlankURI(&nonBlank);
if (nonBlank) {
nsContentUtils::ReportToConsoleNonLocalized(
NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("mozprivatebrowsing"),
nullptr);
} else {
nsCOMPtr<nsILoadContext> context = do_GetInterface(docShell);
context->SetUsePrivateBrowsing(true);
nsCOMPtr<nsILoadContext> context = do_GetInterface(docShell);
// No need to re-set private browsing mode.
if (!context->UsePrivateBrowsing()) {
bool nonBlank;
docShell->GetHasLoadedNonBlankURI(&nonBlank);
if (nonBlank) {
nsContentUtils::ReportToConsoleNonLocalized(
NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("mozprivatebrowsing"),
nullptr);
} else {
context->SetUsePrivateBrowsing(true);
}
}
}
}

View File

@ -240,6 +240,16 @@ public:
static already_AddRefed<TabChild> FindTabChild(const TabId& aTabId);
public:
/**
* Create a new TabChild object.
*/
TabChild(nsIContentChild* aManager,
const TabId& aTabId,
const TabContext& aContext,
uint32_t aChromeFlags);
nsresult Init();
/**
* This is expected to be called off the critical path to content
* startup. This is an opportunity to load things that are slow
@ -289,7 +299,8 @@ public:
const ViewID& aViewId,
const Maybe<ZoomConstraints>& aConstraints) override;
virtual bool RecvLoadURL(const nsCString& aURI,
const BrowserConfiguration& aConfiguration) override;
const BrowserConfiguration& aConfiguration,
const ShowInfo& aInfo) override;
virtual bool RecvCacheFileDescriptor(const nsString& aPath,
const FileDescriptor& aFileDescriptor)
override;
@ -510,6 +521,12 @@ public:
virtual ScreenIntSize GetInnerSize() override;
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
PRenderFrameChild* aRenderFrame,
const ShowInfo& aShowInfo);
protected:
virtual ~TabChild();
@ -535,16 +552,6 @@ protected:
#endif
private:
/**
* Create a new TabChild object.
*/
TabChild(nsIContentChild* aManager,
const TabId& aTabId,
const TabContext& aContext,
uint32_t aChromeFlags);
nsresult Init();
class DelayedFireContextMenuEvent;
// Notify others that our TabContext has been updated. (At the moment, this
@ -564,11 +571,6 @@ private:
void DestroyWindow();
void SetProcessNameToAppName();
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
PRenderFrameChild* aRenderFrame);
void ApplyShowInfo(const ShowInfo& aInfo);
// These methods are used for tracking synthetic mouse events
@ -581,19 +583,6 @@ private:
void CancelTapTracking();
void UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus);
nsresult
ProvideWindowCommon(nsIDOMWindow* aOpener,
bool aIframeMoz,
uint32_t aChromeFlags,
bool aCalledFromJS,
bool aPositionSpecified,
bool aSizeSpecified,
nsIURI* aURI,
const nsAString& aName,
const nsACString& aFeatures,
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
bool HasValidInnerSize();
void SetTabId(const TabId& aTabId);
@ -647,12 +636,16 @@ private:
// Position of tab, relative to parent widget (typically the window)
LayoutDeviceIntPoint mChromeDisp;
TabId mUniqueId;
friend class ContentChild;
float mDPI;
double mDefaultScale;
bool mIPCOpen;
bool mParentIsActive;
bool mAsyncPanZoomEnabled;
CSSSize mUnscaledInnerSize;
bool mDidSetRealShowInfo;
nsAutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;

View File

@ -232,10 +232,9 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
nsAutoCString originSuffix;
nsAutoCString signedPkgOriginNoSuffix;
const IPCTabContextUnion& contextUnion = aParams.contextUnion();
switch(contextUnion.type()) {
case IPCTabContextUnion::TPopupIPCTabContext: {
const PopupIPCTabContext &ipcContext = contextUnion.get_PopupIPCTabContext();
switch(aParams.type()) {
case IPCTabContext::TPopupIPCTabContext: {
const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
TabContext *context;
if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
@ -281,9 +280,9 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
}
break;
}
case IPCTabContextUnion::TFrameIPCTabContext: {
case IPCTabContext::TFrameIPCTabContext: {
const FrameIPCTabContext &ipcContext =
contextUnion.get_FrameIPCTabContext();
aParams.get_FrameIPCTabContext();
containingAppId = ipcContext.frameOwnerAppId();
signedPkgOriginNoSuffix = ipcContext.signedPkgOriginNoSuffix();
@ -291,6 +290,23 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
originAttributes.PopulateFromSuffix(originSuffix);
break;
}
case IPCTabContext::TUnsafeIPCTabContext: {
// XXXcatalinb: This used *only* by ServiceWorkerClients::OpenWindow.
// It is meant as a temporary solution until service workers can
// provide a TabChild equivalent. Don't allow this on b2g since
// it might be used to escalate privileges.
#ifdef MOZ_B2G
mInvalidReason = "ServiceWorkerClients::OpenWindow is not supported.";
return;
#endif
if (!Preferences::GetBool("dom.serviceWorkers.enabled", false)) {
mInvalidReason = "ServiceWorkers should be enabled.";
return;
}
containingAppId = NO_APP_ID;
break;
}
default: {
MOZ_CRASH();
}

View File

@ -50,7 +50,6 @@
#include "nsIContent.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDOMChromeWindow.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMWindow.h"
@ -61,26 +60,20 @@
#include "nsIPromptFactory.h"
#include "nsIURI.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWindowCreator2.h"
#include "nsIXULBrowserWindow.h"
#include "nsIXULWindow.h"
#include "nsIRemoteBrowser.h"
#include "nsViewManager.h"
#include "nsVariant.h"
#include "nsIWidget.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#ifndef XP_WIN
#include "nsJARProtocolHandler.h"
#endif
#include "nsOpenURIInFrameParams.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowWatcher.h"
#include "nsPresShell.h"
#include "nsPrintfCString.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsWindowWatcher.h"
#include "private/pprio.h"
#include "PermissionMessageUtils.h"
#include "StructuredCloneData.h"
@ -723,249 +716,6 @@ TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
return true;
}
struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
{
public:
AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew, nsCString* aURLToLoad)
: mNewTab(aNewTab), mWindowIsNew(aWindowIsNew), mURLToLoad(aURLToLoad)
{
MOZ_ASSERT(!TabParent::sNextTabParent);
MOZ_ASSERT(!aNewTab->mCreatingWindow);
TabParent::sNextTabParent = aNewTab;
aNewTab->mCreatingWindow = true;
aNewTab->mDelayedURL.Truncate();
}
~AutoUseNewTab()
{
mNewTab->mCreatingWindow = false;
*mURLToLoad = mNewTab->mDelayedURL;
if (TabParent::sNextTabParent) {
MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
TabParent::sNextTabParent = nullptr;
*mWindowIsNew = false;
}
}
private:
TabParent* mNewTab;
bool* mWindowIsNew;
nsCString* mURLToLoad;
};
static already_AddRefed<nsPIDOMWindow>
FindMostRecentOpenWindow()
{
nsCOMPtr<nsIWindowMediator> windowMediator =
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
windowMediator->GetEnumerator(MOZ_UTF16("navigator:browser"),
getter_AddRefs(windowEnumerator));
nsCOMPtr<nsPIDOMWindow> latest;
bool hasMore = false;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
while (hasMore) {
nsCOMPtr<nsISupports> item;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->GetNext(getter_AddRefs(item))));
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(item);
if (window && !window->Closed()) {
latest = window;
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
}
return latest.forget();
}
bool
TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsCString& aFeatures,
const nsString& aBaseURI,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad)
{
// We always expect to open a new window here. If we don't, it's an error.
*aWindowIsNew = true;
// The content process should never be in charge of computing whether or
// not a window should be private or remote - the parent will do that.
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME));
MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
if (NS_WARN_IF(IsBrowserOrApp()))
return false;
nsCOMPtr<nsPIWindowWatcher> pwwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
if (NS_WARN_IF(NS_FAILED(*aResult)))
return true;
TabParent* newTab = TabParent::GetFrom(aNewTab);
MOZ_ASSERT(newTab);
// Content has requested that we open this new content window, so
// we must have an opener.
newTab->SetHasContentOpener(true);
nsCOMPtr<nsIContent> frame(do_QueryInterface(mFrameElement));
nsCOMPtr<nsPIDOMWindow> parent;
if (frame) {
parent = frame->OwnerDoc()->GetWindow();
// If our chrome window is in the process of closing, don't try to open a
// new tab in it.
if (parent && parent->Closed()) {
parent = nullptr;
}
}
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin = mBrowserDOMWindow;
// If we haven't found a chrome window to open in, just use the most recently
// opened one.
if (!parent) {
parent = FindMostRecentOpenWindow();
if (NS_WARN_IF(!parent)) {
*aResult = NS_ERROR_FAILURE;
return true;
}
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(parent);
if (rootChromeWin) {
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
}
}
int32_t openLocation =
nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
aPositionSpecified, aSizeSpecified);
MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
// Opening new tabs is the easy case...
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
if (NS_WARN_IF(!browserDOMWin)) {
*aResult = NS_ERROR_FAILURE;
return true;
}
bool isPrivate;
nsCOMPtr<nsILoadContext> loadContext = GetLoadContext();
loadContext->GetUsePrivateBrowsing(&isPrivate);
nsCOMPtr<nsIOpenURIInFrameParams> params = new nsOpenURIInFrameParams();
params->SetReferrer(aBaseURI);
params->SetIsPrivate(isPrivate);
AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
browserDOMWin->OpenURIInFrame(nullptr, params,
openLocation,
nsIBrowserDOMWindow::OPEN_NEW,
getter_AddRefs(frameLoaderOwner));
if (!frameLoaderOwner) {
*aWindowIsNew = false;
}
aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
return true;
}
// WindowWatcher is going to expect a valid URI to open a window
// to. If it can't find one, it's going to attempt to figure one
// out on its own, which is problematic because it can't access
// the document for the remote browser we're opening. Luckily,
// TabChild has sent us a baseURI with which we can ensure that
// the URI we pass to WindowWatcher is valid.
nsCOMPtr<nsIURI> baseURI;
*aResult = NS_NewURI(getter_AddRefs(baseURI), aBaseURI);
if (NS_WARN_IF(NS_FAILED(*aResult)))
return true;
nsAutoCString finalURIString;
if (!aURI.IsEmpty()) {
nsCOMPtr<nsIURI> finalURI;
*aResult = NS_NewURI(getter_AddRefs(finalURI), NS_ConvertUTF16toUTF8(aURI).get(), baseURI);
if (NS_WARN_IF(NS_FAILED(*aResult)))
return true;
finalURI->GetSpec(finalURIString);
}
nsCOMPtr<nsIDOMWindow> window;
AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
const char* features = aFeatures.Length() ? aFeatures.get() : nullptr;
*aResult = pwwatch->OpenWindow2(parent, finalURIString.get(),
NS_ConvertUTF16toUTF8(aName).get(),
features, aCalledFromJS,
false, false, this, nullptr, getter_AddRefs(window));
if (NS_WARN_IF(NS_FAILED(*aResult)))
return true;
*aResult = NS_ERROR_FAILURE;
nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
if (NS_WARN_IF(!pwindow)) {
return true;
}
nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
if (NS_WARN_IF(!windowDocShell)) {
return true;
}
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
if (NS_WARN_IF(!xulWin)) {
return true;
}
nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
if (NS_WARN_IF(!xulBrowserWin)) {
return true;
}
nsCOMPtr<nsITabParent> newRemoteTab;
*aResult = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
if (NS_WARN_IF(NS_FAILED(*aResult)))
return true;
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
return true;
}
TabParent* TabParent::sNextTabParent;
/* static */ TabParent*
@ -1029,7 +779,7 @@ TabParent::LoadURL(nsIURI* aURI)
return;
}
unused << SendLoadURL(spec, configuration);
unused << SendLoadURL(spec, configuration, GetShowInfo());
// If this app is a packaged app then we can speed startup by sending over
// the file descriptor for the "application.zip" file that it will
@ -1117,20 +867,7 @@ TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
}
}
TryCacheDPIAndScale();
ShowInfo info(EmptyString(), false, false, mDPI, mDefaultScale.scale);
if (mFrameElement) {
nsAutoString name;
mFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
bool allowFullscreen =
mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen);
bool isPrivate = mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
info = ShowInfo(name, allowFullscreen, isPrivate, mDPI, mDefaultScale.scale);
}
unused << SendShow(size, info, textureFactoryIdentifier,
unused << SendShow(size, GetShowInfo(), textureFactoryIdentifier,
layersId, renderFrame, aParentIsActive);
}
@ -3631,6 +3368,25 @@ TabParent::StartPersistence(uint64_t aOuterWindowID,
// (The actor will be destroyed on constructor failure.)
}
ShowInfo
TabParent::GetShowInfo()
{
TryCacheDPIAndScale();
if (mFrameElement) {
nsAutoString name;
mFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
bool allowFullscreen =
mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen);
bool isPrivate = mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
return ShowInfo(name, allowFullscreen, isPrivate, false,
mDPI, mDefaultScale.scale);
}
return ShowInfo(EmptyString(), false, false, false,
mDPI, mDefaultScale.scale);
}
NS_IMETHODIMP
FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
{

View File

@ -11,6 +11,7 @@
#include "mozilla/ContentCache.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/PFilePickerParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/EventForwards.h"
@ -93,6 +94,9 @@ class TabParent final : public PBrowserParent
virtual ~TabParent();
public:
// Helper class for ContentParent::RecvCreateWindow.
struct AutoUseNewTab;
// nsITabParent
NS_DECL_NSITABPARENT
// nsIDOMEventListener interfaces
@ -125,6 +129,12 @@ public:
mBrowserDOMWindow = aBrowserDOMWindow;
}
void SetHasContentOpener(bool aHasContentOpener);
void SwapFrameScriptsFrom(nsTArray<FrameScriptInfo>& aFrameScripts) {
aFrameScripts.SwapElements(mDelayedFrameScripts);
}
already_AddRefed<nsILoadContext> GetLoadContext();
already_AddRefed<nsIWidget> GetTopLevelWidget();
nsIXULBrowserWindow* GetXULBrowserWindow();
@ -147,19 +157,6 @@ public:
const nsString& aName,
const nsString& aFeatures,
bool* aOutWindowOpened) override;
virtual bool RecvCreateWindow(PBrowserParent* aOpener,
const uint32_t& aChromeFlags,
const bool& aCalledFromJS,
const bool& aPositionSpecified,
const bool& aSizeSpecified,
const nsString& aURI,
const nsString& aName,
const nsCString& aFeatures,
const nsString& aBaseURI,
nsresult* aResult,
bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad) override;
virtual bool RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows,
@ -497,8 +494,6 @@ protected:
bool InitBrowserConfiguration(const nsCString& aURI,
BrowserConfiguration& aConfiguration);
void SetHasContentOpener(bool aHasContentOpener);
// Decide whether we have to use a new process to reload the URI associated
// with the given channel.
bool ShouldSwitchProcess(nsIChannel* aChannel);
@ -584,9 +579,6 @@ private:
TabId mTabId;
// Helper class for RecvCreateWindow.
struct AutoUseNewTab;
// When loading a new tab or window via window.open, the child process sends
// a new PBrowser to use. We store that tab in sNextTabParent and then
// proceed through the browser's normal paths to create a new
@ -642,6 +634,8 @@ private:
bool mHasContentOpener;
DebugOnly<int32_t> mActiveSupressDisplayportCount;
ShowInfo GetShowInfo();
private:
// This is used when APZ needs to find the TabParent associated with a layer
// to dispatch events.
@ -655,6 +649,38 @@ public:
static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
};
struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
{
public:
AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew, nsCString* aURLToLoad)
: mNewTab(aNewTab), mWindowIsNew(aWindowIsNew), mURLToLoad(aURLToLoad)
{
MOZ_ASSERT(!TabParent::sNextTabParent);
MOZ_ASSERT(!aNewTab->mCreatingWindow);
TabParent::sNextTabParent = aNewTab;
aNewTab->mCreatingWindow = true;
aNewTab->mDelayedURL.Truncate();
}
~AutoUseNewTab()
{
mNewTab->mCreatingWindow = false;
*mURLToLoad = mNewTab->mDelayedURL;
if (TabParent::sNextTabParent) {
MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
TabParent::sNextTabParent = nullptr;
*mWindowIsNew = false;
}
}
private:
TabParent* mNewTab;
bool* mWindowIsNew;
nsCString* mURLToLoad;
};
} // namespace dom
} // namespace mozilla

View File

@ -71,35 +71,36 @@ nsIContentParent::DeallocPJavaScriptParent(PJavaScriptParent* aParent)
bool
nsIContentParent::CanOpenBrowser(const IPCTabContext& aContext)
{
const IPCTabContextUnion& contextUnion = aContext.contextUnion();
// We don't trust the IPCTabContext we receive from the child, so we'll bail
// if we receive an IPCTabContext that's not a PopupIPCTabContext.
// (PopupIPCTabContext lets the child process prove that it has access to
// the app it's trying to open.)
if (contextUnion.type() != IPCTabContextUnion::TPopupIPCTabContext) {
// On e10s we also allow UnsafeTabContext to allow service workers to open
// windows. This is enforced in MaybeInvalidTabContext.
if (aContext.type() != IPCTabContext::TPopupIPCTabContext &&
aContext.type() != IPCTabContext::TUnsafeIPCTabContext) {
ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type. Aborting AllocPBrowserParent.");
return false;
}
const PopupIPCTabContext& popupContext = contextUnion.get_PopupIPCTabContext();
if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type. Aborting AllocPBrowserParent.");
return false;
}
if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type. Aborting AllocPBrowserParent.");
return false;
}
auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
if (!opener) {
ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
return false;
}
auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
if (!opener) {
ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
return false;
}
// Popup windows of isBrowser frames must be isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID would allow
// the content to access data it's not supposed to.
if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent.");
return false;
// Popup windows of isBrowser frames must be isBrowser if the parent
// isBrowser. Allocating a !isBrowser frame with same app ID would allow
// the content to access data it's not supposed to.
if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent.");
return false;
}
}
MaybeInvalidTabContext tc(aContext);
@ -129,26 +130,25 @@ nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
return nullptr;
}
const IPCTabContextUnion& contextUnion = aContext.contextUnion();
const PopupIPCTabContext& popupContext = contextUnion.get_PopupIPCTabContext();
uint32_t chromeFlags = aChromeFlags;
if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
// CanOpenBrowser has ensured that the IPCTabContext is of
// type PopupIPCTabContext, and that the opener TabParent is
// reachable.
const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext();
auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
// We must ensure that the private browsing and remoteness flags
// match those of the opener.
nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
if (!loadContext) {
return nullptr;
}
// CanOpenBrowser has ensured that the IPCTabContext is of
// type PopupIPCTabContext, and that the opener TabParent is
// reachable.
auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
// We must ensure that the private browsing and remoteness flags
// match those of the opener.
nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
if (!loadContext) {
return nullptr;
}
bool isPrivate;
loadContext->GetUsePrivateBrowsing(&isPrivate);
if (isPrivate) {
chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
bool isPrivate;
loadContext->GetUsePrivateBrowsing(&isPrivate);
if (isPrivate) {
chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
}
}
// And because we're allocating a remote browser, of course the

View File

@ -168,23 +168,21 @@ PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener,
AppCacheWarning=The Application Cache API (AppCache) is deprecated and will be removed at a future date. Please consider using ServiceWorker for offline support.
# LOCALIZATION NOTE: Do not translate "Worker".
EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
InterceptionFailed=ServiceWorker network interception failed due to an unexpected error.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "opaque", or "Response".
OpaqueInterceptionDisabled=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while opaque interception is disabled.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "FetchEvent.request.type", "same-origin", "cors", "no-cors", "opaque", "Response", or "RequestMode".
BadOpaqueInterceptionRequestMode=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while the FetchEvent.request.type was either "same-origin" or "cors". Opaque Response objects are only valid when the RequestMode is "no-cors".
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()".
InterceptedErrorResponse=A ServiceWorker passed an Error Response to FetchEvent.respondWith(). This typically means the ServiceWorker performed an invalid fetch() call.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()".
InterceptedUsedResponse=A ServiceWorker passed a used Response to FetchEvent.respondWith(). The body of a Response may only be read once. Use Response.clone() to access the body multiple times.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "opaque", "Response", "FetchEvent.respondWith()", "FetchEvent.request", or "Worker".
ClientRequestOpaqueInterception=A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while FetchEvent.request was a client request. A client request is generally a browser navigation or top-level Worker script.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "opaqueredirect", "Response", "FetchEvent.respondWith()", or "FetchEvent.request".
BadOpaqueRedirectInterception=A ServiceWorker passed an opaqueredirect Response to FetchEvent.respondWith() while FetchEvent.request was not a navigation request.
# LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()".
InterceptionCanceled=ServiceWorker canceled network interception by calling FetchEvent.preventDefault().
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Promise", or "FetchEvent.respondWith()".
InterceptionRejectedResponse=ServiceWorker passed a rejected Promise to FetchEvent.respondWith(). This typically means that the code that resolves the Promise has failed.
WebrtcDeprecatedPrefixWarning=WebRTC interfaces with the "moz" prefix (mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate) have been deprecated.
NavigatorGetUserMediaWarning=navigator.mozGetUserMedia has been replaced by navigator.mediaDevices.getUserMedia
# LOCALIZATION NOTE: Do not translate "ServiceWorker". %S is a URL.
InterceptionFailedWithURL=Failed to load '%S'. A ServiceWorker intercepted the request and encountered an unexpected error.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "opaque", or "Response". %S is a URL.
OpaqueInterceptionDisabledWithURL=Failed to load '%S'. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while opaque interception is disabled.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "FetchEvent", "no-cors", "opaque", "Response", or "RequestMode". %1$S is a URL. %2$S is a RequestMode value.
BadOpaqueInterceptionRequestModeWithURL=Failed to load '%1$S'. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while handling a '%2$S' FetchEvent. Opaque Response objects are only valid when the RequestMode is 'no-cors'.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()". %S is a URL.
InterceptedErrorResponseWithURL=Failed to load '%S'. A ServiceWorker passed an Error Response to FetchEvent.respondWith(). This typically means the ServiceWorker performed an invalid fetch() call.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()". %S is a URL.
InterceptedUsedResponseWithURL=Failed to load '%S'. A ServiceWorker passed a used Response to FetchEvent.respondWith(). The body of a Response may only be read once. Use Response.clone() to access the body multiple times.
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "opaqueredirect", "Response", "FetchEvent.respondWith()", or "FetchEvent". %s is a URL.
BadOpaqueRedirectInterceptionWithURL=Failed to load '%S'. A ServiceWorker passed an opaqueredirect Response to FetchEvent.respondWith() while handling a non-navigation FetchEvent.
# LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()". %S is a URL.
InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the load by calling FetchEvent.preventDefault().
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", or "FetchEvent.respondWith()". %1$S is a URL. %2$S is an error string.
InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.

View File

@ -259,6 +259,7 @@ MediaDecoderReader::AsyncReadMetadata()
// Attempt to read the metadata.
RefPtr<MetadataHolder> metadata = new MetadataHolder();
nsresult rv = ReadMetadata(&metadata->mInfo, getter_Transfers(metadata->mTags));
metadata->mInfo.AssertValid();
// We're not waiting for anything. If we didn't get the metadata, that's an
// error.

View File

@ -343,6 +343,12 @@ public:
mToken = nullptr;
}
void DisconnectIfExists() {
if (mToken) {
Disconnect();
}
}
private:
// Avoid exposing RevocableToken directly to the client code so that
// listeners can be disconnected in a controlled manner.

View File

@ -37,7 +37,7 @@ public:
const nsAString& aLabel,
const nsAString& aLanguage,
bool aEnabled,
TrackID aTrackId = TRACK_INVALID)
TrackID aTrackId)
: mId(aId)
, mKind(aKind)
, mLabel(aLabel)
@ -53,21 +53,17 @@ public:
}
// Only used for backward compatibility. Do not use in new code.
void Init(TrackType aType,
const nsAString& aId,
void Init(const nsAString& aId,
const nsAString& aKind,
const nsAString& aLabel,
const nsAString& aLanguage,
bool aEnabled,
TrackID aTrackId = TRACK_INVALID)
bool aEnabled)
{
mId = aId;
mKind = aKind;
mLabel = aLabel;
mLanguage = aLanguage;
mEnabled = aEnabled;
mTrackId = aTrackId;
mType = aType;
}
// Fields common with MediaTrack object.
@ -381,6 +377,17 @@ public:
return HasVideo() || HasAudio();
}
void AssertValid() const
{
NS_ASSERTION(!HasAudio() || mAudio.mTrackId != TRACK_INVALID,
"Audio track ID must be valid");
NS_ASSERTION(!HasVideo() || mVideo.mTrackId != TRACK_INVALID,
"Audio track ID must be valid");
NS_ASSERTION(!HasAudio() || !HasVideo() ||
mAudio.mTrackId != mVideo.mTrackId,
"Duplicate track IDs");
}
// TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
VideoInfo mVideo;
AudioInfo mAudio;

View File

@ -553,7 +553,7 @@ private:
}
}
bool Check3gppPermission()
bool CheckPermission(const char* aType)
{
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
if (!doc) {
@ -576,7 +576,7 @@ private:
}
uint32_t perm = nsIPermissionManager::DENY_ACTION;
pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), "audio-capture:3gpp", &perm);
pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), aType, &perm);
return perm == nsIPermissionManager::ALLOW_ACTION;
}
@ -593,12 +593,18 @@ private:
// At this stage, the API doesn't allow UA to choose the output mimeType format.
// Make sure the application has permission to assign AUDIO_3GPP
if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && Check3gppPermission()) {
if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && CheckPermission("audio-capture:3gpp")) {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes);
} else if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP2) && CheckPermission("audio-capture:3gpp2")) {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP2),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes);
} else {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
mRecorder->GetAudioBitrate(),

View File

@ -156,7 +156,7 @@ private:
void RegisterActivityObserver();
void UnRegisterActivityObserver();
bool Check3gppPermission();
bool CheckPermission(const nsString &aType);
};
} // namespace dom

View File

@ -580,10 +580,13 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream)
return;
}
if (!aStream->GetStreamBuffer().GetAndResetTracksDirty()) {
if (!aStream->GetStreamBuffer().GetAndResetTracksDirty() &&
!aStream->mAudioOutputStreams.IsEmpty()) {
return;
}
STREAM_LOG(LogLevel::Debug, ("Updating AudioOutputStreams for MediaStream %p", aStream));
nsAutoTArray<bool,2> audioOutputStreamsFound;
for (uint32_t i = 0; i < aStream->mAudioOutputStreams.Length(); ++i) {
audioOutputStreamsFound.AppendElement(false);
@ -1804,9 +1807,19 @@ MediaStream::SetAudioOutputVolume(void* aKey, float aVolume)
GraphImpl()->AppendMessage(new Message(this, aKey, aVolume));
}
void
MediaStream::AddAudioOutputImpl(void* aKey)
{
STREAM_LOG(LogLevel::Info, ("MediaStream %p Adding AudioOutput for key %p",
this, aKey));
mAudioOutputs.AppendElement(AudioOutput(aKey));
}
void
MediaStream::RemoveAudioOutputImpl(void* aKey)
{
STREAM_LOG(LogLevel::Info, ("MediaStream %p Removing AudioOutput for key %p",
this, aKey));
for (uint32_t i = 0; i < mAudioOutputs.Length(); ++i) {
if (mAudioOutputs[i].mKey == aKey) {
mAudioOutputs.RemoveElementAt(i);
@ -1832,6 +1845,26 @@ MediaStream::RemoveAudioOutput(void* aKey)
GraphImpl()->AppendMessage(new Message(this, aKey));
}
void
MediaStream::AddVideoOutputImpl(already_AddRefed<VideoFrameContainer> aContainer)
{
RefPtr<VideoFrameContainer> container = aContainer;
STREAM_LOG(LogLevel::Info, ("MediaStream %p Adding VideoFrameContainer %p as output",
this, container.get()));
*mVideoOutputs.AppendElement() = container.forget();
}
void
MediaStream::RemoveVideoOutputImpl(VideoFrameContainer* aContainer)
{
STREAM_LOG(LogLevel::Info, ("MediaStream %p Removing VideoFrameContainer %p as output",
this, aContainer));
// Ensure that any frames currently queued for playback by the compositor
// are removed.
aContainer->ClearFutureFrames();
mVideoOutputs.RemoveElement(aContainer);
}
void
MediaStream::AddVideoOutput(VideoFrameContainer* aContainer)
{

View File

@ -440,27 +440,15 @@ public:
void DumpTrackInfo() { return mBuffer.DumpTrackInfo(); }
#endif
void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
void AddAudioOutputImpl(void* aKey)
{
mAudioOutputs.AppendElement(AudioOutput(aKey));
}
void AddAudioOutputImpl(void* aKey);
// Returns true if this stream has an audio output.
bool HasAudioOutput()
{
return !mAudioOutputs.IsEmpty();
}
void RemoveAudioOutputImpl(void* aKey);
void AddVideoOutputImpl(already_AddRefed<VideoFrameContainer> aContainer)
{
*mVideoOutputs.AppendElement() = aContainer;
}
void RemoveVideoOutputImpl(VideoFrameContainer* aContainer)
{
// Ensure that any frames currently queued for playback by the compositor
// are removed.
aContainer->ClearFutureFrames();
mVideoOutputs.RemoveElement(aContainer);
}
void AddVideoOutputImpl(already_AddRefed<VideoFrameContainer> aContainer);
void RemoveVideoOutputImpl(VideoFrameContainer* aContainer);
void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
void RemoveListenerImpl(MediaStreamListener* aListener);
void RemoveAllListenersImpl();

View File

@ -60,6 +60,8 @@ public:
AAC_CSD, // AAC codec specific data
AMR_AUDIO_CSD,
AMR_AUDIO_FRAME,
EVRC_AUDIO_CSD,
EVRC_AUDIO_FRAME,
UNKNOWN // FrameType not set
};
void SwapInFrameData(nsTArray<uint8_t>& aData)

View File

@ -130,6 +130,14 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint32_t aAudioBitrate,
writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3GP);
NS_ENSURE_TRUE(writer, nullptr);
mimeType = NS_LITERAL_STRING(AUDIO_3GPP);
} else if (MediaEncoder::IsOMXEncoderEnabled() &&
(aMIMEType.EqualsLiteral(AUDIO_3GPP2))) {
audioEncoder = new OmxEVRCAudioTrackEncoder();
NS_ENSURE_TRUE(audioEncoder, nullptr);
writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3G2);
NS_ENSURE_TRUE(writer, nullptr);
mimeType = NS_LITERAL_STRING(AUDIO_3GPP2) ;
}
#endif // MOZ_OMX_ENCODER
else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() &&

View File

@ -184,7 +184,7 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
3000); // wait up to 3ms
NS_ENSURE_SUCCESS(rv, rv);
if (!frameData.IsEmpty()) {
if (!frameData.IsEmpty() || outFlags & OMXCodecWrapper::BUFFER_EOS) { // Some hw codec may send out EOS with an empty frame
bool isCSD = false;
if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { // codec specific data
isCSD = true;
@ -199,6 +199,9 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
} else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){
audiodata->SetFrameType(isCSD ?
EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME);
} else if (mEncoder->GetCodecType() == OMXCodecWrapper::EVRC_ENC){
audiodata->SetFrameType(isCSD ?
EncodedFrame::EVRC_AUDIO_CSD : EncodedFrame::EVRC_AUDIO_FRAME);
} else {
MOZ_ASSERT(false, "audio codec not supported");
}
@ -343,4 +346,44 @@ OmxAMRAudioTrackEncoder::GetMetadata()
return meta.forget();
}
nsresult
OmxEVRCAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
{
mChannels = aChannels;
mSamplingRate = aSamplingRate;
mEncoder = OMXCodecWrapper::CreateEVRCEncoder();
NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, EVRC_SAMPLERATE);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mInitialized = (rv == NS_OK);
mReentrantMonitor.NotifyAll();
return NS_OK;
}
already_AddRefed<TrackMetadataBase>
OmxEVRCAudioTrackEncoder::GetMetadata()
{
PROFILER_LABEL("OmxEVRCAudioTrackEncoder", "GetMetadata",
js::ProfileEntry::Category::OTHER);
{
// Wait if mEncoder is not initialized nor is being canceled.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mReentrantMonitor.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
RefPtr<EVRCTrackMetadata> meta = new EVRCTrackMetadata();
meta->mChannels = mChannels;
return meta.forget();
}
}

View File

@ -90,5 +90,21 @@ protected:
nsresult Init(int aChannels, int aSamplingRate) override;
};
class OmxEVRCAudioTrackEncoder final : public OmxAudioTrackEncoder
{
public:
OmxEVRCAudioTrackEncoder()
: OmxAudioTrackEncoder()
{}
enum {
EVRC_SAMPLERATE = 8000,
};
already_AddRefed<TrackMetadataBase> GetMetadata() override;
protected:
nsresult Init(int aChannels, int aSamplingRate) override;
};
}
#endif

View File

@ -22,6 +22,7 @@ public:
METADATA_AVC,
METADATA_AAC,
METADATA_AMR,
METADATA_EVRC,
METADATA_UNKNOWN // Metadata Kind not set
};
// Return the specific metadata kind

View File

@ -0,0 +1,84 @@
/* -*- Mode: C++; 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 "ISOControl.h"
#include "ISOMediaBoxes.h"
#include "EVRCBox.h"
#include "ISOTrackMetadata.h"
namespace mozilla {
nsresult
EVRCSampleEntry::Generate(uint32_t* aBoxSize)
{
uint32_t box_size;
nsresult rv = evrc_special_box->Generate(&box_size);
NS_ENSURE_SUCCESS(rv, rv);
size += box_size;
*aBoxSize = size;
return NS_OK;
}
nsresult
EVRCSampleEntry::Write()
{
BoxSizeChecker checker(mControl, size);
nsresult rv;
rv = AudioSampleEntry::Write();
NS_ENSURE_SUCCESS(rv, rv);
rv = evrc_special_box->Write();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
EVRCSampleEntry::EVRCSampleEntry(ISOControl* aControl)
: AudioSampleEntry(NS_LITERAL_CSTRING("sevc"), aControl)
{
evrc_special_box = new EVRCSpecificBox(aControl);
MOZ_COUNT_CTOR(EVRCSampleEntry);
}
EVRCSampleEntry::~EVRCSampleEntry()
{
MOZ_COUNT_DTOR(EVRCSampleEntry);
}
nsresult
EVRCSpecificBox::Generate(uint32_t* aBoxSize)
{
nsresult rv;
FragmentBuffer* frag = mControl->GetFragment(Audio_Track);
rv = frag->GetCSD(evrcDecSpecInfo);
NS_ENSURE_SUCCESS(rv, rv);
size += evrcDecSpecInfo.Length();
*aBoxSize = size;
return NS_OK;
}
nsresult
EVRCSpecificBox::Write()
{
BoxSizeChecker checker(mControl, size);
Box::Write();
mControl->Write(evrcDecSpecInfo.Elements(), evrcDecSpecInfo.Length());
return NS_OK;
}
EVRCSpecificBox::EVRCSpecificBox(ISOControl* aControl)
: Box(NS_LITERAL_CSTRING("devc"), aControl)
{
MOZ_COUNT_CTOR(EVRCSpecificBox);
}
EVRCSpecificBox::~EVRCSpecificBox()
{
MOZ_COUNT_DTOR(EVRCSpecificBox);
}
}

View File

@ -0,0 +1,50 @@
/* -*- Mode: C++; 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/. */
#ifndef EVRCBOX_h_
#define EVRCBOX_h_
#include "nsTArray.h"
#include "MuxerOperation.h"
namespace mozilla {
class ISOControl;
// 3GPP TS 26.244 6.7 'EVRCSpecificBox field for EVRCSampleEntry box'
// Box type: 'devc'
class EVRCSpecificBox : public Box {
public:
// 3GPP members
nsTArray<uint8_t> evrcDecSpecInfo;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// EVRCSpecificBox methods
EVRCSpecificBox(ISOControl* aControl);
~EVRCSpecificBox();
};
// 3GPP TS 26.244 6.5 'EVRCSampleEntry box'
// Box type: 'sevc'
class EVRCSampleEntry : public AudioSampleEntry {
public:
// 3GPP members
RefPtr<EVRCSpecificBox> evrc_special_box;
// MuxerOperation methods
nsresult Generate(uint32_t* aBoxSize) override;
nsresult Write() override;
// EVRCSampleEntry methods
EVRCSampleEntry(ISOControl* aControl);
~EVRCSampleEntry();
};
}
#endif // EVRCBOX_h_

View File

@ -62,7 +62,7 @@ FragmentBuffer::AddFrame(EncodedFrame* aFrame)
EncodedFrame::FrameType type = aFrame->GetFrameType();
if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD ||
type == EncodedFrame::AMR_AUDIO_CSD) {
type == EncodedFrame::AMR_AUDIO_CSD || type == EncodedFrame::EVRC_AUDIO_CSD) {
mCSDFrame = aFrame;
// Use CSD's timestamp as the start time. Encoder should send CSD frame first
// and then data frames.
@ -168,7 +168,8 @@ ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
{
if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) {
mMetaArray.AppendElement(aTrackMeta);
return NS_OK;
}
@ -180,7 +181,8 @@ ISOControl::GetAudioMetadata(RefPtr<AudioTrackMetadata>& aAudMeta)
{
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) {
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR ||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_EVRC) {
aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
return NS_OK;
}

View File

@ -13,6 +13,7 @@
#include "MP4ESDS.h"
#include "AMRBox.h"
#include "AVCBox.h"
#include "EVRCBox.h"
#include "VideoUtils.h"
namespace mozilla {
@ -666,6 +667,8 @@ SampleDescriptionBox::CreateAudioSampleEntry(RefPtr<SampleEntryBox>& aSampleEntr
aSampleEntry = new AMRSampleEntry(mControl);
} else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) {
aSampleEntry = new MP4AudioSampleEntry(mControl);
} else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) {
aSampleEntry = new EVRCSampleEntry(mControl);
} else {
MOZ_ASSERT(0);
}
@ -1250,6 +1253,17 @@ FileTypeBox::Generate(uint32_t* aBoxSize)
compatible_brands.AppendElement("3gp7");
compatible_brands.AppendElement("3gp6");
compatible_brands.AppendElement("isom");
} else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3G2) {
major_brand = "3g2a";
// 3GPP2 Release 0 and A and 3GPP Release 6 allow movie fragmentation
compatible_brands.AppendElement("3gp9");
compatible_brands.AppendElement("3gp8");
compatible_brands.AppendElement("3gp7");
compatible_brands.AppendElement("3gp6");
compatible_brands.AppendElement("isom");
compatible_brands.AppendElement("3g2c");
compatible_brands.AppendElement("3g2b");
compatible_brands.AppendElement("3g2a");
} else {
MOZ_ASSERT(0);
}

View File

@ -104,7 +104,9 @@ ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
if (type == EncodedFrame::AAC_AUDIO_FRAME ||
type == EncodedFrame::AAC_CSD ||
type == EncodedFrame::AMR_AUDIO_FRAME ||
type == EncodedFrame::AMR_AUDIO_CSD) {
type == EncodedFrame::AMR_AUDIO_CSD ||
type == EncodedFrame::EVRC_AUDIO_FRAME ||
type == EncodedFrame::EVRC_AUDIO_CSD) {
frag = mAudioFragmentBuffer;
} else if (type == EncodedFrame::AVC_I_FRAME ||
type == EncodedFrame::AVC_P_FRAME ||
@ -212,7 +214,8 @@ ISOMediaWriter::SetMetadata(TrackMetadataBase* aMetadata)
PROFILER_LABEL("ISOMediaWriter", "SetMetadata",
js::ProfileEntry::Category::OTHER);
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AAC ||
aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR) {
aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR ||
aMetadata->GetKind() == TrackMetadataBase::METADATA_EVRC) {
mControl->SetMetadata(aMetadata);
mAudioFragmentBuffer = new FragmentBuffer(Audio_Track, FRAG_DURATION);
mControl->SetFragment(mAudioFragmentBuffer);

View File

@ -26,6 +26,10 @@ public:
// Brand names in 'ftyp' box are '3gp9' and 'isom'.
const static uint32_t TYPE_FRAG_3GP = 1 << 1;
// Generate an fragmented 3G2 stream, 3GPP2 C.S0050-B
// Brand names in 'ftyp' box are '3g2c' and 'isom'
const static uint32_t TYPE_FRAG_3G2 = 1 << 2;
// aType is the combination of CREATE_AUDIO_TRACK and CREATE_VIDEO_TRACK.
// It is a hint to muxer that the output streaming contains audio, video
// or both.

View File

@ -99,6 +99,33 @@ public:
~AMRTrackMetadata() { MOZ_COUNT_DTOR(AMRTrackMetadata); }
};
// EVRC sample rate is 8000 samples/s.
#define EVRC_SAMPLE_RATE 8000
class EVRCTrackMetadata : public AudioTrackMetadata {
public:
// AudioTrackMetadata members
//
// The number of sample sets generates by encoder is variant. So the
// frame duration and frame size are both 0.
uint32_t GetAudioFrameDuration() override { return 0; }
uint32_t GetAudioFrameSize() override { return 0; }
uint32_t GetAudioSampleRate() override { return EVRC_SAMPLE_RATE; }
uint32_t GetAudioChannels() override { return mChannels; }
// TrackMetadataBase member
MetadataKind GetKind() const override { return METADATA_EVRC; }
// EVRCTrackMetadata members
EVRCTrackMetadata()
: mChannels(0) {
MOZ_COUNT_CTOR(EVRCTrackMetadata);
}
~EVRCTrackMetadata() { MOZ_COUNT_DTOR(EVRCTrackMetadata); }
uint32_t mChannels; // Channel number, it should be 1 or 2.
};
}
#endif // ISOTrackMetadata_h_

View File

@ -12,6 +12,7 @@ EXPORTS += [
UNIFIED_SOURCES += [
'AMRBox.cpp',
'AVCBox.cpp',
'EVRCBox.cpp',
'ISOControl.cpp',
'ISOMediaBoxes.cpp',
'ISOMediaWriter.cpp',

View File

@ -106,8 +106,7 @@ static const nsString GetKind(const nsCString& aRole)
return EmptyString();
}
static void InitTrack(TrackInfo::TrackType aTrackType,
MessageField* aMsgInfo,
static void InitTrack(MessageField* aMsgInfo,
TrackInfo* aInfo,
bool aEnable)
{
@ -118,8 +117,7 @@ static void InitTrack(TrackInfo::TrackType aTrackType,
nsCString* sRole = aMsgInfo->mValuesStore.Get(eRole);
nsCString* sTitle = aMsgInfo->mValuesStore.Get(eTitle);
nsCString* sLanguage = aMsgInfo->mValuesStore.Get(eLanguage);
aInfo->Init(aTrackType,
sName? NS_ConvertUTF8toUTF16(*sName):EmptyString(),
aInfo->Init(sName? NS_ConvertUTF8toUTF16(*sName):EmptyString(),
sRole? GetKind(*sRole):EmptyString(),
sTitle? NS_ConvertUTF8toUTF16(*sTitle):EmptyString(),
sLanguage? NS_ConvertUTF8toUTF16(*sLanguage):EmptyString(),
@ -319,8 +317,7 @@ void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
}
if (msgInfo) {
InitTrack(TrackInfo::kVideoTrack,
msgInfo,
InitTrack(msgInfo,
&mInfo.mVideo,
mTheoraState == theoraState);
}
@ -344,8 +341,7 @@ void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
}
if (msgInfo) {
InitTrack(TrackInfo::kAudioTrack,
msgInfo,
InitTrack(msgInfo,
&mInfo.mAudio,
mVorbisState == vorbisState);
}
@ -359,8 +355,7 @@ void OggReader::SetupMediaTracksInfo(const nsTArray<uint32_t>& aSerials)
}
if (msgInfo) {
InitTrack(TrackInfo::kAudioTrack,
msgInfo,
InitTrack(msgInfo,
&mInfo.mAudio,
mOpusState == opusState);
}
@ -777,7 +772,7 @@ bool OggReader::ReadOggChain()
LOG(LogLevel::Debug, ("New vorbis ogg link, serial=%d\n", mVorbisSerial));
if (msgInfo) {
InitTrack(TrackInfo::kAudioTrack, msgInfo, &mInfo.mAudio, true);
InitTrack(msgInfo, &mInfo.mAudio, true);
}
mInfo.mAudio.mRate = newVorbisState->mInfo.rate;
mInfo.mAudio.mChannels = newVorbisState->mInfo.channels;
@ -793,7 +788,7 @@ bool OggReader::ReadOggChain()
SetupTargetOpus(newOpusState);
if (msgInfo) {
InitTrack(TrackInfo::kAudioTrack, msgInfo, &mInfo.mAudio, true);
InitTrack(msgInfo, &mInfo.mAudio, true);
}
mInfo.mAudio.mRate = newOpusState->mRate;
mInfo.mAudio.mChannels = newOpusState->mChannels;

View File

@ -30,6 +30,7 @@ using namespace mozilla::layers;
#define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
// AMR NB kbps
#define AMRNB_BITRATE 12200
#define EVRC_BITRATE 8755
#define CODEC_ERROR(args...) \
do { \
@ -38,6 +39,8 @@ using namespace mozilla::layers;
namespace android {
const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc";
enum BufferState
{
BUFFER_OK,
@ -85,6 +88,16 @@ OMXCodecWrapper::CreateAMRNBEncoder()
return amr.forget();
}
OMXAudioEncoder*
OMXCodecWrapper::CreateEVRCEncoder()
{
nsAutoPtr<OMXAudioEncoder> evrc(new OMXAudioEncoder(CodecType::EVRC_ENC));
// Return the object only when media codec is valid.
NS_ENSURE_TRUE(evrc->IsValid(), nullptr);
return evrc.forget();
}
OMXVideoEncoder*
OMXCodecWrapper::CreateAVCEncoder()
{
@ -99,6 +112,7 @@ OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
: mCodecType(aCodecType)
, mStarted(false)
, mAMRCSDProvided(false)
, mEVRCCSDProvided(false)
{
ProcessState::self()->startThreadPool();
@ -111,6 +125,8 @@ OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true);
} else if (aCodecType == CodecType::AAC_ENC) {
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true);
} else if (aCodecType == CodecType::EVRC_ENC) {
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_EVRC, true);
} else {
NS_ERROR("Unknown codec type.");
}
@ -633,6 +649,10 @@ OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
format->setInt32("bitrate", AMRNB_BITRATE);
format->setInt32("sample-rate", aEncodedSampleRate);
} else if (mCodecType == EVRC_ENC) {
format->setString("mime", MEDIA_MIMETYPE_AUDIO_EVRC);
format->setInt32("bitrate", EVRC_BITRATE);
format->setInt32("sample-rate", aEncodedSampleRate);
} else {
MOZ_ASSERT(false, "Can't support this codec type!!");
}
@ -1070,6 +1090,18 @@ OMXCodecWrapper::GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
mAMRCSDProvided = true;
} else if ((mCodecType == EVRC_ENC) && !mEVRCCSDProvided){
// OMX EVRC codec won't provide csd data, need to generate a fake one.
RefPtr<EncodedFrame> audiodata = new EncodedFrame();
// Decoder config descriptor
const uint8_t decConfig[] = {
0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
0x0, // decoder version
0x01, // frames per sample
};
aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
mEVRCCSDProvided = true;
} else {
AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size());
}

View File

@ -88,6 +88,7 @@ public:
AAC_ENC, // AAC encoder.
AMR_NB_ENC, // AMR_NB encoder.
AVC_ENC, // AVC/H.264 encoder.
EVRC_ENC, // EVRC encoder
TYPE_COUNT
};
@ -120,6 +121,9 @@ public:
/** Create a AMR audio encoder. Returns nullptr when failed. */
static OMXAudioEncoder* CreateAMRNBEncoder();
/** Create a EVRC audio encoder. Returns nullptr when failed. */
static OMXAudioEncoder* CreateEVRCEncoder();
/** Create a AVC/H.264 video encoder. Returns nullptr when failed. */
static OMXVideoEncoder* CreateAVCEncoder();
@ -204,6 +208,7 @@ private:
int mCodecType;
bool mStarted; // Has MediaCodec been started?
bool mAMRCSDProvided;
bool mEVRCCSDProvided;
};
/**

View File

@ -130,7 +130,7 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1,
{ \
MutexAutoLock lock(mMutex); \
\
mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers); \
AddAllTopLevelWorkersToArray(workers); \
} \
\
if (!workers.IsEmpty()) { \
@ -1580,6 +1580,28 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return true;
}
void
RuntimeService::RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
WorkerPrivate* aWorkerPrivate)
{
for (auto iter = aDomainInfo->mSharedWorkerInfos.Iter();
!iter.Done();
iter.Next()) {
SharedWorkerInfo* data = iter.UserData();
if (data->mWorkerPrivate == aWorkerPrivate) {
#ifdef DEBUG
fprintf(stderr, "njn: RemoveSharedWorker\n");
nsAutoCString key;
GenerateSharedWorkerKey(data->mScriptSpec, data->mName,
aWorkerPrivate->IsInPrivateBrowsing(), key);
MOZ_ASSERT(iter.Key() == key);
#endif
iter.Remove();
break;
}
}
}
void
RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
@ -1622,19 +1644,8 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
domainInfo->mActiveWorkers.RemoveElement(aWorkerPrivate);
}
if (aWorkerPrivate->IsSharedWorker()) {
MatchSharedWorkerInfo match(aWorkerPrivate);
domainInfo->mSharedWorkerInfos.EnumerateRead(FindSharedWorkerInfo,
&match);
if (match.mSharedWorkerInfo) {
nsAutoCString key;
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
match.mSharedWorkerInfo->mName,
aWorkerPrivate->IsInPrivateBrowsing(), key);
domainInfo->mSharedWorkerInfos.Remove(key);
}
RemoveSharedWorker(domainInfo, aWorkerPrivate);
}
// See if there's a queued worker we can schedule.
@ -1676,7 +1687,21 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
parent->RemoveChildWorker(aCx, aWorkerPrivate);
}
else if (aWorkerPrivate->IsSharedWorker()) {
mWindowMap.Enumerate(RemoveSharedWorkerFromWindowMap, aWorkerPrivate);
AssertIsOnMainThread();
for (auto iter = mWindowMap.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<nsTArray<WorkerPrivate*>>& workers = iter.Data();
MOZ_ASSERT(workers.get());
if (workers->RemoveElement(aWorkerPrivate)) {
MOZ_ASSERT(!workers->Contains(aWorkerPrivate),
"Added worker more than once!");
if (workers->IsEmpty()) {
iter.Remove();
}
}
}
}
else if (aWorkerPrivate->IsDedicatedWorker()) {
// May be null.
@ -1966,7 +1991,7 @@ RuntimeService::Shutdown()
MutexAutoLock lock(mMutex);
nsAutoTArray<WorkerPrivate*, 100> workers;
mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
AddAllTopLevelWorkersToArray(workers);
if (!workers.IsEmpty()) {
// Cancel all top-level workers.
@ -2007,7 +2032,7 @@ RuntimeService::Cleanup()
MutexAutoLock lock(mMutex);
nsAutoTArray<WorkerPrivate*, 100> workers;
mDomainMap.EnumerateRead(AddAllTopLevelWorkersToArray, &workers);
AddAllTopLevelWorkersToArray(workers);
if (!workers.IsEmpty()) {
nsIThread* currentThread = NS_GetCurrentThread();
@ -2118,80 +2143,35 @@ RuntimeService::Cleanup()
nsLayoutStatics::Release();
}
// static
PLDHashOperator
RuntimeService::AddAllTopLevelWorkersToArray(const nsACString& aKey,
WorkerDomainInfo* aData,
void* aUserArg)
void
RuntimeService::AddAllTopLevelWorkersToArray(nsTArray<WorkerPrivate*>& aWorkers)
{
nsTArray<WorkerPrivate*>* array =
static_cast<nsTArray<WorkerPrivate*>*>(aUserArg);
for (auto iter = mDomainMap.Iter(); !iter.Done(); iter.Next()) {
WorkerDomainInfo* aData = iter.UserData();
#ifdef DEBUG
for (uint32_t index = 0; index < aData->mActiveWorkers.Length(); index++) {
MOZ_ASSERT(!aData->mActiveWorkers[index]->GetParent(),
"Shouldn't have a parent in this list!");
}
for (uint32_t index = 0; index < aData->mActiveServiceWorkers.Length(); index++) {
MOZ_ASSERT(!aData->mActiveServiceWorkers[index]->GetParent(),
"Shouldn't have a parent in this list!");
}
for (uint32_t index = 0; index < aData->mActiveWorkers.Length(); index++) {
MOZ_ASSERT(!aData->mActiveWorkers[index]->GetParent(),
"Shouldn't have a parent in this list!");
}
for (uint32_t index = 0; index < aData->mActiveServiceWorkers.Length(); index++) {
MOZ_ASSERT(!aData->mActiveServiceWorkers[index]->GetParent(),
"Shouldn't have a parent in this list!");
}
#endif
array->AppendElements(aData->mActiveWorkers);
array->AppendElements(aData->mActiveServiceWorkers);
aWorkers.AppendElements(aData->mActiveWorkers);
aWorkers.AppendElements(aData->mActiveServiceWorkers);
// These might not be top-level workers...
for (uint32_t index = 0; index < aData->mQueuedWorkers.Length(); index++) {
WorkerPrivate* worker = aData->mQueuedWorkers[index];
if (!worker->GetParent()) {
array->AppendElement(worker);
// These might not be top-level workers...
for (uint32_t index = 0; index < aData->mQueuedWorkers.Length(); index++) {
WorkerPrivate* worker = aData->mQueuedWorkers[index];
if (!worker->GetParent()) {
aWorkers.AppendElement(worker);
}
}
}
return PL_DHASH_NEXT;
}
// static
PLDHashOperator
RuntimeService::RemoveSharedWorkerFromWindowMap(
nsPIDOMWindow* aKey,
nsAutoPtr<nsTArray<WorkerPrivate*> >& aData,
void* aUserArg)
{
AssertIsOnMainThread();
MOZ_ASSERT(aData.get());
MOZ_ASSERT(aUserArg);
auto workerPrivate = static_cast<WorkerPrivate*>(aUserArg);
MOZ_ASSERT(workerPrivate->IsSharedWorker());
if (aData->RemoveElement(workerPrivate)) {
MOZ_ASSERT(!aData->Contains(workerPrivate), "Added worker more than once!");
if (aData->IsEmpty()) {
return PL_DHASH_REMOVE;
}
}
return PL_DHASH_NEXT;
}
// static
PLDHashOperator
RuntimeService::FindSharedWorkerInfo(const nsACString& aKey,
SharedWorkerInfo* aData,
void* aUserArg)
{
auto match = static_cast<MatchSharedWorkerInfo*>(aUserArg);
if (aData->mWorkerPrivate == match->mWorkerPrivate) {
match->mSharedWorkerInfo = aData;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
void
@ -2437,17 +2417,7 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
WorkerDomainInfo* domainInfo;
if (mDomainMap.Get(aWorkerPrivate->Domain(), &domainInfo)) {
MatchSharedWorkerInfo match(aWorkerPrivate);
domainInfo->mSharedWorkerInfos.EnumerateRead(FindSharedWorkerInfo,
&match);
if (match.mSharedWorkerInfo) {
nsAutoCString key;
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
match.mSharedWorkerInfo->mName,
aWorkerPrivate->IsInPrivateBrowsing(), key);
domainInfo->mSharedWorkerInfos.Remove(key);
}
RemoveSharedWorker(domainInfo, aWorkerPrivate);
}
}

View File

@ -75,16 +75,6 @@ class RuntimeService final : public nsIObserver
struct IdleThreadInfo;
struct MatchSharedWorkerInfo
{
WorkerPrivate* mWorkerPrivate;
SharedWorkerInfo* mSharedWorkerInfo;
explicit MatchSharedWorkerInfo(WorkerPrivate* aWorkerPrivate)
: mWorkerPrivate(aWorkerPrivate), mSharedWorkerInfo(nullptr)
{ }
};
mozilla::Mutex mMutex;
// Protected by mMutex.
@ -139,6 +129,10 @@ public:
void
UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
void
RemoveSharedWorker(WorkerDomainInfo* aDomainInfo,
WorkerPrivate* aWorkerPrivate);
void
CancelWorkersForWindow(nsPIDOMWindow* aWindow);
@ -268,20 +262,8 @@ private:
void
Cleanup();
static PLDHashOperator
AddAllTopLevelWorkersToArray(const nsACString& aKey,
WorkerDomainInfo* aData,
void* aUserArg);
static PLDHashOperator
RemoveSharedWorkerFromWindowMap(nsPIDOMWindow* aKey,
nsAutoPtr<nsTArray<WorkerPrivate*> >& aData,
void* aUserArg);
static PLDHashOperator
FindSharedWorkerInfo(const nsACString& aKey,
SharedWorkerInfo* aData,
void* aUserArg);
void
AddAllTopLevelWorkersToArray(nsTArray<WorkerPrivate*>& aWorkers);
void
GetWorkersForWindow(nsPIDOMWindow* aWindow,

View File

@ -20,9 +20,12 @@
#include "nsIDOMChromeWindow.h"
#include "nsIDOMWindow.h"
#include "nsIWebNavigation.h"
#include "nsIWindowMediator.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsWindowWatcher.h"
#include "nsWeakReference.h"
using namespace mozilla;
@ -498,6 +501,31 @@ private:
return rv;
}
if (XRE_IsContentProcess()) {
// ContentProcess
nsCOMPtr<nsIWindowWatcher> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
nsCString spec;
uri->GetSpec(spec);
nsCOMPtr<nsIDOMWindow> newWindow;
pwwatch->OpenWindow2(nullptr,
spec.get(),
nullptr,
nullptr,
false, false, true, nullptr, nullptr,
getter_AddRefs(newWindow));
nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(newWindow);
pwindow.forget(aWindow);
return NS_OK;
}
// Find the most recent browser window and open a new tab in it.
nsCOMPtr<nsIDOMWindow> browserWindow;
rv = wm->GetMostRecentWindow(MOZ_UTF16("navigator:browser"),
@ -580,13 +608,6 @@ already_AddRefed<Promise>
ServiceWorkerClients::OpenWindow(const nsAString& aUrl,
ErrorResult& aRv)
{
// XXXcatalinb: This works only on non-multiprocess for now, bail if we're
// running in a content process.
if (XRE_IsContentProcess()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);

View File

@ -6,6 +6,7 @@
#include "ServiceWorkerEvents.h"
#include "nsIConsoleReportCollector.h"
#include "nsIHttpChannelInternal.h"
#include "nsINetworkInterceptController.h"
#include "nsIOutputStream.h"
@ -19,6 +20,7 @@
#include "nsSerializationHelper.h"
#include "nsQueryObject.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/FetchEventBinding.h"
#include "mozilla/dom/PromiseNativeHandler.h"
@ -36,6 +38,7 @@
#include "mozilla/dom/TypedArray.h"
#endif
#include "js/Conversions.h"
#include "WorkerPrivate.h"
using namespace mozilla::dom;
@ -60,6 +63,8 @@ CancelChannelRunnable::Run()
FetchEvent::FetchEvent(EventTarget* aOwner)
: ExtendableEvent(aOwner)
, mPreventDefaultLineNumber(0)
, mPreventDefaultColumnNumber(0)
, mIsReload(false)
, mWaitToRespond(false)
{
@ -97,6 +102,42 @@ FetchEvent::Constructor(const GlobalObject& aGlobal,
namespace {
void
AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
const nsACString& aRespondWithScriptSpec,
uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
const nsACString& aMessageName, const nsTArray<nsString>& aParams)
{
MOZ_ASSERT(aInterceptedChannel);
// Since the intercepted channel is kept alive and paused while handling
// the FetchEvent, we are guaranteed the reporter is stable on the worker
// thread.
nsIConsoleReportCollector* reporter =
aInterceptedChannel->GetConsoleReportCollector();
if (reporter) {
reporter->AddConsoleReport(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Service Worker Interception"),
nsContentUtils::eDOM_PROPERTIES,
aRespondWithScriptSpec,
aRespondWithLineNumber,
aRespondWithColumnNumber,
aMessageName, aParams);
}
}
template<typename... Params>
void
AsyncLog(nsIInterceptedChannel* aInterceptedChannel,
const nsACString& aRespondWithScriptSpec,
uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
const nsACString& aMessageName, Params... aParams)
{
nsTArray<nsString> paramsList(sizeof...(Params));
StringArrayAppender::Append(paramsList, sizeof...(Params), aParams...);
AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
aRespondWithColumnNumber, aMessageName, paramsList);
}
class FinishResponse final : public nsRunnable
{
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
@ -197,6 +238,10 @@ class RespondWithHandler final : public PromiseNativeHandler
const DebugOnly<bool> mIsClientRequest;
const bool mIsNavigationRequest;
const nsCString mScriptSpec;
const nsString mRequestURL;
const nsCString mRespondWithScriptSpec;
const uint32_t mRespondWithLineNumber;
const uint32_t mRespondWithColumnNumber;
bool mRequestWasHandled;
public:
NS_DECL_ISUPPORTS
@ -204,12 +249,20 @@ public:
RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
RequestMode aRequestMode, bool aIsClientRequest,
bool aIsNavigationRequest,
const nsACString& aScriptSpec)
const nsACString& aScriptSpec,
const nsAString& aRequestURL,
const nsACString& aRespondWithScriptSpec,
uint32_t aRespondWithLineNumber,
uint32_t aRespondWithColumnNumber)
: mInterceptedChannel(aChannel)
, mRequestMode(aRequestMode)
, mIsClientRequest(aIsClientRequest)
, mIsNavigationRequest(aIsNavigationRequest)
, mScriptSpec(aScriptSpec)
, mRequestURL(aRequestURL)
, mRespondWithScriptSpec(aRespondWithScriptSpec)
, mRespondWithLineNumber(aRespondWithLineNumber)
, mRespondWithColumnNumber(aRespondWithColumnNumber)
, mRequestWasHandled(false)
{
}
@ -219,10 +272,20 @@ public:
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
void CancelRequest(nsresult aStatus);
void AsyncLog(const nsACString& aMessageName, const nsTArray<nsString>& aParams)
{
::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
mRespondWithColumnNumber, aMessageName, aParams);
}
private:
~RespondWithHandler()
{
if (!mRequestWasHandled) {
::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec,
mRespondWithLineNumber, mRespondWithColumnNumber,
NS_LITERAL_CSTRING("InterceptionFailedWithURL"), &mRequestURL);
CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
}
}
@ -235,17 +298,29 @@ struct RespondWithClosure
ChannelInfo mWorkerChannelInfo;
const nsCString mScriptSpec;
const nsCString mResponseURLSpec;
const nsString mRequestURL;
const nsCString mRespondWithScriptSpec;
const uint32_t mRespondWithLineNumber;
const uint32_t mRespondWithColumnNumber;
RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
InternalResponse* aInternalResponse,
const ChannelInfo& aWorkerChannelInfo,
const nsCString& aScriptSpec,
const nsACString& aResponseURLSpec)
const nsACString& aResponseURLSpec,
const nsAString& aRequestURL,
const nsACString& aRespondWithScriptSpec,
uint32_t aRespondWithLineNumber,
uint32_t aRespondWithColumnNumber)
: mInterceptedChannel(aChannel)
, mInternalResponse(aInternalResponse)
, mWorkerChannelInfo(aWorkerChannelInfo)
, mScriptSpec(aScriptSpec)
, mResponseURLSpec(aResponseURLSpec)
, mRequestURL(aRequestURL)
, mRespondWithScriptSpec(aRespondWithScriptSpec)
, mRespondWithLineNumber(aRespondWithLineNumber)
, mRespondWithColumnNumber(aRespondWithColumnNumber)
{
}
};
@ -261,6 +336,10 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
data->mScriptSpec,
data->mResponseURLSpec);
} else {
AsyncLog(data->mInterceptedChannel, data->mRespondWithScriptSpec,
data->mRespondWithLineNumber, data->mRespondWithColumnNumber,
NS_LITERAL_CSTRING("InterceptionFailedWithURL"),
&data->mRequestURL);
event = new CancelChannelRunnable(data->mInterceptedChannel,
NS_ERROR_INTERCEPTION_FAILED);
}
@ -270,26 +349,34 @@ void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
class MOZ_STACK_CLASS AutoCancel
{
RefPtr<RespondWithHandler> mOwner;
nsresult mStatus;
nsCString mMessageName;
nsTArray<nsString> mParams;
public:
explicit AutoCancel(RespondWithHandler* aOwner)
AutoCancel(RespondWithHandler* aOwner, const nsString& aRequestURL)
: mOwner(aOwner)
, mStatus(NS_ERROR_INTERCEPTION_FAILED)
, mMessageName(NS_LITERAL_CSTRING("InterceptionFailedWithURL"))
{
mParams.AppendElement(aRequestURL);
}
~AutoCancel()
{
if (mOwner) {
mOwner->CancelRequest(mStatus);
mOwner->AsyncLog(mMessageName, mParams);
mOwner->CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
}
}
void SetCancelStatus(nsresult aStatus)
template<typename... Params>
void SetCancelMessage(const nsACString& aMessageName, Params... aParams)
{
MOZ_ASSERT(NS_FAILED(aStatus));
mStatus = aStatus;
MOZ_ASSERT(mOwner);
MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL"));
MOZ_ASSERT(mParams.Length() == 1);
mMessageName = aMessageName;
mParams.Clear();
StringArrayAppender::Append(mParams, sizeof...(Params), aParams...);
}
void Reset()
@ -303,7 +390,7 @@ NS_IMPL_ISUPPORTS0(RespondWithHandler)
void
RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
AutoCancel autoCancel(this);
AutoCancel autoCancel(this, mRequestURL);
if (!aValue.isObject()) {
NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value");
@ -324,7 +411,8 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
// security implications are not a complete disaster.
if (response->Type() == ResponseType::Opaque &&
!worker->OpaqueInterceptionEnabled()) {
autoCancel.SetCancelStatus(NS_ERROR_OPAQUE_INTERCEPTION_DISABLED);
autoCancel.SetCancelMessage(
NS_LITERAL_CSTRING("OpaqueInterceptionDisabledWithURL"), &mRequestURL);
return;
}
@ -336,24 +424,33 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
// "opaqueredirect".
if (response->Type() == ResponseType::Error) {
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_ERROR_RESPONSE);
autoCancel.SetCancelMessage(
NS_LITERAL_CSTRING("InterceptedErrorResponseWithURL"), &mRequestURL);
return;
}
MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin);
if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE);
uint32_t mode = static_cast<uint32_t>(mRequestMode);
NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[mode].value,
RequestModeValues::strings[mode].length);
autoCancel.SetCancelMessage(
NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestModeWithURL"),
&mRequestURL, &modeString);
return;
}
if (!mIsNavigationRequest && response->Type() == ResponseType::Opaqueredirect) {
autoCancel.SetCancelStatus(NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION);
autoCancel.SetCancelMessage(
NS_LITERAL_CSTRING("BadOpaqueRedirectInterceptionWithURL"), &mRequestURL);
return;
}
if (NS_WARN_IF(response->BodyUsed())) {
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTED_USED_RESPONSE);
autoCancel.SetCancelMessage(
NS_LITERAL_CSTRING("InterceptedUsedResponseWithURL"), &mRequestURL);
return;
}
@ -369,7 +466,6 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
if (response->Type() == ResponseType::Opaque) {
ir->GetUnfilteredUrl(responseURL);
if (NS_WARN_IF(responseURL.IsEmpty())) {
autoCancel.SetCancelStatus(NS_ERROR_INTERCEPTION_FAILED);
return;
}
}
@ -377,7 +473,11 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir,
worker->GetChannelInfo(),
mScriptSpec,
responseURL));
responseURL,
mRequestURL,
mRespondWithScriptSpec,
mRespondWithLineNumber,
mRespondWithColumnNumber));
nsCOMPtr<nsIInputStream> body;
ir->GetUnfilteredBody(getter_AddRefs(body));
// Errors and redirects may not have a body.
@ -414,7 +514,14 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
void
RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
CancelRequest(NS_ERROR_REJECTED_RESPONSE_INTERCEPTION);
nsAutoJSString rejectionString;
if (rejectionString.init(aCx, aValue)) {
::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
mRespondWithColumnNumber,
NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
&mRequestURL, &rejectionString);
}
CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
}
void
@ -429,24 +536,78 @@ RespondWithHandler::CancelRequest(nsresult aStatus)
} // namespace
void
FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
{
if (EventPhase() == nsIDOMEvent::NONE || mWaitToRespond) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
// Record where respondWith() was called in the script so we can include the
// information in any error reporting. We should be guaranteed not to get
// a file:// string here because service workers require http/https.
nsCString spec;
uint32_t line = 0;
uint32_t column = 0;
nsJSUtils::GetCallingLocation(aCx, spec, &line, &column);
RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
nsAutoCString requestURL;
ir->GetURL(requestURL);
StopImmediatePropagation();
mWaitToRespond = true;
RefPtr<RespondWithHandler> handler =
new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(),
ir->IsNavigationRequest(), mScriptSpec);
ir->IsNavigationRequest(), mScriptSpec,
NS_ConvertUTF8toUTF16(requestURL),
spec, line, column);
aArg.AppendNativeHandler(handler);
WaitUntil(aArg, aRv);
}
void
FetchEvent::PreventDefault(JSContext* aCx)
{
MOZ_ASSERT(aCx);
if (mPreventDefaultScriptSpec.IsEmpty()) {
// Note when the FetchEvent might have been canceled by script, but don't
// actually log the location until we are sure it matters. This is
// determined in ServiceWorkerPrivate.cpp. We only remember the first
// call to preventDefault() as its the most likely to have actually canceled
// the event.
nsJSUtils::GetCallingLocation(aCx, mPreventDefaultScriptSpec,
&mPreventDefaultLineNumber,
&mPreventDefaultColumnNumber);
}
Event::PreventDefault(aCx);
}
void
FetchEvent::ReportCanceled()
{
MOZ_ASSERT(!mPreventDefaultScriptSpec.IsEmpty());
RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
nsAutoCString url;
ir->GetURL(url);
// The variadic template provided by StringArrayAppender requires exactly
// an nsString.
NS_ConvertUTF8toUTF16 requestURL(url);
//nsString requestURL;
//CopyUTF8toUTF16(url, requestURL);
::AsyncLog(mChannel.get(), mPreventDefaultScriptSpec,
mPreventDefaultLineNumber, mPreventDefaultColumnNumber,
NS_LITERAL_CSTRING("InterceptionCanceledWithURL"), &requestURL);
}
NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)

View File

@ -103,6 +103,9 @@ class FetchEvent final : public ExtendableEvent
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
RefPtr<Request> mRequest;
nsCString mScriptSpec;
nsCString mPreventDefaultScriptSpec;
uint32_t mPreventDefaultLineNumber;
uint32_t mPreventDefaultColumnNumber;
bool mIsReload;
bool mWaitToRespond;
protected:
@ -112,7 +115,10 @@ protected:
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, ExtendableEvent)
NS_FORWARD_TO_EVENT
// Note, we cannot use NS_FORWARD_TO_EVENT because we want a different
// PreventDefault(JSContext*) override.
NS_FORWARD_NSIDOMEVENT(Event::)
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
{
@ -147,13 +153,19 @@ public:
}
void
RespondWith(Promise& aArg, ErrorResult& aRv);
RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv);
already_AddRefed<Promise>
ForwardTo(const nsAString& aUrl);
already_AddRefed<Promise>
Default();
void
PreventDefault(JSContext* aCx) override;
void
ReportCanceled();
};
#ifndef MOZ_SIMPLEPUSH

View File

@ -3325,44 +3325,6 @@ ServiceWorkerManager::SoftUpdate(const nsACString& aScopeKey,
namespace {
class MOZ_STACK_CLASS FilterRegistrationData
{
public:
FilterRegistrationData(nsTArray<ServiceWorkerClientInfo>& aDocuments,
ServiceWorkerRegistrationInfo* aRegistration)
: mDocuments(aDocuments),
mRegistration(aRegistration)
{
}
nsTArray<ServiceWorkerClientInfo>& mDocuments;
RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
};
static PLDHashOperator
EnumControlledDocuments(nsISupports* aKey,
ServiceWorkerRegistrationInfo* aRegistration,
void* aData)
{
FilterRegistrationData* data = static_cast<FilterRegistrationData*>(aData);
MOZ_ASSERT(data->mRegistration);
MOZ_ASSERT(aRegistration);
if (!data->mRegistration->mScope.Equals(aRegistration->mScope)) {
return PL_DHASH_NEXT;
}
nsCOMPtr<nsIDocument> document = do_QueryInterface(aKey);
if (!document || !document->GetWindow()) {
return PL_DHASH_NEXT;
}
ServiceWorkerClientInfo clientInfo(document);
data->mDocuments.AppendElement(clientInfo);
return PL_DHASH_NEXT;
}
static void
FireControllerChangeOnDocument(nsIDocument* aDocument)
{
@ -3388,28 +3350,6 @@ FireControllerChangeOnDocument(nsIDocument* aDocument)
}
}
static PLDHashOperator
FireControllerChangeOnMatchingDocument(nsISupports* aKey,
ServiceWorkerRegistrationInfo* aValue,
void* aData)
{
AssertIsOnMainThread();
ServiceWorkerRegistrationInfo* contextReg = static_cast<ServiceWorkerRegistrationInfo*>(aData);
if (aValue != contextReg) {
return PL_DHASH_NEXT;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aKey);
if (NS_WARN_IF(!doc)) {
return PL_DHASH_NEXT;
}
FireControllerChangeOnDocument(doc);
return PL_DHASH_NEXT;
}
} // anonymous namespace
void
@ -3427,9 +3367,22 @@ ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
return;
}
FilterRegistrationData data(aControlledDocuments, registration);
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerRegistrationInfo* thisRegistration = iter.UserData();
MOZ_ASSERT(thisRegistration);
if (!registration->mScope.Equals(thisRegistration->mScope)) {
continue;
}
mControlledDocuments.EnumerateRead(EnumControlledDocuments, &data);
nsCOMPtr<nsIDocument> document = do_QueryInterface(iter.Key());
if (!document || !document->GetWindow()) {
continue;
}
ServiceWorkerClientInfo clientInfo(document);
aControlledDocuments.AppendElement(clientInfo);
}
}
void
@ -3517,7 +3470,19 @@ ServiceWorkerManager::SetSkipWaitingFlag(nsIPrincipal* aPrincipal,
void
ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration)
{
mControlledDocuments.EnumerateRead(FireControllerChangeOnMatchingDocument, aRegistration);
AssertIsOnMainThread();
for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
if (iter.UserData() != aRegistration) {
continue;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
if (NS_WARN_IF(!doc)) {
continue;
}
FireControllerChangeOnDocument(doc);
}
}
already_AddRefed<ServiceWorkerRegistrationInfo>
@ -3687,171 +3652,6 @@ HasRootDomain(nsIURI* aURI, const nsACString& aDomain)
return prevChar == '.';
}
struct UnregisterIfMatchesUserData final
{
UnregisterIfMatchesUserData(
ServiceWorkerManager::RegistrationDataPerPrincipal* aRegistrationData,
void* aUserData)
: mRegistrationData(aRegistrationData)
, mUserData(aUserData)
{}
ServiceWorkerManager::RegistrationDataPerPrincipal* mRegistrationData;
void *mUserData;
};
// If host/aData is null, unconditionally unregisters.
PLDHashOperator
UnregisterIfMatchesHost(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aPtr)
{
UnregisterIfMatchesUserData* data =
static_cast<UnregisterIfMatchesUserData*>(aPtr);
// We avoid setting toRemove = aReg by default since there is a possibility
// of failure when data->mUserData is passed, in which case we don't want to
// remove the registration.
ServiceWorkerRegistrationInfo* toRemove = nullptr;
if (data->mUserData) {
const nsACString& domain = *static_cast<nsACString*>(data->mUserData);
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
// This way subdomains are also cleared.
if (NS_SUCCEEDED(rv) && HasRootDomain(scopeURI, domain)) {
toRemove = aReg;
}
} else {
toRemove = aReg;
}
if (toRemove) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->ForceUnregister(data->mRegistrationData, toRemove);
}
return PL_DHASH_NEXT;
}
// If host/aData is null, unconditionally unregisters.
PLDHashOperator
UnregisterIfMatchesHostPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
UnregisterIfMatchesUserData data(aData, aUserData);
aData->mInfos.EnumerateRead(UnregisterIfMatchesHost, &data);
return PL_DHASH_NEXT;
}
PLDHashOperator
UnregisterIfMatchesClearOriginParams(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aPtr)
{
UnregisterIfMatchesUserData* data =
static_cast<UnregisterIfMatchesUserData*>(aPtr);
MOZ_ASSERT(data);
if (data->mUserData) {
OriginAttributes* params = static_cast<OriginAttributes*>(data->mUserData);
MOZ_ASSERT(params);
MOZ_ASSERT(aReg);
MOZ_ASSERT(aReg->mPrincipal);
bool equals = false;
if (params->mInBrowser) {
// When we do a system wide "clear cookies and stored data" on B2G we get
// the "clear-origin-data" notification with the System app appID and
// the browserOnly flag set to true.
// Web sites registering a service worker on B2G have a principal with the
// following information: web site origin + System app appId + inBrowser=1
// So we need to check if the service worker registration info contains
// the System app appID and the enabled inBrowser flag and in that case
// remove it from the registry.
OriginAttributes attrs =
mozilla::BasePrincipal::Cast(aReg->mPrincipal)->OriginAttributesRef();
equals = attrs == *params;
} else {
// If we get the "clear-origin-data" notification because of an app
// uninstallation, we need to check the full principal to get the match
// in the service workers registry. If we find a match, we unregister the
// worker.
nsCOMPtr<nsIAppsService> appsService =
do_GetService(APPS_SERVICE_CONTRACTID);
if (NS_WARN_IF(!appsService)) {
return PL_DHASH_NEXT;
}
nsCOMPtr<mozIApplication> app;
appsService->GetAppByLocalId(params->mAppId, getter_AddRefs(app));
if (NS_WARN_IF(!app)) {
return PL_DHASH_NEXT;
}
nsCOMPtr<nsIPrincipal> principal;
app->GetPrincipal(getter_AddRefs(principal));
if (NS_WARN_IF(!principal)) {
return PL_DHASH_NEXT;
}
aReg->mPrincipal->Equals(principal, &equals);
}
if (equals) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->ForceUnregister(data->mRegistrationData, aReg);
}
}
return PL_DHASH_NEXT;
}
PLDHashOperator
UnregisterIfMatchesClearOriginParams(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
UnregisterIfMatchesUserData data(aData, aUserData);
// We can use EnumerateRead because ForceUnregister (and Unregister) are async.
// Otherwise doing some R/W operations on an hashtable during an EnumerateRead
// will crash.
aData->mInfos.EnumerateRead(UnregisterIfMatchesClearOriginParams,
&data);
return PL_DHASH_NEXT;
}
PLDHashOperator
GetAllRegistrationsEnumerator(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aData)
{
nsIMutableArray* array = static_cast<nsIMutableArray*>(aData);
MOZ_ASSERT(aReg);
if (aReg->mPendingUninstall) {
return PL_DHASH_NEXT;
}
nsCOMPtr<nsIServiceWorkerInfo> info = ServiceWorkerDataInfo::Create(aReg);
if (NS_WARN_IF(!info)) {
return PL_DHASH_NEXT;
}
array->AppendElement(info, false);
return PL_DHASH_NEXT;
}
PLDHashOperator
GetAllRegistrationsPerPrincipalEnumerator(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
aData->mInfos.EnumerateRead(GetAllRegistrationsEnumerator, aUserData);
return PL_DHASH_NEXT;
}
} // namespace
NS_IMPL_ISUPPORTS(ServiceWorkerDataInfo, nsIServiceWorkerInfo)
@ -3939,12 +3739,29 @@ ServiceWorkerManager::GetAllRegistrations(nsIArray** aResult)
return NS_ERROR_OUT_OF_MEMORY;
}
mRegistrationInfos.EnumerateRead(GetAllRegistrationsPerPrincipalEnumerator, array);
for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
for (auto it2 = it1.UserData()->mInfos.Iter(); !it2.Done(); it2.Next()) {
ServiceWorkerRegistrationInfo* reg = it2.UserData();
MOZ_ASSERT(reg);
if (reg->mPendingUninstall) {
continue;
}
nsCOMPtr<nsIServiceWorkerInfo> info = ServiceWorkerDataInfo::Create(reg);
if (NS_WARN_IF(!info)) {
continue;
}
array->AppendElement(info, false);
}
}
array.forget(aResult);
return NS_OK;
}
// MUST ONLY BE CALLED FROM UnregisterIfMatchesHost!
// MUST ONLY BE CALLED FROM Remove(), RemoveAll() and RemoveAllRegistrations()!
void
ServiceWorkerManager::ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData,
ServiceWorkerRegistrationInfo* aRegistration)
@ -3983,8 +3800,20 @@ ServiceWorkerManager::Remove(const nsACString& aHost)
return;
}
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal,
&const_cast<nsACString&>(aHost));
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
ServiceWorkerManager::RegistrationDataPerPrincipal* data = it1.UserData();
for (auto it2 = data->mInfos.Iter(); !it2.Done(); it2.Next()) {
ServiceWorkerRegistrationInfo* reg = it2.UserData();
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), it2.Key(),
nullptr, nullptr);
// This way subdomains are also cleared.
if (NS_SUCCEEDED(rv) && HasRootDomain(scopeURI, aHost)) {
swm->ForceUnregister(data, reg);
}
}
}
}
void
@ -4005,7 +3834,15 @@ void
ServiceWorkerManager::RemoveAll()
{
AssertIsOnMainThread();
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal, nullptr);
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
ServiceWorkerManager::RegistrationDataPerPrincipal* data = it1.UserData();
for (auto it2 = data->mInfos.Iter(); !it2.Done(); it2.Next()) {
ServiceWorkerRegistrationInfo* reg = it2.UserData();
swm->ForceUnregister(data, reg);
}
}
}
void
@ -4023,17 +3860,6 @@ ServiceWorkerManager::PropagateRemoveAll()
mActor->SendPropagateRemoveAll();
}
static PLDHashOperator
UpdateEachRegistration(const nsACString& aKey,
ServiceWorkerRegistrationInfo* aInfo,
void* aUserArg) {
auto This = static_cast<ServiceWorkerManager*>(aUserArg);
MOZ_ASSERT(!aInfo->mScope.IsEmpty());
This->SoftUpdate(aInfo->mPrincipal, aInfo->mScope);
return PL_DHASH_NEXT;
}
void
ServiceWorkerManager::RemoveAllRegistrations(OriginAttributes* aParams)
{
@ -4041,16 +3867,63 @@ ServiceWorkerManager::RemoveAllRegistrations(OriginAttributes* aParams)
MOZ_ASSERT(aParams);
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesClearOriginParams,
aParams);
}
for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
ServiceWorkerManager::RegistrationDataPerPrincipal* data = it1.UserData();
static PLDHashOperator
UpdateEachRegistrationPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserArg) {
aData->mInfos.EnumerateRead(UpdateEachRegistration, aUserArg);
return PL_DHASH_NEXT;
// We can use iteration because ForceUnregister (and Unregister) are
// async. Otherwise doing some R/W operations on an hashtable during
// iteration will crash.
for (auto it2 = data->mInfos.Iter(); !it2.Done(); it2.Next()) {
ServiceWorkerRegistrationInfo* reg = it2.UserData();
MOZ_ASSERT(reg);
MOZ_ASSERT(reg->mPrincipal);
bool equals = false;
if (aParams->mInBrowser) {
// When we do a system wide "clear cookies and stored data" on B2G we
// get the "clear-origin-data" notification with the System app appID
// and the browserOnly flag set to true. Web sites registering a
// service worker on B2G have a principal with the following
// information: web site origin + System app appId + inBrowser=1 So
// we need to check if the service worker registration info contains
// the System app appID and the enabled inBrowser flag and in that
// case remove it from the registry.
OriginAttributes attrs =
mozilla::BasePrincipal::Cast(reg->mPrincipal)->OriginAttributesRef();
equals = attrs == *aParams;
} else {
// If we get the "clear-origin-data" notification because of an app
// uninstallation, we need to check the full principal to get the
// match in the service workers registry. If we find a match, we
// unregister the worker.
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (NS_WARN_IF(!appsService)) {
continue;
}
nsCOMPtr<mozIApplication> app;
appsService->GetAppByLocalId(aParams->mAppId, getter_AddRefs(app));
if (NS_WARN_IF(!app)) {
continue;
}
nsCOMPtr<nsIPrincipal> principal;
app->GetPrincipal(getter_AddRefs(principal));
if (NS_WARN_IF(!principal)) {
continue;
}
reg->mPrincipal->Equals(principal, &equals);
}
if (equals) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->ForceUnregister(data, reg);
}
}
}
}
NS_IMETHODIMP
@ -4058,7 +3931,14 @@ ServiceWorkerManager::UpdateAllRegistrations()
{
AssertIsOnMainThread();
mRegistrationInfos.EnumerateRead(UpdateEachRegistrationPerPrincipal, this);
for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
for (auto it2 = it1.UserData()->mInfos.Iter(); !it2.Done(); it2.Next()) {
ServiceWorkerRegistrationInfo* info = it2.UserData();
MOZ_ASSERT(!info->mScope.IsEmpty());
SoftUpdate(info->mPrincipal, info->mScope);
}
}
return NS_OK;
}

View File

@ -1167,7 +1167,9 @@ private:
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
nsCOMPtr<nsIRunnable> runnable;
if (event->DefaultPrevented(aCx)) {
runnable = new CancelChannelRunnable(mInterceptedChannel, NS_ERROR_INTERCEPTION_CANCELED);
event->ReportCanceled();
runnable = new CancelChannelRunnable(mInterceptedChannel,
NS_ERROR_INTERCEPTION_FAILED);
} else {
runnable = new ResumeRequest(mInterceptedChannel);
}

View File

@ -23,7 +23,7 @@ parent:
PPrintProgressDialog printProgressDialog,
bool isForPrinting)
returns(bool notifyOnOpen,
bool success);
nsresult rv);
async ShowPrintDialog(PPrintSettingsDialog dialog,
PBrowser browser,

View File

@ -30,9 +30,10 @@ PrintingParent::RecvShowProgress(PBrowserParent* parent,
PPrintProgressDialogParent* printProgressDialog,
const bool& isForPrinting,
bool* notifyOnOpen,
bool* success)
nsresult* result)
{
*success = false;
*result = NS_ERROR_FAILURE;
*notifyOnOpen = false;
nsCOMPtr<nsIDOMWindow> parentWin = DOMWindowFromBrowserParent(parent);
if (!parentWin) {
@ -52,17 +53,16 @@ PrintingParent::RecvShowProgress(PBrowserParent* parent,
nsCOMPtr<nsIWebProgressListener> printProgressListener;
nsCOMPtr<nsIPrintProgressParams> printProgressParams;
nsresult rv = pps->ShowProgress(parentWin, nullptr, nullptr, observer,
isForPrinting,
getter_AddRefs(printProgressListener),
getter_AddRefs(printProgressParams),
notifyOnOpen);
NS_ENSURE_SUCCESS(rv, true);
*result = pps->ShowProgress(parentWin, nullptr, nullptr, observer,
isForPrinting,
getter_AddRefs(printProgressListener),
getter_AddRefs(printProgressParams),
notifyOnOpen);
NS_ENSURE_SUCCESS(*result, true);
dialogParent->SetWebProgressListener(printProgressListener);
dialogParent->SetPrintProgressParams(printProgressParams);
*success = true;
return true;
}

View File

@ -25,7 +25,7 @@ public:
PPrintProgressDialogParent* printProgressDialog,
const bool& isForPrinting,
bool* notifyOnOpen,
bool* success);
nsresult* result);
virtual bool
RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
PBrowserParent* aParent,

View File

@ -149,10 +149,12 @@ nsPrintingProxy::ShowProgress(nsIDOMWindow* parent,
SendPPrintProgressDialogConstructor(dialogChild);
bool success = false;
mozilla::unused << SendShowProgress(pBrowser, dialogChild,
isForPrinting, notifyOnOpen, &success);
isForPrinting, notifyOnOpen, &rv);
if (NS_FAILED(rv)) {
return rv;
}
NS_ADDREF(*webProgressListener = dialogChild);
NS_ADDREF(*printProgressParams = dialogChild);

View File

@ -545,8 +545,8 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
// no extant window? make a new one.
// If no parent, consider it chrome.
bool hasChromeParent = true;
// If no parent, consider it chrome when running in the parent process.
bool hasChromeParent = XRE_IsContentProcess() ? false : true;
if (aParent) {
// Check if the parent document has chrome privileges.
nsIDocument* doc = parentWindow->GetDoc();
@ -613,7 +613,9 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
// based on whether the docshell type is chrome or content.
nsCOMPtr<nsIGlobalObject> parentGlobalObject = do_QueryInterface(aParent);
if (NS_WARN_IF(!jsapiChromeGuard.Init(parentGlobalObject))) {
if (!aParent) {
jsapiChromeGuard.Init();
} else if (NS_WARN_IF(!jsapiChromeGuard.Init(parentGlobalObject))) {
return NS_ERROR_UNEXPECTED;
}
}
@ -645,10 +647,16 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
!(chromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
nsCOMPtr<nsIWindowProvider> provider = do_GetInterface(parentTreeOwner);
if (provider) {
NS_ASSERTION(aParent, "We've _got_ to have a parent here!");
nsCOMPtr<nsIWindowProvider> provider;
if (parentTreeOwner) {
provider = do_GetInterface(parentTreeOwner);
} else if (XRE_IsContentProcess()) {
// we're in a content process but we don't have a tabchild we can
// use.
provider = nsContentUtils::GetWindowProviderForContentProcess();
}
if (provider) {
nsCOMPtr<nsIDOMWindow> newWindow;
rv = provider->ProvideWindow(aParent, chromeFlags, aCalledFromJS,
sizeSpec.PositionSpecified(),

View File

@ -17,6 +17,7 @@
#include "GLScreenBuffer.h"
#include "gfxCrashReporterUtils.h"
#include "gfxEnv.h"
#include "gfxUtils.h"
#include "GLContextProvider.h"
#include "GLTextureImage.h"
@ -637,16 +638,16 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
#ifdef MOZ_GL_DEBUG
if (PR_GetEnv("MOZ_GL_DEBUG"))
if (gfxEnv::GlDebug())
sDebugMode |= DebugEnabled;
// enables extra verbose output, informing of the start and finish of every GL call.
// useful e.g. to record information to investigate graphics system crashes/lockups
if (PR_GetEnv("MOZ_GL_DEBUG_VERBOSE"))
if (gfxEnv::GlDebugVerbose())
sDebugMode |= DebugTrace;
// aborts on GL error. Can be useful to debug quicker code that is known not to generate any GL error in principle.
if (PR_GetEnv("MOZ_GL_DEBUG_ABORT_ON_ERROR"))
if (gfxEnv::GlDebugAbortOnError())
sDebugMode |= DebugAbortOnError;
#endif
@ -2582,8 +2583,7 @@ GLContext::FlushIfHeavyGLCallsSinceLastFlush()
/*static*/ bool
GLContext::ShouldDumpExts()
{
static bool ret = PR_GetEnv("MOZ_GL_DUMP_EXTS");
return ret;
return gfxEnv::GlDumpExtensions();
}
bool
@ -2613,8 +2613,7 @@ DoesStringMatch(const char* aString, const char *aWantedString)
/*static*/ bool
GLContext::ShouldSpew()
{
static bool ret = PR_GetEnv("MOZ_GL_SPEW");
return ret;
return gfxEnv::GlSpew();
}
void

View File

@ -26,6 +26,7 @@
#include "GLXLibrary.h"
#include "gfxXlibSurface.h"
#include "gfxContext.h"
#include "gfxEnv.h"
#include "gfxPlatform.h"
#include "GLContextGLX.h"
#include "gfxUtils.h"
@ -98,7 +99,7 @@ GLXLibrary::EnsureInitialized()
reporter.SetSuccessful();
}
if (PR_GetEnv("MOZ_GLX_DEBUG")) {
if (gfxEnv::GlxDebug()) {
mDebug = true;
}
@ -1283,16 +1284,8 @@ GLContextProviderGLX::CreateOffscreen(const IntSize& size,
/*static*/ GLContext*
GLContextProviderGLX::GetGlobalContext()
{
static bool checkedContextSharing = false;
static bool useContextSharing = false;
if (!checkedContextSharing) {
useContextSharing = getenv("MOZ_DISABLE_CONTEXT_SHARING_GLX") == 0;
checkedContextSharing = true;
}
// TODO: get GLX context sharing to work well with multiple threads
if (!useContextSharing) {
if (gfxEnv::DisableContextSharingGlx()) {
return nullptr;
}

View File

@ -111,7 +111,13 @@ Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
color = gfx::Color(0.0f, 1.0f, 1.0f, 1.0f); // greenish blue
}
} else if (aFlags & DiagnosticFlags::IMAGE) {
color = gfx::Color(1.0f, 0.0f, 0.0f, 1.0f); // red
if (aFlags & DiagnosticFlags::NV12) {
color = gfx::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
} else if (aFlags & DiagnosticFlags::YCBCR) {
color = gfx::Color(1.0f, 0.55f, 0.0f, 1.0f); // orange
} else {
color = gfx::Color(1.0f, 0.0f, 0.0f, 1.0f); // red
}
} else if (aFlags & DiagnosticFlags::COLOR) {
color = gfx::Color(0.0f, 0.0f, 1.0f, 1.0f); // blue
} else if (aFlags & DiagnosticFlags::CONTAINER) {

View File

@ -107,7 +107,9 @@ enum class DiagnosticFlags : uint16_t {
TILE = 1 << 5,
BIGIMAGE = 1 << 6,
COMPONENT_ALPHA = 1 << 7,
REGION_RECT = 1 << 8
REGION_RECT = 1 << 8,
NV12 = 1 << 9,
YCBCR = 1 << 10
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DiagnosticFlags)

View File

@ -10,6 +10,7 @@
#include <stdlib.h> // for getenv
#include "DirectedGraph.h" // for DirectedGraph
#include "Layers.h" // for Layer
#include "gfxEnv.h" // for gfxEnv
#include "gfxLineSegment.h" // for gfxLineSegment
#include "gfxPoint.h" // for gfxPoint
#include "gfxQuad.h" // for gfxQuad
@ -152,8 +153,6 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
}
#ifdef DEBUG
static bool gDumpLayerSortList = getenv("MOZ_DUMP_LAYER_SORT_LIST") != 0;
// #define USE_XTERM_COLORING
#ifdef USE_XTERM_COLORING
// List of color values, which can be added to the xterm foreground offset or
@ -251,7 +250,7 @@ void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
DirectedGraph<Layer*> graph;
#ifdef DEBUG
if (gDumpLayerSortList) {
if (gfxEnv::DumpLayerSortList()) {
for (uint32_t i = 0; i < nodeCount; i++) {
if (aLayers.ElementAt(i)->GetDebugColorIndex() == 0) {
aLayers.ElementAt(i)->SetDebugColorIndex(gColorIndex++);
@ -280,7 +279,7 @@ void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
}
#ifdef DEBUG
if (gDumpLayerSortList) {
if (gfxEnv::DumpLayerSortList()) {
fprintf(stderr, " --- Edge List: --- \n");
DumpEdgeList(graph);
}
@ -347,7 +346,7 @@ void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
} while (!noIncoming.IsEmpty());
NS_ASSERTION(!graph.GetEdgeCount(), "Cycles detected!");
#ifdef DEBUG
if (gDumpLayerSortList) {
if (gfxEnv::DumpLayerSortList()) {
fprintf(stderr, " --- Layers after sorting: --- \n");
DumpLayerList(sortedList);
}

View File

@ -15,6 +15,7 @@
#include "LayersLogging.h" // for AppendToString
#include "ReadbackLayer.h" // for ReadbackLayer
#include "UnitTransforms.h" // for ViewAs
#include "gfxEnv.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxPrefs.h"
#include "gfxUtils.h" // for gfxUtils, etc
@ -1052,6 +1053,12 @@ Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
nsIntRegion siblingVisibleRegion(sibling->GetEffectiveVisibleRegion());
// Translate the siblings region to |layer|'s origin.
siblingVisibleRegion.MoveBy(-siblingOffset.x, -siblingOffset.y);
// Apply the sibling's clip.
// Layer clip rects are not affected by the layer's transform.
Maybe<ParentLayerIntRect> clipRect = sibling->GetEffectiveClipRect();
if (clipRect) {
siblingVisibleRegion.AndWith(ParentLayerIntRect::ToUntyped(*clipRect));
}
// Subtract the sibling visible region from the visible region of |this|.
aResult.SubOut(siblingVisibleRegion);
}
@ -1362,7 +1369,7 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToS
GetForceIsolatedGroup()) {
useIntermediateSurface = true;
#ifdef MOZ_DUMP_PAINTING
} else if (gfxUtils::sDumpPaintingIntermediate && !Extend3DContext()) {
} else if (gfxEnv::DumpPaintIntermediate() && !Extend3DContext()) {
useIntermediateSurface = true;
#endif
} else {
@ -1685,9 +1692,9 @@ void
Layer::Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml)
{
#ifdef MOZ_DUMP_PAINTING
bool dumpCompositorTexture = gfxUtils::sDumpCompositorTextures && AsLayerComposite() &&
bool dumpCompositorTexture = gfxEnv::DumpCompositorTextures() && AsLayerComposite() &&
AsLayerComposite()->GetCompositableHost();
bool dumpClientTexture = gfxUtils::sDumpPainting && AsShadowableLayer() &&
bool dumpClientTexture = gfxEnv::DumpPaint() && AsShadowableLayer() &&
AsShadowableLayer()->GetCompositableClient();
nsCString layerId(Name());
layerId.Append('-');

View File

@ -1099,13 +1099,13 @@ nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent,
break;
}
case MOUSE_INPUT: {
ScrollWheelInput scrollInput = aEvent.AsScrollWheelInput();
if (!scrollInput.TransformToLocal(aTransformToApzc)) {
MouseInput mouseInput = aEvent.AsMouseInput();
if (!mouseInput.TransformToLocal(aTransformToApzc)) {
return rv;
}
// TODO Need to implement blocks to properly handle this.
//rv = HandleDragEvent(scrollInput, dragMetrics);
//rv = HandleDragEvent(mouseInput, dragMetrics);
break;
}
case SCROLLWHEEL_INPUT: {

View File

@ -234,7 +234,7 @@ public:
TextureDumpMode aCompress);
protected:
CompositableChild* mCompositableChild;
CompositableForwarder* mForwarder;
RefPtr<CompositableForwarder> mForwarder;
// Some layers may want to enforce some flags to all their textures
// (like disallowing tiling)
TextureFlags mTextureFlags;

Some files were not shown because too many files have changed in this diff Show More