mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to central, a=merge
This commit is contained in:
commit
e94d19c4a0
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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))
|
||||
];
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -52,7 +52,9 @@ var Converter = Class({
|
||||
"nsIRequestObserver"
|
||||
],
|
||||
|
||||
get wrappedJSObject() this,
|
||||
get wrappedJSObject() {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* This component works as such:
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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"]
|
||||
|
86
dom/base/ConsoleReportCollector.cpp
Normal file
86
dom/base/ConsoleReportCollector.cpp
Normal 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
|
73
dom/base/ConsoleReportCollector.h
Normal file
73
dom/base/ConsoleReportCollector.h
Normal 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
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
81
dom/base/nsIConsoleReportCollector.h
Normal file
81
dom/base/nsIConsoleReportCollector.h
Normal 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
|
@ -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"));
|
||||
|
@ -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() {
|
||||
|
@ -495,6 +495,7 @@ DOMInterfaces = {
|
||||
'binaryNames': {
|
||||
'request': 'request_'
|
||||
},
|
||||
'implicitJSContext': [ 'respondWith' ],
|
||||
},
|
||||
|
||||
'FileReader': {
|
||||
|
@ -743,7 +743,7 @@ class CGInterfaceObjectJSClass(CGThing):
|
||||
nullptr, /* unwatch */
|
||||
nullptr, /* getElements */
|
||||
nullptr, /* enumerate */
|
||||
nullptr, /* thisObject */
|
||||
nullptr, /* thisValue */
|
||||
InterfaceObjectToString, /* funToString */
|
||||
}
|
||||
},
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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'.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ parent:
|
||||
PPrintProgressDialog printProgressDialog,
|
||||
bool isForPrinting)
|
||||
returns(bool notifyOnOpen,
|
||||
bool success);
|
||||
nsresult rv);
|
||||
|
||||
async ShowPrintDialog(PPrintSettingsDialog dialog,
|
||||
PBrowser browser,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
PPrintProgressDialogParent* printProgressDialog,
|
||||
const bool& isForPrinting,
|
||||
bool* notifyOnOpen,
|
||||
bool* success);
|
||||
nsresult* result);
|
||||
virtual bool
|
||||
RecvShowPrintDialog(PPrintSettingsDialogParent* aDialog,
|
||||
PBrowserParent* aParent,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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('-');
|
||||
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "BasicLayers.h" // for BasicLayerManager
|
||||
#include "gfxContext.h" // for gfxContext, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxPoint.h" // for IntSize, gfxPoint
|
||||
#include "gfxTeeSurface.h" // for gfxTeeSurface
|
||||
@ -26,7 +27,6 @@
|
||||
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
||||
#include "nsISupportsImpl.h" // for gfxContext::Release, etc
|
||||
#include "nsIWidget.h" // for nsIWidget
|
||||
#include "prenv.h" // for PR_GetEnv
|
||||
#include "nsLayoutUtils.h"
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsPlatform.h"
|
||||
@ -88,7 +88,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
||||
backend == LayersBackend::LAYERS_BASIC;
|
||||
}
|
||||
|
||||
if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
|
||||
if (useDoubleBuffering || gfxEnv::ForceDoubleBuffering()) {
|
||||
return MakeAndAddRef<ContentClientDoubleBuffered>(aForwarder);
|
||||
}
|
||||
return MakeAndAddRef<ContentClientSingleBuffered>(aForwarder);
|
||||
|
@ -381,6 +381,11 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
||||
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(parentBackend, aSelector);
|
||||
|
||||
@ -487,6 +492,11 @@ TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aTextureFlags,
|
||||
TextureAllocationFlags aAllocFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture =
|
||||
CreateBufferTextureClient(aAllocator, aFormat,
|
||||
aTextureFlags, aMoz2DBackend);
|
||||
@ -506,6 +516,11 @@ TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
||||
StereoMode aStereoMode,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture;
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
@ -531,6 +546,11 @@ TextureClient::CreateWithBufferSize(ISurfaceAllocator* aAllocator,
|
||||
size_t aSize,
|
||||
TextureFlags aTextureFlags)
|
||||
{
|
||||
MOZ_ASSERT(aAllocator->IPCOpen());
|
||||
if (!aAllocator || !aAllocator->IPCOpen()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BufferTextureClient> texture;
|
||||
if (aAllocator->IsSameProcess()) {
|
||||
texture = new MemoryTextureClient(aAllocator, gfx::SurfaceFormat::YUV,
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "CanvasLayerComposite.h"
|
||||
#include "composite/CompositableHost.h" // for CompositableHost
|
||||
#include "gfx2DGlue.h" // for ToFilter
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "gfxEnv.h" // for gfxEnv, etc
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/gfx/Point.h" // for Point
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
@ -88,7 +88,7 @@ CanvasLayerComposite::RenderLayer(const IntRect& aClipRect)
|
||||
mCompositor->MakeCurrent();
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpCompositorTextures) {
|
||||
if (gfxEnv::DumpCompositorTextures()) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = mCompositableHost->GetAsSurface();
|
||||
WriteSnapshotToDumpFile(this, surf);
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include "apz/src/AsyncPanZoomController.h" // for AsyncPanZoomController
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for LayerRect, LayerPixel, etc
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/UniquePtr.h" // for UniquePtr
|
||||
@ -40,7 +40,7 @@
|
||||
#define CULLING_LOG(...)
|
||||
// #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
|
||||
|
||||
#define DUMP(...) do { if (getenv("DUMP_DEBUG")) { printf_stderr(__VA_ARGS__); } } while(0)
|
||||
#define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
|
||||
#define XYWH(k) (k).x, (k).y, (k).width, (k).height
|
||||
#define XY(k) (k).x, (k).y
|
||||
#define WH(k) (k).width, (k).height
|
||||
@ -163,7 +163,7 @@ ContainerRenderVR(ContainerT* aContainer,
|
||||
surfaceRect.height = std::min(maxTextureSize, surfaceRect.height);
|
||||
|
||||
gfx::VRHMDRenderingSupport *vrRendering = aHMD->GetRenderingSupport();
|
||||
if (PR_GetEnv("NO_VR_RENDERING")) vrRendering = nullptr;
|
||||
if (gfxEnv::NoVRRendering()) vrRendering = nullptr;
|
||||
if (vrRendering) {
|
||||
if (!aContainer->mVRRenderTargetSet || aContainer->mVRRenderTargetSet->size != surfaceRect.Size()) {
|
||||
aContainer->mVRRenderTargetSet = vrRendering->CreateRenderTargetSet(compositor, surfaceRect.Size());
|
||||
@ -297,7 +297,7 @@ ContainerRenderVR(ContainerT* aContainer,
|
||||
|
||||
// draw the temporary surface with VR distortion to the original destination
|
||||
EffectChain vrEffect(aContainer);
|
||||
bool skipDistortion = vrRendering || PR_GetEnv("MOZ_GFX_VR_NO_DISTORTION");
|
||||
bool skipDistortion = vrRendering || gfxEnv::VRNoDistortion();
|
||||
if (skipDistortion) {
|
||||
vrEffect.mPrimaryEffect = new EffectRenderTarget(surface);
|
||||
} else {
|
||||
@ -708,7 +708,7 @@ ContainerRender(ContainerT* aContainer,
|
||||
gfx::Rect visibleRect(aContainer->GetEffectiveVisibleRegion().GetBounds());
|
||||
RefPtr<Compositor> compositor = aManager->GetCompositor();
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpCompositorTextures) {
|
||||
if (gfxEnv::DumpCompositorTextures()) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
|
||||
if (surf) {
|
||||
WriteSnapshotToDumpFile(aContainer, surf);
|
||||
|
@ -316,6 +316,13 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||
return;
|
||||
}
|
||||
|
||||
DiagnosticFlags diagnosticFlags = DiagnosticFlags::IMAGE;
|
||||
if (effect->mType == EffectTypes::NV12) {
|
||||
diagnosticFlags |= DiagnosticFlags::NV12;
|
||||
} else if (effect->mType == EffectTypes::YCBCR) {
|
||||
diagnosticFlags |= DiagnosticFlags::YCBCR;
|
||||
}
|
||||
|
||||
if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
|
||||
if (mImageContainer) {
|
||||
aLayer->GetLayerManager()->
|
||||
@ -363,12 +370,12 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||
}
|
||||
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
||||
aOpacity, aTransform);
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,
|
||||
GetCompositor()->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
|
||||
rect, aClipRect, aTransform, mFlashCounter);
|
||||
} while (it->NextTile());
|
||||
it->EndBigImageIteration();
|
||||
// layer border
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE, pictureRect,
|
||||
GetCompositor()->DrawDiagnostics(diagnosticFlags, pictureRect,
|
||||
aClipRect, aTransform, mFlashCounter);
|
||||
} else {
|
||||
IntSize textureSize = img->mTextureSource->GetSize();
|
||||
@ -384,7 +391,7 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||
|
||||
GetCompositor()->DrawQuad(pictureRect, aClipRect, aEffectChain,
|
||||
aOpacity, aTransform);
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE,
|
||||
GetCompositor()->DrawDiagnostics(diagnosticFlags,
|
||||
pictureRect, aClipRect,
|
||||
aTransform, mFlashCounter);
|
||||
}
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include "CompositableHost.h" // for CompositableHost
|
||||
#include "Layers.h" // for WriteSnapshotToDumpFile, etc
|
||||
#include "gfx2DGlue.h" // for ToFilter
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/gfx/Point.h" // for IntSize, Point
|
||||
@ -87,7 +87,7 @@ ImageLayerComposite::RenderLayer(const IntRect& aClipRect)
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpCompositorTextures) {
|
||||
if (gfxEnv::DumpCompositorTextures()) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = mImageHost->GetAsSurface();
|
||||
WriteSnapshotToDumpFile(this, surf);
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
|
||||
, mDebugOverlayWantsNextFrame(false)
|
||||
, mGeometryChanged(true)
|
||||
, mLastFrameMissedHWC(false)
|
||||
, mWindowOverlayChanged(false)
|
||||
{
|
||||
mTextRenderer = new TextRenderer(aCompositor);
|
||||
MOZ_ASSERT(aCompositor);
|
||||
@ -339,7 +340,7 @@ LayerManagerComposite::UpdateAndRender()
|
||||
// Update cached layer tree information.
|
||||
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
|
||||
|
||||
if (invalid.IsEmpty()) {
|
||||
if (invalid.IsEmpty() && !mWindowOverlayChanged) {
|
||||
// Composition requested, but nothing has changed. Don't do any work.
|
||||
return;
|
||||
}
|
||||
@ -360,6 +361,7 @@ LayerManagerComposite::UpdateAndRender()
|
||||
RenderToPresentationSurface();
|
||||
#endif
|
||||
mGeometryChanged = false;
|
||||
mWindowOverlayChanged = false;
|
||||
}
|
||||
|
||||
already_AddRefed<DrawTarget>
|
||||
|
@ -278,6 +278,11 @@ public:
|
||||
aNotifications->AppendElements(Move(mImageCompositeNotifications));
|
||||
}
|
||||
|
||||
// Indicate that we need to composite even if nothing in our layers has
|
||||
// changed, so that the widget can draw something different in its window
|
||||
// overlay.
|
||||
void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
|
||||
|
||||
private:
|
||||
/** Region we're clipping our current drawing to. */
|
||||
nsIntRegion mClippingRegion;
|
||||
@ -356,6 +361,8 @@ private:
|
||||
// Testing property. If hardware composer is supported, this will return
|
||||
// true if the last frame was deemed 'too complicated' to be rendered.
|
||||
bool mLastFrameMissedHWC;
|
||||
|
||||
bool mWindowOverlayChanged;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "CompositableHost.h" // for TiledLayerProperties, etc
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for CSSRect, LayerPixel, etc
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/gfx/Point.h" // for Point
|
||||
@ -115,7 +115,7 @@ PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
|
||||
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpCompositorTextures) {
|
||||
if (gfxEnv::DumpCompositorTextures()) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
|
||||
if (surf) {
|
||||
WriteSnapshotToDumpFile(this, surf);
|
||||
|
@ -99,6 +99,9 @@ ISurfaceAllocator::AllocSurfaceDescriptor(const gfx::IntSize& aSize,
|
||||
gfxContentType aContent,
|
||||
SurfaceDescriptor* aBuffer)
|
||||
{
|
||||
if (!IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
return AllocSurfaceDescriptorWithCaps(aSize, aContent, DEFAULT_BUFFER_CAPS, aBuffer);
|
||||
}
|
||||
|
||||
@ -108,6 +111,9 @@ ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
|
||||
uint32_t aCaps,
|
||||
SurfaceDescriptor* aBuffer)
|
||||
{
|
||||
if (!IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
gfx::SurfaceFormat format =
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent);
|
||||
size_t size = ImageDataSerializer::ComputeMinBufferSize(aSize, format);
|
||||
@ -154,6 +160,11 @@ ISurfaceAllocator::IsShmem(SurfaceDescriptor* aSurface)
|
||||
void
|
||||
ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aSurface);
|
||||
if (!aSurface) {
|
||||
return;
|
||||
@ -207,6 +218,10 @@ struct ShmemSectionHeapAllocation
|
||||
bool
|
||||
ISurfaceAllocator::AllocShmemSection(size_t aSize, mozilla::layers::ShmemSection* aShmemSection)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
// For now we only support sizes of 4. If we want to support different sizes
|
||||
// some more complicated bookkeeping should be added.
|
||||
MOZ_ASSERT(aSize == sSupportedBlockSize);
|
||||
@ -277,6 +292,11 @@ ISurfaceAllocator::AllocShmemSection(size_t aSize, mozilla::layers::ShmemSection
|
||||
void
|
||||
ISurfaceAllocator::FreeShmemSection(mozilla::layers::ShmemSection& aShmemSection)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aShmemSection.size() == sSupportedBlockSize);
|
||||
MOZ_ASSERT(aShmemSection.offset() < sShmemPageSize - sSupportedBlockSize);
|
||||
|
||||
@ -301,6 +321,10 @@ ISurfaceAllocator::FreeShmemSection(mozilla::layers::ShmemSection& aShmemSection
|
||||
void
|
||||
ISurfaceAllocator::ShrinkShmemSectionHeap()
|
||||
{
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The loop will terminate as we either increase i, or decrease size
|
||||
// every time through.
|
||||
size_t i = 0;
|
||||
@ -327,18 +351,33 @@ ISurfaceAllocator::AllocGrallocBuffer(const gfx::IntSize& aSize,
|
||||
uint32_t aUsage,
|
||||
MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SharedBufferManagerChild::GetSingleton()->AllocGrallocBuffer(aSize, aFormat, aUsage, aHandle);
|
||||
}
|
||||
|
||||
void
|
||||
ISurfaceAllocator::DeallocGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharedBufferManagerChild::GetSingleton()->DeallocGrallocBuffer(*aHandle);
|
||||
}
|
||||
|
||||
void
|
||||
ISurfaceAllocator::DropGrallocBuffer(MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
MOZ_ASSERT(IPCOpen());
|
||||
if (!IPCOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharedBufferManagerChild::GetSingleton()->DropGrallocBuffer(*aHandle);
|
||||
}
|
||||
|
||||
|
@ -459,6 +459,10 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
||||
edit.get_OpSetDiagnosticTypes().diagnostics());
|
||||
break;
|
||||
}
|
||||
case Edit::TOpWindowOverlayChanged: {
|
||||
mLayerManager->SetWindowOverlayChanged();
|
||||
break;
|
||||
}
|
||||
// Tree ops
|
||||
case Edit::TOpSetRoot: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] SetRoot"));
|
||||
|
@ -299,6 +299,7 @@ struct OpRepositionChild { PLayer container; PLayer childLayer; PLayer after; }
|
||||
struct OpRaiseToTopChild { PLayer container; PLayer childLayer; };
|
||||
|
||||
struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
|
||||
struct OpWindowOverlayChanged { };
|
||||
|
||||
struct ShmemSection {
|
||||
Shmem shmem;
|
||||
@ -457,6 +458,7 @@ union Edit {
|
||||
|
||||
OpSetLayerAttributes;
|
||||
OpSetDiagnosticTypes;
|
||||
OpWindowOverlayChanged;
|
||||
|
||||
OpSetRoot;
|
||||
OpInsertAfter;
|
||||
|
@ -25,10 +25,10 @@
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "gfxEnv.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ERROR
|
||||
#include "prenv.h" // for PR_GetEnv
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
@ -45,7 +45,7 @@ namespace layers {
|
||||
static bool
|
||||
UsingXCompositing()
|
||||
{
|
||||
if (!PR_GetEnv("MOZ_LAYERS_ENABLE_XLIB_SURFACES")) {
|
||||
if (!gfxEnv::LayersEnableXlibSurfaces()) {
|
||||
return false;
|
||||
}
|
||||
return (gfxSurfaceType::Xlib ==
|
||||
|
@ -530,10 +530,13 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
||||
mDiagnosticTypes = diagnostics;
|
||||
mTxn->AddEdit(OpSetDiagnosticTypes(diagnostics));
|
||||
}
|
||||
if (mWindowOverlayChanged) {
|
||||
mTxn->AddEdit(OpWindowOverlayChanged());
|
||||
}
|
||||
|
||||
AutoTxnEnd _(mTxn);
|
||||
|
||||
if (mTxn->Empty() && !mTxn->RotationChanged() && !mWindowOverlayChanged) {
|
||||
if (mTxn->Empty() && !mTxn->RotationChanged()) {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?) and no rotation event, skipping Update()"));
|
||||
return true;
|
||||
}
|
||||
@ -629,7 +632,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
|
||||
|
||||
AutoInfallibleTArray<Edit, 10> cset;
|
||||
size_t nCsets = mTxn->mCset.size() + mTxn->mPaints.size();
|
||||
MOZ_ASSERT(nCsets > 0 || mWindowOverlayChanged || mTxn->RotationChanged(), "should have bailed by now");
|
||||
MOZ_ASSERT(nCsets > 0 || mTxn->RotationChanged(), "should have bailed by now");
|
||||
|
||||
cset.SetCapacity(nCsets);
|
||||
if (!mTxn->mCset.empty()) {
|
||||
|
@ -67,7 +67,7 @@ SharedPlanarYCbCrImage::GetTextureClient(CompositableClient* aClient)
|
||||
uint8_t*
|
||||
SharedPlanarYCbCrImage::GetBuffer()
|
||||
{
|
||||
return mTextureClient->GetBuffer();
|
||||
return mTextureClient ? mTextureClient->GetBuffer() : nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
@ -135,6 +135,9 @@ void
|
||||
SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
|
||||
{
|
||||
MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
|
||||
if (!mTextureClient) {
|
||||
return;
|
||||
}
|
||||
mData = aData;
|
||||
mSize = aData.mPicSize;
|
||||
/* SetDataNoCopy is used to update YUV plane offsets without (re)allocating
|
||||
|
@ -13,10 +13,11 @@
|
||||
#include "Layers.h" // for WriteSnapshotToDumpFile
|
||||
#include "LayerScope.h" // for LayerScope
|
||||
#include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
|
||||
#include "gfxEnv.h" // for gfxEnv
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/ArrayUtils.h" // for ArrayLength
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||
@ -104,14 +105,14 @@ CompositorOGL::CreateContext()
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
|
||||
if (gfxEnv::LayersPreferEGL()) {
|
||||
printf_stderr("Trying GL layers...\n");
|
||||
context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allow to create offscreen GL context for main Layer Manager
|
||||
if (!context && PR_GetEnv("MOZ_LAYERS_PREFER_OFFSCREEN")) {
|
||||
if (!context && gfxEnv::LayersPreferOffscreen()) {
|
||||
SurfaceCaps caps = SurfaceCaps::ForRGB();
|
||||
caps.preserve = false;
|
||||
caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565;
|
||||
@ -1388,7 +1389,7 @@ CompositorOGL::EndFrame()
|
||||
MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpCompositorTextures) {
|
||||
if (gfxEnv::DumpCompositorTextures()) {
|
||||
IntRect rect;
|
||||
if (mUseExternalSurfaceSize) {
|
||||
rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include "OGLShaderProgram.h"
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <sstream> // for ostringstream
|
||||
#include "gfxEnv.h"
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "mozilla/DebugOnly.h" // for DebugOnly
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsString.h" // for nsAutoCString
|
||||
#include "prenv.h" // for PR_GetEnv
|
||||
#include "Layers.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
@ -577,7 +577,7 @@ ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource)
|
||||
*/
|
||||
if (!success
|
||||
#ifdef DEBUG
|
||||
|| (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS"))
|
||||
|| (len > 10 && gfxEnv::DebugShaders())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
@ -630,7 +630,7 @@ ShaderProgramOGL::CreateProgram(const char *aVertexShaderString,
|
||||
*/
|
||||
if (!success
|
||||
#ifdef DEBUG
|
||||
|| (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS"))
|
||||
|| (len > 10 && gfxEnv::DebugShaders())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
* 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 "DriverCrashGuard.h"
|
||||
#include "gfxEnv.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
@ -71,8 +72,7 @@ DriverCrashGuard::Initialize()
|
||||
}
|
||||
|
||||
// Check to see if all guards have been disabled through the environment.
|
||||
static bool sAllGuardsDisabled = !!PR_GetEnv("MOZ_DISABLE_CRASH_GUARD");
|
||||
if (sAllGuardsDisabled) {
|
||||
if (gfxEnv::DisableCrashGuard()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1405,6 +1405,7 @@ gfxContext::GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY)
|
||||
DWRITE_MEASURING_MODE_NATURAL) {
|
||||
return;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
#endif
|
||||
case CAIRO_FONT_TYPE_QUARTZ:
|
||||
// Quartz surfaces implement show_glyphs for Quartz fonts
|
||||
@ -1412,13 +1413,13 @@ gfxContext::GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY)
|
||||
CAIRO_SURFACE_TYPE_QUARTZ) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// fall through:
|
||||
break;
|
||||
case CAIRO_HINT_METRICS_ON:
|
||||
break;
|
||||
}
|
||||
*aRoundX = true;
|
||||
return;
|
||||
}
|
||||
|
124
gfx/thebes/gfxEnv.h
Normal file
124
gfx/thebes/gfxEnv.h
Normal file
@ -0,0 +1,124 @@
|
||||
/* -*- Mode: C++; tab-width: 20; 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 GFX_ENV_H
|
||||
#define GFX_ENV_H
|
||||
|
||||
#include "prenv.h"
|
||||
|
||||
// To register the check for an environment variable existence (and not empty),
|
||||
// add a line in this file using the DECL_GFX_ENV macro.
|
||||
//
|
||||
// For example this line in the .h:
|
||||
// DECL_GFX_ENV_ONCE("MOZ_DISABLE_CONTEXT_SHARING_GLX",DisableContextSharingGLX);
|
||||
// means that you can call
|
||||
// bool var = gfxEnv::DisableContextSharingGLX();
|
||||
// and that the value will be checked only once, first time we call it, then cached.
|
||||
|
||||
#define DECL_GFX_ENV_LIVE(Env, Name) \
|
||||
static bool Name() { \
|
||||
return IsEnvSet(Env); \
|
||||
}
|
||||
|
||||
#define DECL_GFX_ENV_ONCE(Env, Name) \
|
||||
static bool Name() { \
|
||||
static bool isSet = IsEnvSet(Env);\
|
||||
return isSet; \
|
||||
}
|
||||
|
||||
class gfxEnv final
|
||||
{
|
||||
public:
|
||||
// This is where DECL_GFX_ENV for each of the environment variables should go.
|
||||
// We will keep these in an alphabetical order by the environment variable,
|
||||
// to make it easier to see if a method accessing an entry already exists.
|
||||
// Just insert yours in the list.
|
||||
|
||||
// Debugging inside of ContainerLayerComposite
|
||||
DECL_GFX_ENV_LIVE("DUMP_DEBUG", DumpDebug);
|
||||
|
||||
// OpenGL shader debugging in OGLShaderProgram, in DEBUG only
|
||||
DECL_GFX_ENV_LIVE("MOZ_DEBUG_SHADERS", DebugShaders);
|
||||
|
||||
// Disabling context sharing in GLContextProviderGLX
|
||||
DECL_GFX_ENV_ONCE("MOZ_DISABLE_CONTEXT_SHARING_GLX", DisableContextSharingGlx);
|
||||
|
||||
// Disabling the crash guard in DriverCrashGuard
|
||||
DECL_GFX_ENV_ONCE("MOZ_DISABLE_CRASH_GUARD", DisableCrashGuard);
|
||||
|
||||
// Together with paint dumping, only when MOZ_DUMP_PAINTING is defined.
|
||||
// Dumping compositor textures is broken pretty badly. For example,
|
||||
// on Linux it crashes TextureHost::GetAsSurface() returns null.
|
||||
// Expect to have to fix things like this if you turn it on.
|
||||
// Meanwhile, content-side texture dumping
|
||||
// (conditioned on DebugDumpPainting()) is a good replacement.
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_COMPOSITOR_TEXTURES", DumpCompositorTextures);
|
||||
|
||||
// Dumping the layer list in LayerSorter
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_LAYER_SORT_LIST", DumpLayerSortList);
|
||||
|
||||
// Paint dumping, only when MOZ_DUMP_PAINTING is defined.
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_PAINT", DumpPaint);
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_PAINT_INTERMEDIATE", DumpPaintIntermediate);
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_PAINT_ITEMS", DumpPaintItems);
|
||||
DECL_GFX_ENV_ONCE("MOZ_DUMP_PAINT_TO_FILE", DumpPaintToFile);
|
||||
|
||||
// Force double buffering in ContentClient
|
||||
DECL_GFX_ENV_LIVE("MOZ_FORCE_DOUBLE_BUFFERING", ForceDoubleBuffering);
|
||||
|
||||
// Force gfxCrash to use MOZ_CRASH in Beta and Release
|
||||
DECL_GFX_ENV_ONCE("MOZ_GFX_CRASH_MOZ_CRASH", GfxCrashMozCrash);
|
||||
// Force gfxCrash to use telemetry in Nightly and Aurora
|
||||
DECL_GFX_ENV_ONCE("MOZ_GFX_CRASH_TELEMETRY", GfxCrashTelemetry);
|
||||
|
||||
DECL_GFX_ENV_LIVE("MOZ_GFX_VR_NO_DISTORTION", VRNoDistortion);
|
||||
|
||||
// Debugging in GLContext
|
||||
DECL_GFX_ENV_LIVE("MOZ_GL_DEBUG", GlDebug);
|
||||
DECL_GFX_ENV_LIVE("MOZ_GL_DEBUG_VERBOSE", GlDebugVerbose);
|
||||
DECL_GFX_ENV_LIVE("MOZ_GL_DEBUG_ABORT_ON_ERROR", GlDebugAbortOnError);
|
||||
|
||||
// Count GL extensions
|
||||
DECL_GFX_ENV_ONCE("MOZ_GL_DUMP_EXTS", GlDumpExtensions);
|
||||
|
||||
// Very noisy GLContext and GLContextProviderELG
|
||||
DECL_GFX_ENV_ONCE("MOZ_GL_SPEW", GlSpew);
|
||||
|
||||
// Do extra work before and after each GLX call in GLContextProviderGLX
|
||||
DECL_GFX_ENV_LIVE("MOZ_GLX_DEBUG", GlxDebug);
|
||||
|
||||
// Use X compositing
|
||||
DECL_GFX_ENV_LIVE("MOZ_LAYERS_ENABLE_XLIB_SURFACES", LayersEnableXlibSurfaces);
|
||||
|
||||
// GL compositing on Windows
|
||||
DECL_GFX_ENV_LIVE("MOZ_LAYERS_PREFER_EGL", LayersPreferEGL);
|
||||
|
||||
// Offscreen GL context for main layer manager
|
||||
DECL_GFX_ENV_LIVE("MOZ_LAYERS_PREFER_OFFSCREEN", LayersPreferOffscreen);
|
||||
|
||||
// Stop the VR rendering
|
||||
DECL_GFX_ENV_LIVE("NO_VR_RENDERING", NoVRRendering);
|
||||
|
||||
// WARNING:
|
||||
// Please make sure that you've added your new envvar to the list above in
|
||||
// alphabetical order. Please do not just append it to the end of the list.
|
||||
|
||||
private:
|
||||
// Helper function, can be re-used in the other macros
|
||||
static bool IsEnvSet(const char* aName) {
|
||||
char* val = PR_GetEnv(aName);
|
||||
return (val != 0 && *val != '\0');
|
||||
}
|
||||
|
||||
gfxEnv() {};
|
||||
~gfxEnv() {};
|
||||
gfxEnv(const gfxEnv&) = delete;
|
||||
gfxEnv& operator=(const gfxEnv&) = delete;
|
||||
};
|
||||
|
||||
#undef DECL_GFX_ENV_LIVE
|
||||
#undef DECL_GFX_ENV_ONCE
|
||||
|
||||
#endif /* GFX_ENV_H */
|
@ -467,9 +467,14 @@ gfxFontShaper::MergeFontFeatures(
|
||||
// petite caps cases can fallback to appropriate smallcaps
|
||||
uint32_t variantCaps = aStyle->variantCaps;
|
||||
switch (variantCaps) {
|
||||
case NS_FONT_VARIANT_CAPS_NORMAL:
|
||||
break;
|
||||
|
||||
case NS_FONT_VARIANT_CAPS_ALLSMALL:
|
||||
mergedFeatures.Put(HB_TAG('c','2','s','c'), 1);
|
||||
// fall through to the small-caps case
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case NS_FONT_VARIANT_CAPS_SMALLCAPS:
|
||||
mergedFeatures.Put(HB_TAG('s','m','c','p'), 1);
|
||||
break;
|
||||
@ -477,11 +482,13 @@ gfxFontShaper::MergeFontFeatures(
|
||||
case NS_FONT_VARIANT_CAPS_ALLPETITE:
|
||||
mergedFeatures.Put(aAddSmallCaps ? HB_TAG('c','2','s','c') :
|
||||
HB_TAG('c','2','p','c'), 1);
|
||||
// fall through to the petite-caps case
|
||||
// fall through to the petite-caps case
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case NS_FONT_VARIANT_CAPS_PETITECAPS:
|
||||
mergedFeatures.Put(aAddSmallCaps ? HB_TAG('s','m','c','p') :
|
||||
HB_TAG('p','c','a','p'), 1);
|
||||
break;
|
||||
break;
|
||||
|
||||
case NS_FONT_VARIANT_CAPS_TITLING:
|
||||
mergedFeatures.Put(HB_TAG('t','i','t','l'), 1);
|
||||
@ -492,11 +499,14 @@ gfxFontShaper::MergeFontFeatures(
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected variantCaps");
|
||||
break;
|
||||
}
|
||||
|
||||
// font-variant-position - handled here due to the need for fallback
|
||||
switch (aStyle->variantSubSuper) {
|
||||
case NS_FONT_VARIANT_POSITION_NORMAL:
|
||||
break;
|
||||
case NS_FONT_VARIANT_POSITION_SUPER:
|
||||
mergedFeatures.Put(HB_TAG('s','u','p','s'), 1);
|
||||
break;
|
||||
@ -504,6 +514,7 @@ gfxFontShaper::MergeFontFeatures(
|
||||
mergedFeatures.Put(HB_TAG('s','u','b','s'), 1);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected variantSubSuper");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3004,6 +3015,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
||||
case kUppercaseReduce:
|
||||
// use reduced-size font, then fall through to uppercase the text
|
||||
f = smallCapsFont;
|
||||
MOZ_FALLTHROUGH;
|
||||
|
||||
case kUppercase:
|
||||
// apply uppercase transform to the string
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxEnv.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "gfxVR.h"
|
||||
|
||||
@ -310,12 +311,11 @@ CrashStatsLogForwarder::CrashAction(LogReason aReason)
|
||||
#ifndef RELEASE_BUILD
|
||||
// Non-release builds crash by default, but will use telemetry
|
||||
// if this environment variable is present.
|
||||
static bool useTelemetry = getenv("MOZ_GFX_CRASH_TELEMETRY") != 0;
|
||||
static bool useTelemetry = gfxEnv::GfxCrashTelemetry();
|
||||
#else
|
||||
// Release builds use telemetry bu default, but will crash
|
||||
// if this environment variable is present. Double negative
|
||||
// to make the intent clear.
|
||||
static bool useTelemetry = !(getenv("MOZ_GFX_CRASH_MOZ_CRASH") != 0);
|
||||
// Release builds use telemetry by default, but will crash instead
|
||||
// if this environment variable is present.
|
||||
static bool useTelemetry = !gfxEnv::GfxCrashMozCrash();
|
||||
#endif
|
||||
|
||||
if (useTelemetry) {
|
||||
|
@ -1717,6 +1717,7 @@ gfxFontGroup::FamilyFace::CheckState(bool& aSkipDrawing)
|
||||
case gfxUserFontEntry::STATUS_FAILED:
|
||||
SetInvalid();
|
||||
// fall-thru to the default case
|
||||
MOZ_FALLTHROUGH;
|
||||
default:
|
||||
SetLoading(false);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "cairo.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxEnv.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxDrawable.h"
|
||||
@ -1670,20 +1671,6 @@ gfxUtils::DumpDisplayList() {
|
||||
|
||||
FILE *gfxUtils::sDumpPaintFile = stderr;
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
bool gfxUtils::sDumpPainting = getenv("MOZ_DUMP_PAINT") != 0;
|
||||
bool gfxUtils::sDumpPaintingIntermediate = getenv("MOZ_DUMP_PAINT_INTERMEDIATE") != 0;
|
||||
bool gfxUtils::sDumpPaintingToFile = getenv("MOZ_DUMP_PAINT_TO_FILE") != 0;
|
||||
bool gfxUtils::sDumpPaintItems = getenv("MOZ_DUMP_PAINT_ITEMS") != 0;
|
||||
bool gfxUtils::sDumpCompositorTextures = getenv("MOZ_DUMP_COMPOSITOR_TEXTURES") != 0;
|
||||
#else
|
||||
bool gfxUtils::sDumpPainting = false;
|
||||
bool gfxUtils::sDumpPaintingIntermediate = false;
|
||||
bool gfxUtils::sDumpPaintingToFile = false;
|
||||
bool gfxUtils::sDumpPaintItems = false;
|
||||
bool gfxUtils::sDumpCompositorTextures = false;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
|
@ -305,16 +305,6 @@ public:
|
||||
|
||||
static bool DumpDisplayList();
|
||||
|
||||
static bool sDumpPainting;
|
||||
static bool sDumpPaintingIntermediate;
|
||||
static bool sDumpPaintingToFile;
|
||||
static bool sDumpPaintItems;
|
||||
// TODO: Dumping compositor textures is broken pretty badly. For example,
|
||||
// on Linux it crashes because TextureHost::GetAsSurface() returns
|
||||
// null. Expect to have to fix things like this if you turn it on.
|
||||
// Meanwhile, content-side texture dumping (conditioned on
|
||||
// sDumpPainting) is a good replacement.
|
||||
static bool sDumpCompositorTextures;
|
||||
static FILE* sDumpPaintFile;
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@ EXPORTS += [
|
||||
'gfxColor.h',
|
||||
'gfxContext.h',
|
||||
'gfxDrawable.h',
|
||||
'gfxEnv.h',
|
||||
'gfxFailure.h',
|
||||
'gfxFont.h',
|
||||
'gfxFontConstants.h',
|
||||
|
@ -246,12 +246,6 @@ DynamicImage::Draw(gfxContext* aContext,
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicImage::RequestDecode()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DynamicImage::StartDecoding()
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user