Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2016-11-17 14:46:26 +01:00
Родитель ddcb755bd0 e0ff800a74
Коммит 17a7875e17
84 изменённых файлов: 1852 добавлений и 892 удалений

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

@ -42,7 +42,23 @@ AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AccEvent cycle collection // AccEvent cycle collection
NS_IMPL_CYCLE_COLLECTION(AccEvent, mAccessible) NS_IMPL_CYCLE_COLLECTION_CLASS(AccEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AccEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessible)
if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
tmEvent->SetNextEvent(nullptr);
tmEvent->SetPrevEvent(nullptr);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AccEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessible)
if (AccTreeMutationEvent* tmEvent = downcast_accEvent(tmp)) {
CycleCollectionNoteChild(cb, tmEvent->NextEvent(), "mNext");
CycleCollectionNoteChild(cb, tmEvent->PrevEvent(), "mPrevEvent");
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AccEvent, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)

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

@ -94,6 +94,7 @@ public:
eGenericEvent, eGenericEvent,
eStateChangeEvent, eStateChangeEvent,
eTextChangeEvent, eTextChangeEvent,
eTreeMutationEvent,
eMutationEvent, eMutationEvent,
eReorderEvent, eReorderEvent,
eHideEvent, eHideEvent,
@ -129,6 +130,7 @@ protected:
friend class EventQueue; friend class EventQueue;
friend class EventTree; friend class EventTree;
friend class ::nsEventShell; friend class ::nsEventShell;
friend class NotificationController;
}; };
@ -200,17 +202,51 @@ private:
nsString mModifiedText; nsString mModifiedText;
friend class EventTree; friend class EventTree;
friend class NotificationController;
}; };
/**
* A base class for events related to tree mutation, either an AccMutation
* event, or an AccReorderEvent.
*/
class AccTreeMutationEvent : public AccEvent
{
public:
AccTreeMutationEvent(uint32_t aEventType, Accessible* aTarget) :
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder), mGeneration(0) {}
// Event
static const EventGroup kEventGroup = eTreeMutationEvent;
virtual unsigned int GetEventGroups() const override
{
return AccEvent::GetEventGroups() | (1U << eTreeMutationEvent);
}
void SetNextEvent(AccTreeMutationEvent* aNext) { mNextEvent = aNext; }
void SetPrevEvent(AccTreeMutationEvent* aPrev) { mPrevEvent = aPrev; }
AccTreeMutationEvent* NextEvent() const { return mNextEvent; }
AccTreeMutationEvent* PrevEvent() const { return mPrevEvent; }
/**
* A sequence number to know when this event was fired.
*/
uint32_t EventGeneration() const { return mGeneration; }
void SetEventGeneration(uint32_t aGeneration) { mGeneration = aGeneration; }
private:
RefPtr<AccTreeMutationEvent> mNextEvent;
RefPtr<AccTreeMutationEvent> mPrevEvent;
uint32_t mGeneration;
};
/** /**
* Base class for show and hide accessible events. * Base class for show and hide accessible events.
*/ */
class AccMutationEvent: public AccEvent class AccMutationEvent: public AccTreeMutationEvent
{ {
public: public:
AccMutationEvent(uint32_t aEventType, Accessible* aTarget) : AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceReorder) AccTreeMutationEvent(aEventType, aTarget)
{ {
// Don't coalesce these since they are coalesced by reorder event. Coalesce // Don't coalesce these since they are coalesced by reorder event. Coalesce
// contained text change events. // contained text change events.
@ -222,7 +258,7 @@ public:
static const EventGroup kEventGroup = eMutationEvent; static const EventGroup kEventGroup = eMutationEvent;
virtual unsigned int GetEventGroups() const override virtual unsigned int GetEventGroups() const override
{ {
return AccEvent::GetEventGroups() | (1U << eMutationEvent); return AccTreeMutationEvent::GetEventGroups() | (1U << eMutationEvent);
} }
// MutationEvent // MutationEvent
@ -237,6 +273,7 @@ protected:
RefPtr<AccTextChangeEvent> mTextChangeEvent; RefPtr<AccTextChangeEvent> mTextChangeEvent;
friend class EventTree; friend class EventTree;
friend class NotificationController;
}; };
@ -267,6 +304,7 @@ protected:
RefPtr<Accessible> mPrevSibling; RefPtr<Accessible> mPrevSibling;
friend class EventTree; friend class EventTree;
friend class NotificationController;
}; };
@ -298,19 +336,18 @@ private:
/** /**
* Class for reorder accessible event. Takes care about * Class for reorder accessible event. Takes care about
*/ */
class AccReorderEvent : public AccEvent class AccReorderEvent : public AccTreeMutationEvent
{ {
public: public:
explicit AccReorderEvent(Accessible* aTarget) : explicit AccReorderEvent(Accessible* aTarget) :
AccEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget, AccTreeMutationEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget) { }
eAutoDetect, eCoalesceReorder) { }
virtual ~AccReorderEvent() { } virtual ~AccReorderEvent() { }
// Event // Event
static const EventGroup kEventGroup = eReorderEvent; static const EventGroup kEventGroup = eReorderEvent;
virtual unsigned int GetEventGroups() const override virtual unsigned int GetEventGroups() const override
{ {
return AccEvent::GetEventGroups() | (1U << eReorderEvent); return AccTreeMutationEvent::GetEventGroups() | (1U << eReorderEvent);
} }
}; };

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

@ -25,7 +25,8 @@ EventTree* const TreeMutation::kNoEventTree = reinterpret_cast<EventTree*>(-1);
TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) : TreeMutation::TreeMutation(Accessible* aParent, bool aNoEvents) :
mParent(aParent), mStartIdx(UINT32_MAX), mParent(aParent), mStartIdx(UINT32_MAX),
mStateFlagsCopy(mParent->mStateFlags), mStateFlagsCopy(mParent->mStateFlags),
mEventTree(aNoEvents ? kNoEventTree : nullptr) mEventTree(aNoEvents ? kNoEventTree : nullptr),
mQueueEvents(!aNoEvents)
{ {
#ifdef DEBUG #ifdef DEBUG
mIsDone = false; mIsDone = false;
@ -62,17 +63,14 @@ TreeMutation::AfterInsertion(Accessible* aChild)
mStartIdx = aChild->mIndexInParent + 1; mStartIdx = aChild->mIndexInParent + 1;
} }
if (!mEventTree) { if (!mQueueEvents) {
mEventTree = Controller()->QueueMutation(mParent); return;
if (!mEventTree) {
mEventTree = kNoEventTree;
}
} }
if (mEventTree != kNoEventTree) { RefPtr<AccShowEvent> ev = new AccShowEvent(aChild);
mEventTree->Shown(aChild); DebugOnly<bool> added = Controller()->QueueMutationEvent(ev);
Controller()->QueueNameChange(aChild); MOZ_ASSERT(added);
} aChild->SetShowEventTarget(true);
} }
void void
@ -84,16 +82,13 @@ TreeMutation::BeforeRemoval(Accessible* aChild, bool aNoShutdown)
mStartIdx = aChild->mIndexInParent; mStartIdx = aChild->mIndexInParent;
} }
if (!mEventTree) { if (!mQueueEvents) {
mEventTree = Controller()->QueueMutation(mParent); return;
if (!mEventTree) {
mEventTree = kNoEventTree;
}
} }
if (mEventTree != kNoEventTree) { RefPtr<AccHideEvent> ev = new AccHideEvent(aChild, !aNoShutdown);
mEventTree->Hidden(aChild, !aNoShutdown); if (Controller()->QueueMutationEvent(ev)) {
Controller()->QueueNameChange(aChild); aChild->SetHideEventTarget(true);
} }
} }

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

@ -49,6 +49,11 @@ private:
uint32_t mStateFlagsCopy; uint32_t mStateFlagsCopy;
EventTree* mEventTree; EventTree* mEventTree;
/*
* True if mutation events should be queued.
*/
bool mQueueEvents;
#ifdef DEBUG #ifdef DEBUG
bool mIsDone; bool mIsDone;
#endif #endif
@ -67,15 +72,19 @@ public:
mFireReorder(aFireReorder) { } mFireReorder(aFireReorder) { }
~EventTree() { Clear(); } ~EventTree() { Clear(); }
void Shown(Accessible* aChild); void Shown(Accessible* aTarget);
void Hidden(Accessible*, bool);
void Hidden(Accessible* aChild, bool aNeedsShutdown = true);
/** /**
* Return an event tree node for the given accessible. * Return an event tree node for the given accessible.
*/ */
const EventTree* Find(const Accessible* aContainer) const; const EventTree* Find(const Accessible* aContainer) const;
/**
* Add a mutation event to this event tree.
*/
void Mutated(AccMutationEvent* aEv);
#ifdef A11Y_LOG #ifdef A11Y_LOG
void Log(uint32_t aLevel = UINT32_MAX) const; void Log(uint32_t aLevel = UINT32_MAX) const;
#endif #endif
@ -91,7 +100,6 @@ private:
*/ */
EventTree* FindOrInsert(Accessible* aContainer); EventTree* FindOrInsert(Accessible* aContainer);
void Mutated(AccMutationEvent* aEv);
void Clear(); void Clear();
UniquePtr<EventTree> mFirst; UniquePtr<EventTree> mFirst;

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

@ -24,7 +24,7 @@ using namespace mozilla::a11y;
NotificationController::NotificationController(DocAccessible* aDocument, NotificationController::NotificationController(DocAccessible* aDocument,
nsIPresShell* aPresShell) : nsIPresShell* aPresShell) :
EventQueue(aDocument), mObservingState(eNotObservingRefresh), EventQueue(aDocument), mObservingState(eNotObservingRefresh),
mPresShell(aPresShell) mPresShell(aPresShell), mEventGeneration(0)
{ {
#ifdef DEBUG #ifdef DEBUG
mMoveGuardOnStack = false; mMoveGuardOnStack = false;
@ -114,6 +114,289 @@ NotificationController::QueueMutation(Accessible* aContainer)
return tree; return tree;
} }
bool
NotificationController::QueueMutationEvent(AccTreeMutationEvent* aEvent)
{
// We have to allow there to be a hide and then a show event for a target
// because of targets getting moved. However we need to coalesce a show and
// then a hide for a target which means we need to check for that here.
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
aEvent->GetAccessible()->ShowEventTarget()) {
AccTreeMutationEvent* showEvent = mMutationMap.GetEvent(aEvent->GetAccessible(), EventMap::ShowEvent);
DropMutationEvent(showEvent);
return false;
}
AccMutationEvent* mutEvent = downcast_accEvent(aEvent);
mEventGeneration++;
mutEvent->SetEventGeneration(mEventGeneration);
if (!mFirstMutationEvent) {
mFirstMutationEvent = aEvent;
ScheduleProcessing();
}
if (mLastMutationEvent) {
NS_ASSERTION(!mLastMutationEvent->NextEvent(), "why isn't the last event the end?");
mLastMutationEvent->SetNextEvent(aEvent);
}
aEvent->SetPrevEvent(mLastMutationEvent);
mLastMutationEvent = aEvent;
mMutationMap.PutEvent(aEvent);
// Because we could be hiding the target of a show event we need to get rid
// of any such events. It may be possible to do less than coallesce all
// events, however that is easiest.
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
CoalesceMutationEvents();
// mLastMutationEvent will point to something other than aEvent if and only
// if aEvent was just coalesced away. In that case a parent accessible
// must already have the required reorder and text change events so we are
// done here.
if (mLastMutationEvent != aEvent) {
return false;
}
}
// We need to fire a reorder event after all of the events targeted at shown or
// hidden children of a container. So either queue a new one, or move an
// existing one to the end of the queue if the container already has a
// reorder event.
Accessible* target = aEvent->GetAccessible();
Accessible* container = aEvent->GetAccessible()->Parent();
RefPtr<AccReorderEvent> reorder;
if (!container->ReorderEventTarget()) {
reorder = new AccReorderEvent(container);
container->SetReorderEventTarget(true);
mMutationMap.PutEvent(reorder);
// Since this is the first child of container that is changing, the name of
// container may be changing.
QueueNameChange(target);
} else {
AccReorderEvent* event = downcast_accEvent(mMutationMap.GetEvent(container, EventMap::ReorderEvent));
reorder = event;
if (mFirstMutationEvent == event) {
mFirstMutationEvent = event->NextEvent();
} else {
event->PrevEvent()->SetNextEvent(event->NextEvent());
}
event->NextEvent()->SetPrevEvent(event->PrevEvent());
event->SetNextEvent(nullptr);
}
reorder->SetEventGeneration(mEventGeneration);
reorder->SetPrevEvent(mLastMutationEvent);
mLastMutationEvent->SetNextEvent(reorder);
mLastMutationEvent = reorder;
// It is not possible to have a text change event for something other than a
// hyper text accessible.
if (!container->IsHyperText()) {
return true;
}
MOZ_ASSERT(mutEvent);
nsString text;
aEvent->GetAccessible()->AppendTextTo(text);
if (text.IsEmpty()) {
return true;
}
int32_t offset = container->AsHyperText()->GetChildOffset(target);
AccTreeMutationEvent* prevEvent = aEvent->PrevEvent();
while (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
prevEvent = prevEvent->PrevEvent();
}
if (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
mutEvent->IsHide()) {
AccHideEvent* prevHide = downcast_accEvent(prevEvent);
AccTextChangeEvent* prevTextChange = prevHide->mTextChangeEvent;
if (prevTextChange) {
if (prevHide->mNextSibling == target) {
target->AppendTextTo(prevTextChange->mModifiedText);
} else if (prevHide->mPrevSibling == target) {
nsString temp;
target->AppendTextTo(temp);
uint32_t extraLen = temp.Length();
temp += prevTextChange->mModifiedText;;
prevTextChange->mModifiedText = temp;
prevTextChange->mStart -= extraLen;
}
prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
}
} else if (prevEvent && mutEvent->IsShow() &&
prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
AccShowEvent* prevShow = downcast_accEvent(prevEvent);
AccTextChangeEvent* prevTextChange = prevShow->mTextChangeEvent;
if (prevTextChange) {
int32_t index = target->IndexInParent();
int32_t prevIndex = prevShow->GetAccessible()->IndexInParent();
if (prevIndex + 1 == index) {
target->AppendTextTo(prevTextChange->mModifiedText);
} else if (index + 1 == prevIndex) {
nsString temp;
target->AppendTextTo(temp);
prevTextChange->mStart -= temp.Length();
temp += prevTextChange->mModifiedText;
prevTextChange->mModifiedText = temp;
}
prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
}
}
if (!mutEvent->mTextChangeEvent) {
mutEvent->mTextChangeEvent =
new AccTextChangeEvent(container, offset, text, mutEvent->IsShow(),
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}
return true;
}
void
NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
{
// unset the event bits since the event isn't being fired any more.
if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
aEvent->GetAccessible()->SetReorderEventTarget(false);
} else if (aEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
aEvent->GetAccessible()->SetShowEventTarget(false);
} else {
AccHideEvent* hideEvent = downcast_accEvent(aEvent);
MOZ_ASSERT(hideEvent);
if (hideEvent->NeedsShutdown()) {
mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
}
}
// Do the work to splice the event out of the list.
if (mFirstMutationEvent == aEvent) {
mFirstMutationEvent = aEvent->NextEvent();
} else {
aEvent->PrevEvent()->SetNextEvent(aEvent->NextEvent());
}
if (mLastMutationEvent == aEvent) {
mLastMutationEvent = aEvent->PrevEvent();
} else {
aEvent->NextEvent()->SetPrevEvent(aEvent->PrevEvent());
}
aEvent->SetPrevEvent(nullptr);
aEvent->SetNextEvent(nullptr);
mMutationMap.RemoveEvent(aEvent);
}
void
NotificationController::CoalesceMutationEvents()
{
AccTreeMutationEvent* event = mFirstMutationEvent;
while (event) {
AccTreeMutationEvent* nextEvent = event->NextEvent();
uint32_t eventType = event->GetEventType();
if (event->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
Accessible* acc = event->GetAccessible();
while (acc) {
if (acc->IsDoc()) {
break;
}
// if a parent of the reorder event's target is being hidden that
// hide event's target must have a parent that is also a reorder event
// target. That means we don't need this reorder event.
if (acc->HideEventTarget()) {
DropMutationEvent(event);
break;
}
Accessible* parent = acc->Parent();
if (parent->ReorderEventTarget()) {
AccReorderEvent* reorder = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ReorderEvent));
// We want to make sure that a reorder event comes after any show or
// hide events targeted at the children of its target. We keep the
// invariant that event generation goes up as you are farther in the
// queue, so we want to use the spot of the event with the higher
// generation number, and keep that generation number.
if (reorder && reorder->EventGeneration() < event->EventGeneration()) {
// There really should be a show or hide event before the first
// reorder event.
if (reorder->PrevEvent()) {
reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
} else {
mFirstMutationEvent = reorder->NextEvent();
}
reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
event->PrevEvent()->SetNextEvent(reorder);
reorder->SetPrevEvent(event->PrevEvent());
event->SetPrevEvent(reorder);
reorder->SetNextEvent(event);
reorder->SetEventGeneration(event->EventGeneration());
}
DropMutationEvent(event);
break;
}
acc = parent;
}
} else if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
Accessible* parent = event->GetAccessible()->Parent();
while (parent) {
if (parent->IsDoc()) {
break;
}
// if the parent of a show event is being either shown or hidden then
// we don't need to fire a show event for a subtree of that change.
if (parent->ShowEventTarget() || parent->HideEventTarget()) {
DropMutationEvent(event);
break;
}
parent = parent->Parent();
}
} else {
MOZ_ASSERT(eventType == nsIAccessibleEvent::EVENT_HIDE, "mutation event list has an invalid event");
AccHideEvent* hideEvent = downcast_accEvent(event);
Accessible* parent = hideEvent->Parent();
while (parent) {
if (parent->IsDoc()) {
break;
}
if (parent->HideEventTarget()) {
DropMutationEvent(event);
break;
}
if (parent->ShowEventTarget()) {
AccShowEvent* showEvent = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ShowEvent));
if (showEvent->EventGeneration() < hideEvent->EventGeneration()) {
DropMutationEvent(hideEvent);
break;
}
}
parent = parent->Parent();
}
}
event = nextEvent;
}
}
void void
NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument) NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
{ {
@ -172,6 +455,128 @@ NotificationController::IsUpdatePending()
!mDocument->HasLoadState(DocAccessible::eTreeConstructed); !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
} }
void
NotificationController::ProcessMutationEvents()
{
// there is no reason to fire a hide event for a child of a show event
// target. That can happen if something is inserted into the tree and
// removed before the next refresh driver tick, but it should not be
// observable outside gecko so it should be safe to coalesce away any such
// events. This means that it should be fine to fire all of the hide events
// first, and then deal with any shown subtrees.
for (AccTreeMutationEvent* event = mFirstMutationEvent;
event; event = event->NextEvent()) {
if (event->GetEventType() != nsIAccessibleEvent::EVENT_HIDE) {
continue;
}
nsEventShell::FireEvent(event);
if (!mDocument) {
return;
}
AccMutationEvent* mutEvent = downcast_accEvent(event);
if (mutEvent->mTextChangeEvent) {
nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
if (!mDocument) {
return;
}
}
// Fire menupopup end event before a hide event if a menu goes away.
// XXX: We don't look into children of hidden subtree to find hiding
// menupopup (as we did prior bug 570275) because we don't do that when
// menu is showing (and that's impossible until bug 606924 is fixed).
// Nevertheless we should do this at least because layout coalesces
// the changes before our processing and we may miss some menupopup
// events. Now we just want to be consistent in content insertion/removal
// handling.
if (event->mAccessible->ARIARole() == roles::MENUPOPUP) {
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
event->mAccessible);
if (!mDocument) {
return;
}
}
AccHideEvent* hideEvent = downcast_accEvent(event);
if (hideEvent->NeedsShutdown()) {
mDocument->ShutdownChildrenInSubtree(event->mAccessible);
}
}
// Group the show events by the parent of their target.
nsDataHashtable<nsPtrHashKey<Accessible>, nsTArray<AccTreeMutationEvent*>> showEvents;
for (AccTreeMutationEvent* event = mFirstMutationEvent;
event; event = event->NextEvent()) {
if (event->GetEventType() != nsIAccessibleEvent::EVENT_SHOW) {
continue;
}
Accessible* parent = event->GetAccessible()->Parent();
showEvents.GetOrInsert(parent).AppendElement(event);
}
// We need to fire show events for the children of an accessible in the order
// of their indices at this point. So sort each set of events for the same
// container by the index of their target.
for (auto iter = showEvents.Iter(); !iter.Done(); iter.Next()) {
struct AccIdxComparator {
bool LessThan(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
{
int32_t aIdx = a->GetAccessible()->IndexInParent();
int32_t bIdx = b->GetAccessible()->IndexInParent();
MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
return aIdx < bIdx;
}
bool Equals(const AccTreeMutationEvent* a, const AccTreeMutationEvent* b) const
{
DebugOnly<int32_t> aIdx = a->GetAccessible()->IndexInParent();
DebugOnly<int32_t> bIdx = b->GetAccessible()->IndexInParent();
MOZ_ASSERT(aIdx >= 0 && bIdx >= 0 && aIdx != bIdx);
return false;
}
};
nsTArray<AccTreeMutationEvent*>& events = iter.Data();
events.Sort(AccIdxComparator());
for (AccTreeMutationEvent* event: events) {
nsEventShell::FireEvent(event);
if (!mDocument) {
return;
}
AccMutationEvent* mutEvent = downcast_accEvent(event);
if (mutEvent->mTextChangeEvent) {
nsEventShell::FireEvent(mutEvent->mTextChangeEvent);
if (!mDocument) {
return;
}
}
}
}
// Now we can fire the reorder events after all the show and hide events.
for (AccTreeMutationEvent* event = mFirstMutationEvent;
event; event = event->NextEvent()) {
if (event->GetEventType() != nsIAccessibleEvent::EVENT_REORDER) {
continue;
}
nsEventShell::FireEvent(event);
if (!mDocument) {
return;
}
Accessible* target = event->GetAccessible();
target->Document()->MaybeNotifyOfValueChange(target);
if (!mDocument) {
return;
}
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// NotificationCollector: private // NotificationCollector: private
@ -397,9 +802,39 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// events causes script to run. // events causes script to run.
mObservingState = eRefreshProcessing; mObservingState = eRefreshProcessing;
RefPtr<DocAccessible> deathGrip(mDocument); CoalesceMutationEvents();
mEventTree.Process(deathGrip); ProcessMutationEvents();
deathGrip = nullptr; mEventGeneration = 0;
// Now that we are done with them get rid of the events we fired.
RefPtr<AccTreeMutationEvent> mutEvent = Move(mFirstMutationEvent);
mLastMutationEvent = nullptr;
mFirstMutationEvent = nullptr;
while (mutEvent) {
RefPtr<AccTreeMutationEvent> nextEvent = mutEvent->NextEvent();
Accessible* target = mutEvent->GetAccessible();
// We need to be careful here, while it may seem that we can simply 0 all
// the pending event bits that is not true. Because accessibles may be
// reparented they may be the target of both a hide event and a show event
// at the same time.
if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
target->SetShowEventTarget(false);
}
if (mutEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE) {
target->SetHideEventTarget(false);
}
// However it is not possible for a reorder event target to also be the
// target of a show or hide, so we can just zero that.
target->SetReorderEventTarget(false);
mutEvent->SetPrevEvent(nullptr);
mutEvent->SetNextEvent(nullptr);
mMutationMap.RemoveEvent(mutEvent);
mutEvent = nextEvent;
}
ProcessEventQueue(); ProcessEventQueue();
@ -449,3 +884,52 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
mObservingState = eNotObservingRefresh; mObservingState = eNotObservingRefresh;
} }
} }
void
NotificationController::EventMap::PutEvent(AccTreeMutationEvent* aEvent)
{
EventType type = GetEventType(aEvent);
uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
addr |= type;
mTable.Put(addr, aEvent);
}
AccTreeMutationEvent*
NotificationController::EventMap::GetEvent(Accessible* aTarget, EventType aType)
{
uint64_t addr = reinterpret_cast<uintptr_t>(aTarget);
MOZ_ASSERT((addr & 0x3) == 0, "target is not 4 byte aligned");
addr |= aType;
return mTable.GetWeak(addr);
}
void
NotificationController::EventMap::RemoveEvent(AccTreeMutationEvent* aEvent)
{
EventType type = GetEventType(aEvent);
uint64_t addr = reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
MOZ_ASSERT((addr & 0x3) == 0, "accessible is not 4 byte aligned");
addr |= type;
MOZ_ASSERT(mTable.GetWeak(addr) == aEvent, "mTable has the wrong event");
mTable.Remove(addr);
}
NotificationController::EventMap::EventType
NotificationController::EventMap::GetEventType(AccTreeMutationEvent* aEvent)
{
switch(aEvent->GetEventType())
{
case nsIAccessibleEvent::EVENT_SHOW:
return ShowEvent;
case nsIAccessibleEvent::EVENT_HIDE:
return HideEvent;
case nsIAccessibleEvent::EVENT_REORDER:
return ReorderEvent;
default:
MOZ_ASSERT_UNREACHABLE("event has invalid type");
return ShowEvent;
}
}

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

@ -159,6 +159,17 @@ public:
const EventTree& RootEventTree() const { return mEventTree; }; const EventTree& RootEventTree() const { return mEventTree; };
#endif #endif
/**
* Queue a mutation event to emit if not coalesced away. Returns true if the
* event was queued and has not yet been coalesced.
*/
bool QueueMutationEvent(AccTreeMutationEvent* aEvent);
/**
* Coalesce all queued mutation events.
*/
void CoalesceMutationEvents();
/** /**
* Schedule binding the child document to the tree of this document. * Schedule binding the child document to the tree of this document.
*/ */
@ -291,6 +302,16 @@ private:
} }
private: private:
/**
* get rid of a mutation event that is no longer necessary.
*/
void DropMutationEvent(AccTreeMutationEvent* aEvent);
/**
* Fire all necessary mutation events.
*/
void ProcessMutationEvents();
/** /**
* Indicates whether we're waiting on an event queue processing from our * Indicates whether we're waiting on an event queue processing from our
* notification controller to flush events. * notification controller to flush events.
@ -376,6 +397,40 @@ private:
friend class MoveGuard; friend class MoveGuard;
friend class EventTree; friend class EventTree;
/**
* A list of all mutation events we may want to emit. Ordered from the first
* event that should be emitted to the last one to emit.
*/
RefPtr<AccTreeMutationEvent> mFirstMutationEvent;
RefPtr<AccTreeMutationEvent> mLastMutationEvent;
/**
* A class to map an accessible and event type to an event.
*/
class EventMap
{
public:
enum EventType
{
ShowEvent = 0x0,
HideEvent = 0x1,
ReorderEvent = 0x2,
};
void PutEvent(AccTreeMutationEvent* aEvent);
AccTreeMutationEvent* GetEvent(Accessible* aTarget, EventType aType);
void RemoveEvent(AccTreeMutationEvent* aEvent);
void Clear() { mTable.Clear(); }
private:
EventType GetEventType(AccTreeMutationEvent* aEvent);
nsRefPtrHashtable<nsUint64HashKey, AccTreeMutationEvent> mTable;
};
EventMap mMutationMap;
uint32_t mEventGeneration;
}; };
} // namespace a11y } // namespace a11y

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

@ -109,7 +109,8 @@ Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
mContent(aContent), mDoc(aDoc), mContent(aContent), mDoc(aDoc),
mParent(nullptr), mIndexInParent(-1), mParent(nullptr), mIndexInParent(-1),
mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX), mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX),
mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0) mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false)
{ {
mBits.groupInfo = nullptr; mBits.groupInfo = nullptr;
mInt.mIndexOfEmbeddedChild = -1; mInt.mIndexOfEmbeddedChild = -1;
@ -2157,9 +2158,9 @@ Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
"No move, same index"); "No move, same index");
MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given"); MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
EventTree* eventTree = mDoc->Controller()->QueueMutation(this); RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
if (eventTree) { if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
eventTree->Hidden(aChild, false); aChild->SetHideEventTarget(true);
} }
mEmbeddedObjCollector = nullptr; mEmbeddedObjCollector = nullptr;
@ -2191,10 +2192,10 @@ Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1; mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
} }
if (eventTree) { RefPtr<AccShowEvent> showEvent = new AccShowEvent(aChild);
eventTree->Shown(aChild); DebugOnly<bool> added = mDoc->Controller()->QueueMutationEvent(showEvent);
mDoc->Controller()->QueueNameChange(aChild); MOZ_ASSERT(added);
} aChild->SetShowEventTarget(true);
} }
Accessible* Accessible*

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

@ -956,6 +956,36 @@ public:
*/ */
bool IsInsideAlert() const { return mContextFlags & eInsideAlert; } bool IsInsideAlert() const { return mContextFlags & eInsideAlert; }
/**
* Return true if there is a pending reorder event for this accessible.
*/
bool ReorderEventTarget() const { return mReorderEventTarget; }
/**
* Return true if there is a pending show event for this accessible.
*/
bool ShowEventTarget() const { return mShowEventTarget; }
/**
* Return true if there is a pending hide event for this accessible.
*/
bool HideEventTarget() const { return mHideEventTarget; }
/**
* Set if there is a pending reorder event for this accessible.
*/
void SetReorderEventTarget(bool aTarget) { mReorderEventTarget = aTarget; }
/**
* Set if this accessible is a show event target.
*/
void SetShowEventTarget(bool aTarget) { mShowEventTarget = aTarget; }
/**
* Set if this accessible is a hide event target.
*/
void SetHideEventTarget(bool aTarget) { mHideEventTarget = aTarget; }
protected: protected:
virtual ~Accessible(); virtual ~Accessible();
@ -1132,6 +1162,9 @@ protected:
uint32_t mContextFlags : kContextFlagsBits; uint32_t mContextFlags : kContextFlagsBits;
uint32_t mType : kTypeBits; uint32_t mType : kTypeBits;
uint32_t mGenericTypes : kGenericTypesBits; uint32_t mGenericTypes : kGenericTypesBits;
uint32_t mReorderEventTarget : 1;
uint32_t mShowEventTarget : 1;
uint32_t mHideEventTarget : 1;
void StaticAsserts() const; void StaticAsserts() const;

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

@ -1860,8 +1860,8 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
"container", aContainer, "child", iter.Child(), nullptr); "container", aContainer, "child", iter.Child(), nullptr);
#endif #endif
mt.AfterInsertion(iter.Child());
CreateSubtree(iter.Child()); CreateSubtree(iter.Child());
mt.AfterInsertion(iter.Child());
continue; continue;
} }
@ -1907,10 +1907,10 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer, nsIContent* aNode)
if (!aContainer->InsertAfter(child, walker.Prev())) { if (!aContainer->InsertAfter(child, walker.Prev())) {
return; return;
} }
CreateSubtree(child);
mt.AfterInsertion(child); mt.AfterInsertion(child);
mt.Done(); mt.Done();
CreateSubtree(child);
FireEventsOnInsertion(aContainer); FireEventsOnInsertion(aContainer);
} }
} }

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

@ -85,7 +85,7 @@ DocAccessibleChildBase::ShowEvent(AccShowEvent* aShowEvent)
{ {
Accessible* parent = aShowEvent->Parent(); Accessible* parent = aShowEvent->Parent();
uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID()); uint64_t parentID = parent->IsDoc() ? 0 : reinterpret_cast<uint64_t>(parent->UniqueID());
uint32_t idxInParent = aShowEvent->InsertionIndex(); uint32_t idxInParent = aShowEvent->GetAccessible()->IndexInParent();
nsTArray<AccessibleData> shownTree; nsTArray<AccessibleData> shownTree;
ShowEventData data(parentID, idxInParent, shownTree); ShowEventData data(parentID, idxInParent, shownTree);
SerializeTree(aShowEvent->GetAccessible(), data.NewTree()); SerializeTree(aShowEvent->GetAccessible(), data.NewTree());

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

@ -1705,7 +1705,9 @@ function invokerChecker(aEventType, aTargetOrFunc, aTargetFuncArg, aIsAsync)
*/ */
function orderChecker() function orderChecker()
{ {
this.__proto__ = new invokerChecker(null, null, null, false); // XXX it doesn't actually work to inherit from invokerChecker, but maybe we
// should fix that?
// this.__proto__ = new invokerChecker(null, null, null, false);
} }
/** /**

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

@ -55,8 +55,8 @@
// related show event. // related show event.
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_SHOW, this.menuNode), new invokerChecker(EVENT_SHOW, this.menuNode),
new asyncInvokerChecker(EVENT_MENUPOPUP_START, this.menuNode), new invokerChecker(EVENT_REORDER, getNode(aParentMenuID)),
new invokerChecker(EVENT_REORDER, getNode(aParentMenuID)) new invokerChecker(EVENT_MENUPOPUP_START, this.menuNode)
]; ];
this.invoke = function showMenu_invoke() this.invoke = function showMenu_invoke()

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

@ -419,8 +419,8 @@
this.lb = getAccessible("t5_lb"); this.lb = getAccessible("t5_lb");
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, this.o),
new invokerChecker(EVENT_HIDE, this.b), new invokerChecker(EVENT_HIDE, this.b),
new invokerChecker(EVENT_HIDE, this.o),
new invokerChecker(EVENT_REORDER, "t5"), new invokerChecker(EVENT_REORDER, "t5"),
new unexpectedInvokerChecker(EVENT_HIDE, this.ofc), new unexpectedInvokerChecker(EVENT_HIDE, this.ofc),
new unexpectedInvokerChecker(EVENT_REORDER, this.o), new unexpectedInvokerChecker(EVENT_REORDER, this.o),
@ -539,8 +539,8 @@
new invokerChecker(EVENT_HIDE, getNode('t8_c1_child')), new invokerChecker(EVENT_HIDE, getNode('t8_c1_child')),
new invokerChecker(EVENT_HIDE, 't8_c2_moved'), new invokerChecker(EVENT_HIDE, 't8_c2_moved'),
new invokerChecker(EVENT_SHOW, 't8_c2_moved'), new invokerChecker(EVENT_SHOW, 't8_c2_moved'),
new invokerChecker(EVENT_REORDER, 't8_c2'),
new invokerChecker(EVENT_REORDER, 't8_c1'), new invokerChecker(EVENT_REORDER, 't8_c1'),
new invokerChecker(EVENT_REORDER, 't8_c2')
]; ];
this.invoke = function test8_invoke() this.invoke = function test8_invoke()
@ -578,13 +578,13 @@
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode('t9_c1_child')), new invokerChecker(EVENT_HIDE, getNode('t9_c1_child')),
new invokerChecker(EVENT_HIDE, getNode('t9_c2_child')),
new invokerChecker(EVENT_HIDE, 't9_c3_moved'), new invokerChecker(EVENT_HIDE, 't9_c3_moved'),
new invokerChecker(EVENT_HIDE, 't9_c2_moved'), new invokerChecker(EVENT_HIDE, 't9_c2_moved'),
new invokerChecker(EVENT_SHOW, 't9_c2_moved'), new invokerChecker(EVENT_SHOW, 't9_c2_moved'),
new invokerChecker(EVENT_REORDER, 't9_c1'),
new invokerChecker(EVENT_HIDE, getNode('t9_c2_child')),
new invokerChecker(EVENT_REORDER, 't9_c2'),
new invokerChecker(EVENT_REORDER, 't9_c3'), new invokerChecker(EVENT_REORDER, 't9_c3'),
new invokerChecker(EVENT_REORDER, 't9_c2'),
new invokerChecker(EVENT_REORDER, 't9_c1'),
new unexpectedInvokerChecker(EVENT_SHOW, 't9_c3_moved') new unexpectedInvokerChecker(EVENT_SHOW, 't9_c3_moved')
]; ];
@ -624,12 +624,12 @@
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode('t10_c1_child')), new invokerChecker(EVENT_HIDE, getNode('t10_c1_child')),
new invokerChecker(EVENT_HIDE, getNode('t10_c2_child')),
new invokerChecker(EVENT_HIDE, getNode('t10_c2_moved')), new invokerChecker(EVENT_HIDE, getNode('t10_c2_moved')),
new invokerChecker(EVENT_HIDE, getNode('t10_c3_moved')), new invokerChecker(EVENT_HIDE, getNode('t10_c3_moved')),
new invokerChecker(EVENT_SHOW, getNode('t10_c2_moved')), new invokerChecker(EVENT_SHOW, getNode('t10_c2_moved')),
new invokerChecker(EVENT_REORDER, 't10_c1'),
new invokerChecker(EVENT_HIDE, getNode('t10_c2_child')),
new invokerChecker(EVENT_REORDER, 't10_c2'), new invokerChecker(EVENT_REORDER, 't10_c2'),
new invokerChecker(EVENT_REORDER, 't10_c1'),
new invokerChecker(EVENT_REORDER, 't10_c3') new invokerChecker(EVENT_REORDER, 't10_c3')
]; ];
@ -659,9 +659,11 @@
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode('t11_c1_child')), new invokerChecker(EVENT_HIDE, getNode('t11_c1_child')),
new invokerChecker(EVENT_SHOW, 't11_c2_child'),
new invokerChecker(EVENT_HIDE, getNode('t11_c2')), new invokerChecker(EVENT_HIDE, getNode('t11_c2')),
new invokerChecker(EVENT_SHOW, 't11_c2'), new orderChecker(),
new asyncInvokerChecker(EVENT_SHOW, 't11_c2_child'),
new asyncInvokerChecker(EVENT_SHOW, 't11_c2'),
new orderChecker(),
new invokerChecker(EVENT_REORDER, 't11'), new invokerChecker(EVENT_REORDER, 't11'),
new unexpectedInvokerChecker(EVENT_HIDE, 't11_c2_child'), new unexpectedInvokerChecker(EVENT_HIDE, 't11_c2_child'),
new unexpectedInvokerChecker(EVENT_REORDER, 't11_c1'), new unexpectedInvokerChecker(EVENT_REORDER, 't11_c1'),
@ -689,7 +691,7 @@
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Do tests. // Do tests.
//gA11yEventDumpToConsole = true; // debug stuff gA11yEventDumpToConsole = true; // debug stuff
//enableLogging("eventTree"); //enableLogging("eventTree");
var gQueue = null; var gQueue = null;

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

@ -341,8 +341,8 @@
this.containerNode = getNode(aContainerID); this.containerNode = getNode(aContainerID);
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.lastChild; }, this.containerNode),
new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.firstChild; }, this.containerNode), new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.firstChild; }, this.containerNode),
new invokerChecker(EVENT_SHOW, function(aNode) { return aNode.lastChild; }, this.containerNode),
new invokerChecker(EVENT_REORDER, this.containerNode) new invokerChecker(EVENT_REORDER, this.containerNode)
]; ];

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

@ -27,11 +27,11 @@
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_button")), new invokerChecker(EVENT_HIDE, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
// no hide for t1_subdiv because it is contained by hidden t1_checkbox // no hide for t1_subdiv because it is contained by hidden t1_checkbox
new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")), new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")), new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
new invokerChecker(EVENT_REORDER, getNode("t1_container")) new invokerChecker(EVENT_REORDER, getNode("t1_container"))
]; ];
@ -73,10 +73,12 @@
function removeARIAOwns() function removeARIAOwns()
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
new invokerChecker(EVENT_HIDE, getNode("t1_button")), new invokerChecker(EVENT_HIDE, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")), new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
new orderChecker(),
new asyncInvokerChecker(EVENT_SHOW, getNode("t1_button")),
new asyncInvokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
new orderChecker(),
new invokerChecker(EVENT_REORDER, getNode("t1_container")), new invokerChecker(EVENT_REORDER, getNode("t1_container")),
new unexpectedInvokerChecker(EVENT_REORDER, getNode("t1_checkbox")) new unexpectedInvokerChecker(EVENT_REORDER, getNode("t1_checkbox"))
]; ];
@ -108,8 +110,8 @@
function setARIAOwns() function setARIAOwns()
{ {
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
new invokerChecker(EVENT_HIDE, getNode("t1_button")), new invokerChecker(EVENT_HIDE, getNode("t1_button")),
new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
new invokerChecker(EVENT_SHOW, getNode("t1_button")), new invokerChecker(EVENT_SHOW, getNode("t1_button")),
new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")), new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
new invokerChecker(EVENT_REORDER, getNode("t1_container")) new invokerChecker(EVENT_REORDER, getNode("t1_container"))
@ -447,6 +449,9 @@
this.eventSeq = []; this.eventSeq = [];
for (var id of aIdList) { for (var id of aIdList) {
this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id))); this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
}
for (var id of aIdList) {
this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id))); this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
} }
this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer))); this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));

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

@ -21,9 +21,9 @@
this.containerNode = getNode("outerDiv"); this.containerNode = getNode("outerDiv");
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_HIDE, getNode("child")),
new invokerChecker(EVENT_HIDE, getNode("childDoc")), new invokerChecker(EVENT_HIDE, getNode("childDoc")),
new invokerChecker(EVENT_SHOW, "newChildDoc"), new invokerChecker(EVENT_SHOW, "newChildDoc"),
new invokerChecker(EVENT_HIDE, getNode("child")),
new invokerChecker(EVENT_REORDER, this.containerNode) new invokerChecker(EVENT_REORDER, this.containerNode)
]; ];
@ -47,7 +47,7 @@
} }
//enableLogging("tree"); //enableLogging("tree");
//gA11yEventDumpToConsole = true; gA11yEventDumpToConsole = true;
var gQueue = null; var gQueue = null;
function doTest() function doTest()
{ {

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

@ -101,8 +101,9 @@
this.imgNode.setAttribute("src", "../moz.png"); this.imgNode.setAttribute("src", "../moz.png");
this.eventSeq = [ this.eventSeq = [
new invokerChecker(EVENT_SHOW, getAccessible, this.imgNode), new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.textNode),
new invokerChecker(EVENT_SHOW, getAccessible, this.textNode), new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.imgNode),
new orderChecker(),
new invokerChecker(EVENT_REORDER, this.topNode) new invokerChecker(EVENT_REORDER, this.topNode)
]; ];

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

@ -735,7 +735,7 @@ TextPropertyEditor.prototype = {
return; return;
} }
if (this.isDisplayGrid) { if (this.isDisplayGrid()) {
this.ruleView.highlighters._hideGridHighlighter(); this.ruleView.highlighters._hideGridHighlighter();
} }

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

@ -7,6 +7,7 @@ support-files =
html_cause-test-page.html html_cause-test-page.html
html_content-type-test-page.html html_content-type-test-page.html
html_content-type-without-cache-test-page.html html_content-type-without-cache-test-page.html
html_brotli-test-page.html
html_image-tooltip-test-page.html html_image-tooltip-test-page.html
html_cors-test-page.html html_cors-test-page.html
html_custom-get-page.html html_custom-get-page.html
@ -68,6 +69,7 @@ skip-if = true # Bug 1309191 - replace with rewritten version in React
[browser_net_clear.js] [browser_net_clear.js]
[browser_net_complex-params.js] [browser_net_complex-params.js]
[browser_net_content-type.js] [browser_net_content-type.js]
[browser_net_brotli.js]
[browser_net_curl-utils.js] [browser_net_curl-utils.js]
[browser_net_copy_image_as_data_uri.js] [browser_net_copy_image_as_data_uri.js]
subsuite = clipboard subsuite = clipboard

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

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const BROTLI_URL = HTTPS_EXAMPLE_URL + "html_brotli-test-page.html";
const BROTLI_REQUESTS = 1;
/**
* Test brotli encoded response is handled correctly on HTTPS.
*/
add_task(function* () {
let { L10N } = require("devtools/client/netmonitor/l10n");
let { tab, monitor } = yield initNetMonitor(BROTLI_URL);
info("Starting test... ");
let { document, Editor, NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
let wait = waitForNetworkEvents(monitor, BROTLI_REQUESTS);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", HTTPS_CONTENT_TYPE_SJS + "?fmt=br", {
status: 200,
statusText: "Connected",
type: "plain",
fullMimeType: "text/plain",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 10),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 64),
time: true
});
let onEvent = waitForResponseBodyDisplayed();
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
yield onEvent;
yield testResponseTab("br");
yield teardown(monitor);
function* testResponseTab(type) {
let tabEl = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tabEl.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
function checkVisibility(box) {
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), box != "json",
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), box != "textarea",
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), box != "image",
"The response content image box doesn't have the intended visibility.");
}
switch (type) {
case "br": {
checkVisibility("textarea");
let expected = "X".repeat(64);
let editor = yield NetMonitorView.editor("#response-content-textarea");
is(editor.getText(), expected,
"The text shown in the source editor is incorrect for the brotli request.");
is(editor.getMode(), Editor.modes.text,
"The mode active in the source editor is incorrect for the brotli request.");
break;
}
}
}
function waitForResponseBodyDisplayed() {
return monitor.panelWin.once(monitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED);
}
});

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

@ -7,16 +7,10 @@
* Tests if different response content types are handled correctly. * Tests if different response content types are handled correctly.
*/ */
function* content_type_test(isHTTPS) { add_task(function* () {
let { L10N } = require("devtools/client/netmonitor/l10n"); let { L10N } = require("devtools/client/netmonitor/l10n");
let pageURL = isHTTPS ? HTTPS_CONTENT_TYPE_WITHOUT_CACHE_URL let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
: CONTENT_TYPE_WITHOUT_CACHE_URL;
let imageURL = isHTTPS ? HTTPS_TEST_IMAGE
: TEST_IMAGE;
let sjsURL = isHTTPS ? HTTPS_CONTENT_TYPE_SJS
: CONTENT_TYPE_SJS;
let { tab, monitor } = yield initNetMonitor(pageURL);
info("Starting test... "); info("Starting test... ");
let { document, Editor, NetMonitorView } = monitor.panelWin; let { document, Editor, NetMonitorView } = monitor.panelWin;
@ -30,48 +24,44 @@ function* content_type_test(isHTTPS) {
}); });
yield wait; yield wait;
let okStatus = isHTTPS ? "Connected" : "OK";
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", sjsURL + "?fmt=xml", { "GET", CONTENT_TYPE_SJS + "?fmt=xml", {
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "xml", type: "xml",
fullMimeType: "text/xml; charset=utf-8", fullMimeType: "text/xml; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42),
time: true time: true
}); });
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
"GET", sjsURL + "?fmt=css", { "GET", CONTENT_TYPE_SJS + "?fmt=css", {
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "css", type: "css",
fullMimeType: "text/css; charset=utf-8", fullMimeType: "text/css; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
time: true time: true
}); });
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
"GET", sjsURL + "?fmt=js", { "GET", CONTENT_TYPE_SJS + "?fmt=js", {
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "js", type: "js",
fullMimeType: "application/javascript; charset=utf-8", fullMimeType: "application/javascript; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
time: true time: true
}); });
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
"GET", sjsURL + "?fmt=json", { "GET", CONTENT_TYPE_SJS + "?fmt=json", {
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "json", type: "json",
fullMimeType: "application/json; charset=utf-8", fullMimeType: "application/json; charset=utf-8",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29),
time: true time: true
}); });
if (!isHTTPS) {
// 404 doesn't work on HTTPS test harness.
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
"GET", sjsURL + "?fmt=bogus", { "GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
status: 404, status: 404,
statusText: "Not Found", statusText: "Not Found",
type: "html", type: "html",
@ -79,40 +69,26 @@ function* content_type_test(isHTTPS) {
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
time: true time: true
}); });
}
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
"GET", imageURL, { "GET", TEST_IMAGE, {
fuzzyUrl: true, fuzzyUrl: true,
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "png", type: "png",
fullMimeType: "image/png", fullMimeType: "image/png",
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580), size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580),
time: true time: true
}); });
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6), verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
"GET", sjsURL + "?fmt=gzip", { "GET", CONTENT_TYPE_SJS + "?fmt=gzip", {
status: 200, status: 200,
statusText: okStatus, statusText: "OK",
type: "plain", type: "plain",
fullMimeType: "text/plain", fullMimeType: "text/plain",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73), transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73), size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
time: true time: true
}); });
if (isHTTPS) {
// Brotli is enabled only on HTTPS.
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
"GET", sjsURL + "?fmt=gzip", {
status: 200,
statusText: okStatus,
type: "plain",
fullMimeType: "text/plain",
transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73),
size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
time: true
});
}
let onEvent = waitForResponseBodyDisplayed(); let onEvent = waitForResponseBodyDisplayed();
EventUtils.sendMouseEvent({ type: "mousedown" }, EventUtils.sendMouseEvent({ type: "mousedown" },
@ -140,11 +116,6 @@ function* content_type_test(isHTTPS) {
yield selectIndexAndWaitForTabUpdated(6); yield selectIndexAndWaitForTabUpdated(6);
yield testResponseTab("gzip"); yield testResponseTab("gzip");
if (isHTTPS) {
yield selectIndexAndWaitForTabUpdated(7);
yield testResponseTab("br");
}
yield teardown(monitor); yield teardown(monitor);
function* testResponseTab(type) { function* testResponseTab(type) {
@ -269,17 +240,6 @@ function* content_type_test(isHTTPS) {
"The mode active in the source editor is incorrect for the gzip request."); "The mode active in the source editor is incorrect for the gzip request.");
break; break;
} }
case "br": {
checkVisibility("textarea");
let expected = "X".repeat(64);
let editor = yield NetMonitorView.editor("#response-content-textarea");
is(editor.getText(), expected,
"The text shown in the source editor is incorrect for the brotli request.");
is(editor.getMode(), Editor.modes.text,
"The mode active in the source editor is incorrect for the brotli request.");
break;
}
} }
} }
@ -292,12 +252,4 @@ function* content_type_test(isHTTPS) {
function waitForResponseBodyDisplayed() { function waitForResponseBodyDisplayed() {
return monitor.panelWin.once(monitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED); return monitor.panelWin.once(monitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED);
} }
}
add_task(function* () {
yield* content_type_test(false);
});
add_task(function* () {
yield* content_type_test(true);
}); });

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

@ -20,7 +20,6 @@ const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html"; const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html"; const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html"; const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
const HTTPS_CONTENT_TYPE_WITHOUT_CACHE_URL = HTTPS_EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
const CONTENT_TYPE_WITHOUT_CACHE_REQUESTS = 8; const CONTENT_TYPE_WITHOUT_CACHE_REQUESTS = 8;
const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html"; const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html"; const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
@ -58,7 +57,6 @@ const HSTS_BASE_URL = EXAMPLE_URL;
const HSTS_PAGE_URL = CUSTOM_GET_URL; const HSTS_PAGE_URL = CUSTOM_GET_URL;
const TEST_IMAGE = EXAMPLE_URL + "test-image.png"; const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
const HTTPS_TEST_IMAGE = HTTPS_EXAMPLE_URL + "test-image.png";
const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="; const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js"; const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";

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

@ -0,0 +1,38 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>Network Monitor test page</title>
</head>
<body>
<p>Brotli test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=br", function() {
// Done.
});
}
</script>
</body>
</html>

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

@ -18,5 +18,6 @@ DevToolsModules(
'jsterm.js', 'jsterm.js',
'panel.js', 'panel.js',
'utils.js', 'utils.js',
'webconsole-connection-proxy.js',
'webconsole.js', 'webconsole.js',
) )

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

@ -0,0 +1,503 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=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/. */
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Utils: WebConsoleUtils} =
require("devtools/client/webconsole/utils");
const BrowserLoaderModule = {};
Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
const promise = require("promise");
const Services = require("Services");
const STRINGS_URI = "devtools/client/locales/webconsole.properties";
var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
// Web Console connection proxy
/**
* The WebConsoleConnectionProxy handles the connection between the Web Console
* and the application we connect to through the remote debug protocol.
*
* @constructor
* @param object webConsoleFrame
* The WebConsoleFrame object that owns this connection proxy.
* @param RemoteTarget target
* The target that the console will connect to.
*/
function WebConsoleConnectionProxy(webConsoleFrame, target) {
this.webConsoleFrame = webConsoleFrame;
this.target = target;
this._onPageError = this._onPageError.bind(this);
this._onLogMessage = this._onLogMessage.bind(this);
this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onFileActivity = this._onFileActivity.bind(this);
this._onReflowActivity = this._onReflowActivity.bind(this);
this._onServerLogCall = this._onServerLogCall.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onAttachConsole = this._onAttachConsole.bind(this);
this._onCachedMessages = this._onCachedMessages.bind(this);
this._connectionTimeout = this._connectionTimeout.bind(this);
this._onLastPrivateContextExited =
this._onLastPrivateContextExited.bind(this);
}
WebConsoleConnectionProxy.prototype = {
/**
* The owning Web Console Frame instance.
*
* @see WebConsoleFrame
* @type object
*/
webConsoleFrame: null,
/**
* The target that the console connects to.
* @type RemoteTarget
*/
target: null,
/**
* The DebuggerClient object.
*
* @see DebuggerClient
* @type object
*/
client: null,
/**
* The WebConsoleClient object.
*
* @see WebConsoleClient
* @type object
*/
webConsoleClient: null,
/**
* Tells if the connection is established.
* @type boolean
*/
connected: false,
/**
* Timer used for the connection.
* @private
* @type object
*/
_connectTimer: null,
_connectDefer: null,
_disconnecter: null,
/**
* The WebConsoleActor ID.
*
* @private
* @type string
*/
_consoleActor: null,
/**
* Tells if the window.console object of the remote web page is the native
* object or not.
* @private
* @type boolean
*/
_hasNativeConsoleAPI: false,
/**
* Initialize a debugger client and connect it to the debugger server.
*
* @return object
* A promise object that is resolved/rejected based on the success of
* the connection initialization.
*/
connect: function () {
if (this._connectDefer) {
return this._connectDefer.promise;
}
this._connectDefer = promise.defer();
let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._connectTimer.initWithCallback(this._connectionTimeout,
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
let connPromise = this._connectDefer.promise;
connPromise.then(() => {
this._connectTimer.cancel();
this._connectTimer = null;
}, () => {
this._connectTimer = null;
});
let client = this.client = this.target.client;
if (this.target.isWorkerTarget) {
// XXXworkers: Not Console API yet inside of workers (Bug 1209353).
} else {
client.addListener("logMessage", this._onLogMessage);
client.addListener("pageError", this._onPageError);
client.addListener("consoleAPICall", this._onConsoleAPICall);
client.addListener("fileActivity", this._onFileActivity);
client.addListener("reflowActivity", this._onReflowActivity);
client.addListener("serverLogCall", this._onServerLogCall);
client.addListener("lastPrivateContextExited",
this._onLastPrivateContextExited);
}
this.target.on("will-navigate", this._onTabNavigated);
this.target.on("navigate", this._onTabNavigated);
this._consoleActor = this.target.form.consoleActor;
if (this.target.isTabActor) {
let tab = this.target.form;
this.webConsoleFrame.onLocationChange(tab.url, tab.title);
}
this._attachConsole();
return connPromise;
},
/**
* Connection timeout handler.
* @private
*/
_connectionTimeout: function () {
let error = {
error: "timeout",
message: l10n.getStr("connectionTimeout"),
};
this._connectDefer.reject(error);
},
/**
* Attach to the Web Console actor.
* @private
*/
_attachConsole: function () {
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
"FileActivity"];
this.client.attachConsole(this._consoleActor, listeners,
this._onAttachConsole);
},
/**
* The "attachConsole" response handler.
*
* @private
* @param object response
* The JSON response object received from the server.
* @param object webConsoleClient
* The WebConsoleClient instance for the attached console, for the
* specific tab we work with.
*/
_onAttachConsole: function (response, webConsoleClient) {
if (response.error) {
console.error("attachConsole failed: " + response.error + " " +
response.message);
this._connectDefer.reject(response);
return;
}
this.webConsoleClient = webConsoleClient;
this._hasNativeConsoleAPI = response.nativeConsoleAPI;
// There is no way to view response bodies from the Browser Console, so do
// not waste the memory.
let saveBodies = !this.webConsoleFrame.isBrowserConsole;
this.webConsoleFrame.setSaveRequestAndResponseBodies(saveBodies);
this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
let msgs = ["PageError", "ConsoleAPI"];
this.webConsoleClient.getCachedMessages(msgs, this._onCachedMessages);
this.webConsoleFrame._onUpdateListeners();
},
/**
* Dispatch a message add on the new frontend and emit an event for tests.
*/
dispatchMessageAdd: function(packet) {
this.webConsoleFrame.newConsoleOutput.dispatchMessageAdd(packet);
},
/**
* Batched dispatch of messages.
*/
dispatchMessagesAdd: function(packets) {
this.webConsoleFrame.newConsoleOutput.dispatchMessagesAdd(packets);
},
/**
* The "cachedMessages" response handler.
*
* @private
* @param object response
* The JSON response object received from the server.
*/
_onCachedMessages: function (response) {
if (response.error) {
console.error("Web Console getCachedMessages error: " + response.error +
" " + response.message);
this._connectDefer.reject(response);
return;
}
if (!this._connectTimer) {
// This happens if the promise is rejected (eg. a timeout), but the
// connection attempt is successful, nonetheless.
console.error("Web Console getCachedMessages error: invalid state.");
}
let messages =
response.messages.concat(...this.webConsoleClient.getNetworkEvents());
messages.sort((a, b) => a.timeStamp - b.timeStamp);
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessagesAdd(messages);
} else {
this.webConsoleFrame.displayCachedMessages(messages);
if (!this._hasNativeConsoleAPI) {
this.webConsoleFrame.logWarningAboutReplacedAPI();
}
}
this.connected = true;
this._connectDefer.resolve(this);
},
/**
* The "pageError" message type handler. We redirect any page errors to the UI
* for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onPageError: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(packet);
return;
}
this.webConsoleFrame.handlePageError(packet.pageError);
}
},
/**
* The "logMessage" message type handler. We redirect any message to the UI
* for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onLogMessage: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleLogMessage(packet);
}
},
/**
* The "consoleAPICall" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onConsoleAPICall: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(packet);
} else {
this.webConsoleFrame.handleConsoleAPICall(packet.message);
}
}
},
/**
* The "networkEvent" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object networkInfo
* The network request information.
*/
_onNetworkEvent: function (type, networkInfo) {
if (this.webConsoleFrame) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(networkInfo);
} else {
this.webConsoleFrame.handleNetworkEvent(networkInfo);
}
}
},
/**
* The "networkEventUpdate" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
* @param object networkInfo
* The network request information.
*/
_onNetworkEventUpdate: function (type, { packet, networkInfo }) {
if (this.webConsoleFrame) {
this.webConsoleFrame.handleNetworkEventUpdate(networkInfo, packet);
}
},
/**
* The "fileActivity" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onFileActivity: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleFileActivity(packet.uri);
}
},
_onReflowActivity: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleReflowActivity(packet);
}
},
/**
* The "serverLogCall" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onServerLogCall: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleConsoleAPICall(packet.message);
}
},
/**
* The "lastPrivateContextExited" message type handler. When this message is
* received the Web Console UI is cleared.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onLastPrivateContextExited: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.jsterm.clearPrivateMessages();
}
},
/**
* The "will-navigate" and "navigate" event handlers. We redirect any message
* to the UI for displaying.
*
* @private
* @param string event
* Event type.
* @param object packet
* The message received from the server.
*/
_onTabNavigated: function (event, packet) {
if (!this.webConsoleFrame) {
return;
}
this.webConsoleFrame.handleTabNavigated(event, packet);
},
/**
* Release an object actor.
*
* @param string actor
* The actor ID to send the request to.
*/
releaseActor: function (actor) {
if (this.client) {
this.client.release(actor);
}
},
/**
* Disconnect the Web Console from the remote server.
*
* @return object
* A promise object that is resolved when disconnect completes.
*/
disconnect: function () {
if (this._disconnecter) {
return this._disconnecter.promise;
}
this._disconnecter = promise.defer();
if (!this.client) {
this._disconnecter.resolve(null);
return this._disconnecter.promise;
}
this.client.removeListener("logMessage", this._onLogMessage);
this.client.removeListener("pageError", this._onPageError);
this.client.removeListener("consoleAPICall", this._onConsoleAPICall);
this.client.removeListener("fileActivity", this._onFileActivity);
this.client.removeListener("reflowActivity", this._onReflowActivity);
this.client.removeListener("serverLogCall", this._onServerLogCall);
this.client.removeListener("lastPrivateContextExited",
this._onLastPrivateContextExited);
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
this.target.off("will-navigate", this._onTabNavigated);
this.target.off("navigate", this._onTabNavigated);
this.client = null;
this.webConsoleClient = null;
this.target = null;
this.connected = false;
this.webConsoleFrame = null;
this._disconnecter.resolve(null);
return this._disconnecter.promise;
},
};
exports.WebConsoleConnectionProxy = WebConsoleConnectionProxy;

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

@ -16,15 +16,12 @@ Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderMo
const promise = require("promise"); const promise = require("promise");
const Services = require("Services"); const Services = require("Services");
const ErrorDocs = require("devtools/server/actors/errordocs");
const Telemetry = require("devtools/client/shared/telemetry"); const Telemetry = require("devtools/client/shared/telemetry");
loader.lazyServiceGetter(this, "clipboardHelper", loader.lazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1", "@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper"); "nsIClipboardHelper");
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter"); loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
loader.lazyRequireGetter(this, "AutocompletePopup", "devtools/client/shared/autocomplete-popup", true);
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/framework/sidebar", true);
loader.lazyRequireGetter(this, "ConsoleOutput", "devtools/client/webconsole/console-output", true); loader.lazyRequireGetter(this, "ConsoleOutput", "devtools/client/webconsole/console-output", true);
loader.lazyRequireGetter(this, "Messages", "devtools/client/webconsole/console-output", true); loader.lazyRequireGetter(this, "Messages", "devtools/client/webconsole/console-output", true);
loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/main", true); loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/main", true);
@ -37,6 +34,7 @@ loader.lazyImporter(this, "VariablesViewController", "resource://devtools/client
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true); loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts", true); loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts", true);
loader.lazyRequireGetter(this, "ZoomKeys", "devtools/client/shared/zoom-keys"); loader.lazyRequireGetter(this, "ZoomKeys", "devtools/client/shared/zoom-keys");
loader.lazyRequireGetter(this, "WebConsoleConnectionProxy", "devtools/client/webconsole/webconsole-connection-proxy", true);
const {PluralForm} = require("devtools/shared/plural-form"); const {PluralForm} = require("devtools/shared/plural-form");
const STRINGS_URI = "devtools/client/locales/webconsole.properties"; const STRINGS_URI = "devtools/client/locales/webconsole.properties";
@ -183,10 +181,6 @@ const THROTTLE_UPDATES = 1000;
// The preference prefix for all of the Web Console filters. // The preference prefix for all of the Web Console filters.
const FILTER_PREFS_PREFIX = "devtools.webconsole.filter."; const FILTER_PREFS_PREFIX = "devtools.webconsole.filter.";
// The minimum font size.
const MIN_FONT_SIZE = 10;
const PREF_CONNECTION_TIMEOUT = "devtools.debugger.remote-timeout";
const PREF_PERSISTLOG = "devtools.webconsole.persistlog"; const PREF_PERSISTLOG = "devtools.webconsole.persistlog";
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages"; const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
const PREF_NEW_FRONTEND_ENABLED = "devtools.webconsole.new-frontend-enabled"; const PREF_NEW_FRONTEND_ENABLED = "devtools.webconsole.new-frontend-enabled";
@ -3053,486 +3047,6 @@ CommandController.prototype = {
} }
}; };
// Web Console connection proxy
/**
* The WebConsoleConnectionProxy handles the connection between the Web Console
* and the application we connect to through the remote debug protocol.
*
* @constructor
* @param object webConsoleFrame
* The WebConsoleFrame object that owns this connection proxy.
* @param RemoteTarget target
* The target that the console will connect to.
*/
function WebConsoleConnectionProxy(webConsoleFrame, target) {
this.webConsoleFrame = webConsoleFrame;
this.target = target;
this._onPageError = this._onPageError.bind(this);
this._onLogMessage = this._onLogMessage.bind(this);
this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onFileActivity = this._onFileActivity.bind(this);
this._onReflowActivity = this._onReflowActivity.bind(this);
this._onServerLogCall = this._onServerLogCall.bind(this);
this._onTabNavigated = this._onTabNavigated.bind(this);
this._onAttachConsole = this._onAttachConsole.bind(this);
this._onCachedMessages = this._onCachedMessages.bind(this);
this._connectionTimeout = this._connectionTimeout.bind(this);
this._onLastPrivateContextExited =
this._onLastPrivateContextExited.bind(this);
}
WebConsoleConnectionProxy.prototype = {
/**
* The owning Web Console Frame instance.
*
* @see WebConsoleFrame
* @type object
*/
webConsoleFrame: null,
/**
* The target that the console connects to.
* @type RemoteTarget
*/
target: null,
/**
* The DebuggerClient object.
*
* @see DebuggerClient
* @type object
*/
client: null,
/**
* The WebConsoleClient object.
*
* @see WebConsoleClient
* @type object
*/
webConsoleClient: null,
/**
* Tells if the connection is established.
* @type boolean
*/
connected: false,
/**
* Timer used for the connection.
* @private
* @type object
*/
_connectTimer: null,
_connectDefer: null,
_disconnecter: null,
/**
* The WebConsoleActor ID.
*
* @private
* @type string
*/
_consoleActor: null,
/**
* Tells if the window.console object of the remote web page is the native
* object or not.
* @private
* @type boolean
*/
_hasNativeConsoleAPI: false,
/**
* Initialize a debugger client and connect it to the debugger server.
*
* @return object
* A promise object that is resolved/rejected based on the success of
* the connection initialization.
*/
connect: function () {
if (this._connectDefer) {
return this._connectDefer.promise;
}
this._connectDefer = promise.defer();
let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._connectTimer.initWithCallback(this._connectionTimeout,
timeout, Ci.nsITimer.TYPE_ONE_SHOT);
let connPromise = this._connectDefer.promise;
connPromise.then(() => {
this._connectTimer.cancel();
this._connectTimer = null;
}, () => {
this._connectTimer = null;
});
let client = this.client = this.target.client;
if (this.target.isWorkerTarget) {
// XXXworkers: Not Console API yet inside of workers (Bug 1209353).
} else {
client.addListener("logMessage", this._onLogMessage);
client.addListener("pageError", this._onPageError);
client.addListener("consoleAPICall", this._onConsoleAPICall);
client.addListener("fileActivity", this._onFileActivity);
client.addListener("reflowActivity", this._onReflowActivity);
client.addListener("serverLogCall", this._onServerLogCall);
client.addListener("lastPrivateContextExited",
this._onLastPrivateContextExited);
}
this.target.on("will-navigate", this._onTabNavigated);
this.target.on("navigate", this._onTabNavigated);
this._consoleActor = this.target.form.consoleActor;
if (this.target.isTabActor) {
let tab = this.target.form;
this.webConsoleFrame.onLocationChange(tab.url, tab.title);
}
this._attachConsole();
return connPromise;
},
/**
* Connection timeout handler.
* @private
*/
_connectionTimeout: function () {
let error = {
error: "timeout",
message: l10n.getStr("connectionTimeout"),
};
this._connectDefer.reject(error);
},
/**
* Attach to the Web Console actor.
* @private
*/
_attachConsole: function () {
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
"FileActivity"];
this.client.attachConsole(this._consoleActor, listeners,
this._onAttachConsole);
},
/**
* The "attachConsole" response handler.
*
* @private
* @param object response
* The JSON response object received from the server.
* @param object webConsoleClient
* The WebConsoleClient instance for the attached console, for the
* specific tab we work with.
*/
_onAttachConsole: function (response, webConsoleClient) {
if (response.error) {
console.error("attachConsole failed: " + response.error + " " +
response.message);
this._connectDefer.reject(response);
return;
}
this.webConsoleClient = webConsoleClient;
this._hasNativeConsoleAPI = response.nativeConsoleAPI;
// There is no way to view response bodies from the Browser Console, so do
// not waste the memory.
let saveBodies = !this.webConsoleFrame.isBrowserConsole;
this.webConsoleFrame.setSaveRequestAndResponseBodies(saveBodies);
this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
let msgs = ["PageError", "ConsoleAPI"];
this.webConsoleClient.getCachedMessages(msgs, this._onCachedMessages);
this.webConsoleFrame._onUpdateListeners();
},
/**
* Dispatch a message add on the new frontend and emit an event for tests.
*/
dispatchMessageAdd: function(packet) {
this.webConsoleFrame.newConsoleOutput.dispatchMessageAdd(packet);
},
/**
* Batched dispatch of messages.
*/
dispatchMessagesAdd: function(packets) {
this.webConsoleFrame.newConsoleOutput.dispatchMessagesAdd(packets);
},
/**
* The "cachedMessages" response handler.
*
* @private
* @param object response
* The JSON response object received from the server.
*/
_onCachedMessages: function (response) {
if (response.error) {
console.error("Web Console getCachedMessages error: " + response.error +
" " + response.message);
this._connectDefer.reject(response);
return;
}
if (!this._connectTimer) {
// This happens if the promise is rejected (eg. a timeout), but the
// connection attempt is successful, nonetheless.
console.error("Web Console getCachedMessages error: invalid state.");
}
let messages =
response.messages.concat(...this.webConsoleClient.getNetworkEvents());
messages.sort((a, b) => a.timeStamp - b.timeStamp);
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessagesAdd(messages);
} else {
this.webConsoleFrame.displayCachedMessages(messages);
if (!this._hasNativeConsoleAPI) {
this.webConsoleFrame.logWarningAboutReplacedAPI();
}
}
this.connected = true;
this._connectDefer.resolve(this);
},
/**
* The "pageError" message type handler. We redirect any page errors to the UI
* for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onPageError: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(packet);
return;
}
this.webConsoleFrame.handlePageError(packet.pageError);
}
},
/**
* The "logMessage" message type handler. We redirect any message to the UI
* for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onLogMessage: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleLogMessage(packet);
}
},
/**
* The "consoleAPICall" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onConsoleAPICall: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(packet);
} else {
this.webConsoleFrame.handleConsoleAPICall(packet.message);
}
}
},
/**
* The "networkEvent" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object networkInfo
* The network request information.
*/
_onNetworkEvent: function (type, networkInfo) {
if (this.webConsoleFrame) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
this.dispatchMessageAdd(networkInfo);
} else {
this.webConsoleFrame.handleNetworkEvent(networkInfo);
}
}
},
/**
* The "networkEventUpdate" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
* @param object networkInfo
* The network request information.
*/
_onNetworkEventUpdate: function (type, { packet, networkInfo }) {
if (this.webConsoleFrame) {
this.webConsoleFrame.handleNetworkEventUpdate(networkInfo, packet);
}
},
/**
* The "fileActivity" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onFileActivity: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleFileActivity(packet.uri);
}
},
_onReflowActivity: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleReflowActivity(packet);
}
},
/**
* The "serverLogCall" message type handler. We redirect any message to
* the UI for displaying.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onServerLogCall: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.handleConsoleAPICall(packet.message);
}
},
/**
* The "lastPrivateContextExited" message type handler. When this message is
* received the Web Console UI is cleared.
*
* @private
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onLastPrivateContextExited: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
this.webConsoleFrame.jsterm.clearPrivateMessages();
}
},
/**
* The "will-navigate" and "navigate" event handlers. We redirect any message
* to the UI for displaying.
*
* @private
* @param string event
* Event type.
* @param object packet
* The message received from the server.
*/
_onTabNavigated: function (event, packet) {
if (!this.webConsoleFrame) {
return;
}
this.webConsoleFrame.handleTabNavigated(event, packet);
},
/**
* Release an object actor.
*
* @param string actor
* The actor ID to send the request to.
*/
releaseActor: function (actor) {
if (this.client) {
this.client.release(actor);
}
},
/**
* Disconnect the Web Console from the remote server.
*
* @return object
* A promise object that is resolved when disconnect completes.
*/
disconnect: function () {
if (this._disconnecter) {
return this._disconnecter.promise;
}
this._disconnecter = promise.defer();
if (!this.client) {
this._disconnecter.resolve(null);
return this._disconnecter.promise;
}
this.client.removeListener("logMessage", this._onLogMessage);
this.client.removeListener("pageError", this._onPageError);
this.client.removeListener("consoleAPICall", this._onConsoleAPICall);
this.client.removeListener("fileActivity", this._onFileActivity);
this.client.removeListener("reflowActivity", this._onReflowActivity);
this.client.removeListener("serverLogCall", this._onServerLogCall);
this.client.removeListener("lastPrivateContextExited",
this._onLastPrivateContextExited);
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
this.target.off("will-navigate", this._onTabNavigated);
this.target.off("navigate", this._onTabNavigated);
this.client = null;
this.webConsoleClient = null;
this.target = null;
this.connected = false;
this.webConsoleFrame = null;
this._disconnecter.resolve(null);
return this._disconnecter.promise;
},
};
// Context Menu // Context Menu
/* /*

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

@ -372,78 +372,6 @@ nsPluginCrashedEvent::Run()
return NS_OK; return NS_OK;
} }
class nsStopPluginRunnable : public Runnable, public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsStopPluginRunnable(nsPluginInstanceOwner* aInstanceOwner,
nsObjectLoadingContent* aContent)
: mInstanceOwner(aInstanceOwner)
, mContent(aContent)
{
NS_ASSERTION(aInstanceOwner, "need an owner");
NS_ASSERTION(aContent, "need a nsObjectLoadingContent");
}
// Runnable
NS_IMETHOD Run() override;
// nsITimerCallback
NS_IMETHOD Notify(nsITimer* timer) override;
protected:
~nsStopPluginRunnable() override = default;
private:
nsCOMPtr<nsITimer> mTimer;
RefPtr<nsPluginInstanceOwner> mInstanceOwner;
nsCOMPtr<nsIObjectLoadingContent> mContent;
};
NS_IMPL_ISUPPORTS_INHERITED(nsStopPluginRunnable, Runnable, nsITimerCallback)
NS_IMETHODIMP
nsStopPluginRunnable::Notify(nsITimer *aTimer)
{
return Run();
}
NS_IMETHODIMP
nsStopPluginRunnable::Run()
{
// InitWithCallback calls Release before AddRef so we need to hold a
// strong ref on 'this' since we fall through to this scope if it fails.
nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell) {
uint32_t currentLevel = 0;
appShell->GetEventloopNestingLevel(&currentLevel);
if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
if (!mTimer)
mTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mTimer) {
// Fire 100ms timer to try to tear down this plugin as quickly as
// possible once the nesting level comes back down.
nsresult rv = mTimer->InitWithCallback(this, 100,
nsITimer::TYPE_ONE_SHOT);
if (NS_SUCCEEDED(rv)) {
return rv;
}
}
NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
"time). Stopping the plugin now, this might crash.");
}
}
mTimer = nullptr;
static_cast<nsObjectLoadingContent*>(mContent.get())->
DoStopPlugin(mInstanceOwner, false, true);
return NS_OK;
}
// You can't take the address of bitfield members, so we have two separate // You can't take the address of bitfield members, so we have two separate
// classes for these :-/ // classes for these :-/
@ -3070,29 +2998,6 @@ nsObjectLoadingContent::GetSrcURI(nsIURI** aURI)
return NS_OK; return NS_OK;
} }
static bool
DoDelayedStop(nsPluginInstanceOwner* aInstanceOwner,
nsObjectLoadingContent* aContent,
bool aDelayedStop)
{
// Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
// XStandard (bug 430219), CMISS Zinc (bug 429604).
if (aDelayedStop
#if !(defined XP_WIN || defined MOZ_X11)
&& !aInstanceOwner->MatchPluginName("QuickTime")
&& !aInstanceOwner->MatchPluginName("Flip4Mac")
&& !aInstanceOwner->MatchPluginName("XStandard plugin")
&& !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
#endif
) {
nsCOMPtr<nsIRunnable> evt =
new nsStopPluginRunnable(aInstanceOwner, aContent);
NS_DispatchToCurrentThread(evt);
return true;
}
return false;
}
void void
nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) { nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) {
EventStates oldState = ObjectState(); EventStates oldState = ObjectState();
@ -3156,16 +3061,13 @@ nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) {
} }
void void
nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner, nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner)
bool aDelayedStop,
bool aForcedReentry)
{ {
// DoStopPlugin can process events -- There may be pending // DoStopPlugin can process events -- There may be pending
// CheckPluginStopEvent events which can drop in underneath us and destroy the // CheckPluginStopEvent events which can drop in underneath us and destroy the
// instance we are about to destroy. We prevent that with the mPluginStopping // instance we are about to destroy. We prevent that with the mIsStopping
// flag. (aForcedReentry is only true from the callback of an earlier delayed // flag.
// stop) if (mIsStopping) {
if (mIsStopping && !aForcedReentry) {
return; return;
} }
mIsStopping = true; mIsStopping = true;
@ -3174,10 +3076,6 @@ nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner,
RefPtr<nsNPAPIPluginInstance> inst; RefPtr<nsNPAPIPluginInstance> inst;
aInstanceOwner->GetInstance(getter_AddRefs(inst)); aInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) { if (inst) {
if (DoDelayedStop(aInstanceOwner, this, aDelayedStop)) {
return;
}
#if defined(XP_MACOSX) #if defined(XP_MACOSX)
aInstanceOwner->HidePluginWindow(); aInstanceOwner->HidePluginWindow();
#endif #endif
@ -3230,27 +3128,11 @@ nsObjectLoadingContent::StopPluginInstance()
// the instance owner until the plugin is stopped. // the instance owner until the plugin is stopped.
mInstanceOwner->SetFrame(nullptr); mInstanceOwner->SetFrame(nullptr);
bool delayedStop = false;
#ifdef XP_WIN
// Force delayed stop for Real plugin only; see bug 420886, 426852.
RefPtr<nsNPAPIPluginInstance> inst;
mInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) {
const char* mime = nullptr;
if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
if (nsPluginHost::GetSpecialType(nsDependentCString(mime)) ==
nsPluginHost::eSpecialType_RealPlayer) {
delayedStop = true;
}
}
}
#endif
RefPtr<nsPluginInstanceOwner> ownerGrip(mInstanceOwner); RefPtr<nsPluginInstanceOwner> ownerGrip(mInstanceOwner);
mInstanceOwner = nullptr; mInstanceOwner = nullptr;
// This can/will re-enter // This can/will re-enter
DoStopPlugin(ownerGrip, delayedStop); DoStopPlugin(ownerGrip);
return NS_OK; return NS_OK;
} }

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

@ -331,8 +331,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
void CreateStaticClone(nsObjectLoadingContent* aDest) const; void CreateStaticClone(nsObjectLoadingContent* aDest) const;
void DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner, bool aDelayedStop, void DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner);
bool aForcedReentry = false);
nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent, nsIContent* aBindingParent,

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

@ -490,7 +490,7 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
*out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset, *out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset,
zOffset, mWidth, mHeight, mDepth, nullptr); zOffset, mWidth, mHeight, mDepth, nullptr);
if (*out_error) if (*out_error)
return false; return true;
} }
const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER,
@ -587,7 +587,7 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
yOffset, zOffset, mWidth, mHeight, mDepth, yOffset, zOffset, mWidth, mHeight, mDepth,
nullptr); nullptr);
if (*out_error) if (*out_error)
return false; return true;
} }
do { do {
@ -650,7 +650,7 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after"
" blit failed for TexUnpackImage.", " blit failed for TexUnpackImage.",
funcName); funcName);
return false; return true;
} }
const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
@ -751,8 +751,10 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
} }
gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ); gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ);
if (!map.IsMapped()) if (!map.IsMapped()) {
webgl->ErrorOutOfMemory("%s: Failed to map source surface for upload.", funcName);
return false; return false;
}
const auto srcBytes = map.GetData(); const auto srcBytes = map.GetData();
const auto srcStride = map.GetStride(); const auto srcStride = map.GetStride();

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

@ -74,6 +74,10 @@ public:
virtual bool Validate(WebGLContext* webgl, const char* funcName, virtual bool Validate(WebGLContext* webgl, const char* funcName,
const webgl::PackingInfo& pi) = 0; const webgl::PackingInfo& pi) = 0;
// Returns false when we've generated a WebGL error.
// Returns true but with a non-zero *out_error if we still need to generate a WebGL
// error.
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level, WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset, const webgl::DriverUnpackInfo* dui, GLint xOffset,

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

@ -1609,10 +1609,22 @@ WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl,
bool colorFormatsMatch = true; bool colorFormatsMatch = true;
bool colorTypesMatch = true; bool colorTypesMatch = true;
const auto fnNarrowComponentType = [&](const webgl::FormatInfo* format) {
switch (format->componentType) {
case webgl::ComponentType::NormInt:
case webgl::ComponentType::NormUInt:
return webgl::ComponentType::Float;
default:
return format->componentType;
}
};
const auto fnCheckColorFormat = [&](const webgl::FormatInfo* dstFormat) { const auto fnCheckColorFormat = [&](const webgl::FormatInfo* dstFormat) {
dstHasColor = true; dstHasColor = true;
colorFormatsMatch &= (dstFormat == srcColorFormat); colorFormatsMatch &= (dstFormat == srcColorFormat);
colorTypesMatch &= (dstFormat->componentType == srcColorFormat->componentType); colorTypesMatch &= ( fnNarrowComponentType(dstFormat) ==
fnNarrowComponentType(srcColorFormat) );
}; };
if (dstFB) { if (dstFB) {

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

@ -1239,8 +1239,11 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
const GLint zOffset = 0; const GLint zOffset = 0;
GLenum glError; GLenum glError;
blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level, if (!blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level,
driverUnpackInfo, xOffset, yOffset, zOffset, &glError); driverUnpackInfo, xOffset, yOffset, zOffset, &glError))
{
return;
}
if (glError == LOCAL_GL_OUT_OF_MEMORY) { if (glError == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
@ -1324,8 +1327,11 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
const bool needsRespec = false; const bool needsRespec = false;
GLenum glError; GLenum glError;
blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level, if (!blob->TexOrSubImage(isSubImage, needsRespec, funcName, this, target, level,
driverUnpackInfo, xOffset, yOffset, zOffset, &glError); driverUnpackInfo, xOffset, yOffset, zOffset, &glError))
{
return;
}
if (glError == LOCAL_GL_OUT_OF_MEMORY) { if (glError == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",

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

@ -1849,11 +1849,6 @@ nsPluginHost::GetSpecialType(const nsACString & aMIMEType)
return eSpecialType_Silverlight; return eSpecialType_Silverlight;
} }
if (aMIMEType.LowerCaseEqualsASCII("audio/x-pn-realaudio-plugin")) {
NS_WARNING("You are loading RealPlayer");
return eSpecialType_RealPlayer;
}
if (aMIMEType.LowerCaseEqualsASCII("application/vnd.unity")) { if (aMIMEType.LowerCaseEqualsASCII("application/vnd.unity")) {
return eSpecialType_Unity; return eSpecialType_Unity;
} }

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

@ -205,8 +205,6 @@ public:
// Some IPC quirks // Some IPC quirks
eSpecialType_Silverlight, eSpecialType_Silverlight,
// Native widget quirks // Native widget quirks
eSpecialType_RealPlayer,
// Native widget quirks
eSpecialType_Unity }; eSpecialType_Unity };
static SpecialType GetSpecialType(const nsACString & aMIMEType); static SpecialType GetSpecialType(const nsACString & aMIMEType);

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

@ -129,9 +129,7 @@ public:
nsPluginHost::SpecialType mPluginType; nsPluginHost::SpecialType mPluginType;
}; };
static bool sInMessageDispatch = false;
static bool sInPreviousMessageDispatch = false; static bool sInPreviousMessageDispatch = false;
static UINT sLastMsg = 0;
static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst, static bool ProcessFlashMessageDelayed(nsPluginNativeWindowWin * aWin, nsNPAPIPluginInstance * aInst,
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
@ -201,16 +199,6 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
RefPtr<nsNPAPIPluginInstance> inst; RefPtr<nsNPAPIPluginInstance> inst;
win->GetPluginInstance(inst); win->GetPluginInstance(inst);
// Real may go into a state where it recursivly dispatches the same event
// when subclassed. If this is Real, lets examine the event and drop it
// on the floor if we get into this recursive situation. See bug 192914.
if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer) {
if (sInMessageDispatch && msg == sLastMsg)
return true;
// Cache the last message sent
sLastMsg = msg;
}
bool enablePopups = false; bool enablePopups = false;
// Activate/deactivate mouse capture on the plugin widget // Activate/deactivate mouse capture on the plugin widget
@ -280,10 +268,6 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
case WM_SETFOCUS: case WM_SETFOCUS:
case WM_KILLFOCUS: { case WM_KILLFOCUS: {
// RealPlayer can crash, don't process the message for those,
// see bug 328675.
if (win->mPluginType == nsPluginHost::eSpecialType_RealPlayer && msg == sLastMsg)
return TRUE;
// Make sure setfocus and killfocus get through to the widget procedure // Make sure setfocus and killfocus get through to the widget procedure
// even if they are eaten by the plugin. Also make sure we aren't calling // even if they are eaten by the plugin. Also make sure we aren't calling
// recursively. // recursively.
@ -313,7 +297,6 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
} }
} }
sInMessageDispatch = true;
LRESULT res; LRESULT res;
WNDPROC proc = (WNDPROC)win->GetWindowProc(); WNDPROC proc = (WNDPROC)win->GetWindowProc();
if (PluginWndProc == proc) { if (PluginWndProc == proc) {
@ -323,7 +306,6 @@ static LRESULT CALLBACK PluginWndProcInternal(HWND hWnd, UINT msg, WPARAM wParam
} else { } else {
res = CallWindowProc(proc, hWnd, msg, wParam, lParam); res = CallWindowProc(proc, hWnd, msg, wParam, lParam);
} }
sInMessageDispatch = false;
if (inst) { if (inst) {
// Popups are enabled (were enabled before the call to // Popups are enabled (were enabled before the call to

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

@ -146,5 +146,25 @@ ImageResource::EvaluateAnimation()
} }
} }
void
ImageResource::SendOnUnlockedDraw(uint32_t aFlags)
{
if (!mProgressTracker) {
return;
}
if (!(aFlags & FLAG_ASYNC_NOTIFY)) {
mProgressTracker->OnUnlockedDraw();
} else {
NotNull<RefPtr<ImageResource>> image = WrapNotNull(this);
NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
if (tracker) {
tracker->OnUnlockedDraw();
}
}));
}
}
} // namespace image } // namespace image
} // namespace mozilla } // namespace mozilla

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

@ -305,6 +305,8 @@ protected:
virtual nsresult StartAnimation() = 0; virtual nsresult StartAnimation() = 0;
virtual nsresult StopAnimation() = 0; virtual nsresult StopAnimation() = 0;
void SendOnUnlockedDraw(uint32_t aFlags);
// Member data shared by all implementations of this abstract class // Member data shared by all implementations of this abstract class
RefPtr<ProgressTracker> mProgressTracker; RefPtr<ProgressTracker> mProgressTracker;
RefPtr<ImageURL> mURI; RefPtr<ImageURL> mURI;

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

@ -587,8 +587,8 @@ RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
return nullptr; return nullptr;
} }
if (IsUnlocked() && mProgressTracker) { if (IsUnlocked()) {
mProgressTracker->OnUnlockedDraw(); SendOnUnlockedDraw(aFlags);
} }
RefPtr<layers::ImageContainer> container = mImageContainer.get(); RefPtr<layers::ImageContainer> container = mImageContainer.get();
@ -1343,10 +1343,11 @@ RasterImage::Draw(gfxContext* aContext,
return DrawResult::BAD_ARGS; return DrawResult::BAD_ARGS;
} }
if (IsUnlocked() && mProgressTracker) { if (IsUnlocked()) {
mProgressTracker->OnUnlockedDraw(); SendOnUnlockedDraw(aFlags);
} }
// If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or
// downscale during decode. // downscale during decode.
uint32_t flags = aSamplingFilter == SamplingFilter::GOOD uint32_t flags = aSamplingFilter == SamplingFilter::GOOD

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

@ -835,8 +835,8 @@ VectorImage::Draw(gfxContext* aContext,
return DrawResult::TEMPORARY_ERROR; return DrawResult::TEMPORARY_ERROR;
} }
if (mAnimationConsumers == 0 && mProgressTracker) { if (mAnimationConsumers == 0) {
mProgressTracker->OnUnlockedDraw(); SendOnUnlockedDraw(aFlags);
} }
AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing); AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);

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

@ -374,7 +374,7 @@ nsICODecoder::ReadBIH(const char* aData)
// tells it to skip this, and pass in the required data (dataOffset) that // tells it to skip this, and pass in the required data (dataOffset) that
// would have been present in the header. // would have been present in the header.
uint32_t dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE; uint32_t dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE;
if (mDirEntry.mBitCount <= 8) { if (mBPP <= 8) {
// The color table is present only if BPP is <= 8. // The color table is present only if BPP is <= 8.
uint16_t numColors = GetNumColors(); uint16_t numColors = GetNumColors();
if (numColors == (uint16_t)-1) { if (numColors == (uint16_t)-1) {

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

@ -340,12 +340,20 @@ nsPNGDecoder::InitInternal()
png_set_check_for_invalid_index(mPNG, 0); png_set_check_for_invalid_index(mPNG, 0);
#endif #endif
#if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_sRGB_PROFILE_CHECKS) && \ #ifdef PNG_SET_OPTION_SUPPORTED
PNG_sRGB_PROFILE_CHECKS >= 0 #if defined(PNG_sRGB_PROFILE_CHECKS) && PNG_sRGB_PROFILE_CHECKS >= 0
// Skip checking of sRGB ICC profiles // Skip checking of sRGB ICC profiles
png_set_option(mPNG, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); png_set_option(mPNG, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
#endif #endif
#ifdef PNG_MAXIMUM_INFLATE_WINDOW
// Force a larger zlib inflate window as some images in the wild have
// incorrectly set metadata (specifically CMF bits) which prevent us from
// decoding them otherwise.
png_set_option(mPNG, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
#endif
#endif
// use this as libpng "progressive pointer" (retrieve in callbacks) // use this as libpng "progressive pointer" (retrieve in callbacks)
png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this), png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
nsPNGDecoder::info_callback, nsPNGDecoder::info_callback,

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

@ -558,6 +558,15 @@ ImageTestCase CorruptICOWithBadBMPHeightTestCase()
IntSize(100, 100), TEST_CASE_HAS_ERROR); IntSize(100, 100), TEST_CASE_HAS_ERROR);
} }
ImageTestCase CorruptICOWithBadBppTestCase()
{
// This test case is an ICO with a BPP (15) in the ICO header which differs
// from that in the BMP header itself (1). It should ignore the ICO BPP when
// the BMP BPP is available and thus correctly decode the image.
return ImageTestCase("corrupt-with-bad-ico-bpp.ico", "image/x-icon",
IntSize(100, 100), TEST_CASE_IS_TRANSPARENT);
}
ImageTestCase TransparentPNGTestCase() ImageTestCase TransparentPNGTestCase()
{ {
return ImageTestCase("transparent.png", "image/png", IntSize(32, 32), return ImageTestCase("transparent.png", "image/png", IntSize(32, 32),

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

@ -392,6 +392,7 @@ ImageTestCase CorruptTestCase();
ImageTestCase CorruptBMPWithTruncatedHeader(); ImageTestCase CorruptBMPWithTruncatedHeader();
ImageTestCase CorruptICOWithBadBMPWidthTestCase(); ImageTestCase CorruptICOWithBadBMPWidthTestCase();
ImageTestCase CorruptICOWithBadBMPHeightTestCase(); ImageTestCase CorruptICOWithBadBMPHeightTestCase();
ImageTestCase CorruptICOWithBadBppTestCase();
ImageTestCase TransparentPNGTestCase(); ImageTestCase TransparentPNGTestCase();
ImageTestCase TransparentGIFTestCase(); ImageTestCase TransparentGIFTestCase();

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

@ -364,6 +364,11 @@ TEST_F(ImageDecoders, CorruptICOWithBadBMPHeightMultiChunk)
CheckDecoderMultiChunk(CorruptICOWithBadBMPHeightTestCase()); CheckDecoderMultiChunk(CorruptICOWithBadBMPHeightTestCase());
} }
TEST_F(ImageDecoders, CorruptICOWithBadBppSingleChunk)
{
CheckDecoderSingleChunk(CorruptICOWithBadBppTestCase());
}
TEST_F(ImageDecoders, AnimatedGIFWithFRAME_FIRST) TEST_F(ImageDecoders, AnimatedGIFWithFRAME_FIRST)
{ {
ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase(); ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();

Двоичные данные
image/test/gtest/corrupt-with-bad-ico-bpp.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

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

@ -35,6 +35,7 @@ TEST_HARNESS_FILES.gtest += [
'animated-with-extra-image-sub-blocks.gif', 'animated-with-extra-image-sub-blocks.gif',
'corrupt-with-bad-bmp-height.ico', 'corrupt-with-bad-bmp-height.ico',
'corrupt-with-bad-bmp-width.ico', 'corrupt-with-bad-bmp-width.ico',
'corrupt-with-bad-ico-bpp.ico',
'corrupt.jpg', 'corrupt.jpg',
'downscaled.bmp', 'downscaled.bmp',
'downscaled.gif', 'downscaled.gif',

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

@ -110,6 +110,10 @@ resumption value has one of the following forms:
the `new` expression returns the frame's `this` value. Similarly, if the `new` expression returns the frame's `this` value. Similarly, if
the function is the constructor for a subclass, then a non-object the function is the constructor for a subclass, then a non-object
value may result in a TypeError. value may result in a TypeError.
If the frame is a generator or async function, then <i>value</i> must
conform to the iterator protocol: it must be a non-proxy object of the form
<code>{ done: <i>boolean</i>, value: <i>v</i> }</code>, where
both `done` and `value` are ordinary properties.
<code>{ throw: <i>value</i> }</code> <code>{ throw: <i>value</i> }</code>
: Throw <i>value</i> as an exception from the current bytecode : Throw <i>value</i> as an exception from the current bytecode

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

@ -0,0 +1,130 @@
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = Debugger(g);
g.eval(`
async function f() {
return e;
}
`);
// To continue testing after uncaught exception, remember the exception and
// return normal completeion.
var currentFrame;
var uncaughtException;
dbg.uncaughtExceptionHook = function(e) {
uncaughtException = e;
return {
return: currentFrame.eval("({ done: true, value: 'uncaught' })").return
};
};
function testUncaughtException() {
uncaughtException = undefined;
var val = g.eval(`
var val;
f().then(v => { val = v });
drainJobQueue();
val;
`);
assertEq(val, "uncaught");
assertEq(uncaughtException instanceof TypeError, true);
}
// Just continue
dbg.onExceptionUnwind = function(frame) {
return undefined;
};
g.eval(`
var E;
f().catch(e => { exc = e });
drainJobQueue();
assertEq(exc instanceof ReferenceError, true);
`);
// Should return object.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: "foo"
};
};
testUncaughtException();
// The object should have `done` property and `value` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({})").return
};
};
testUncaughtException();
// The object should have `done` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ value: 10 })").return
};
};
testUncaughtException();
// The object should have `value` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true })").return
};
};
testUncaughtException();
// `done` property should be a boolean value.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: 10, value: 10 })").return
};
};
testUncaughtException();
// `done` property shouldn't be an accessor.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ get done() { return true; }, value: 10 })").return
};
};
testUncaughtException();
// `value` property shouldn't be an accessor.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true, get value() { return 10; } })").return
};
};
testUncaughtException();
// The object shouldn't be a Proxy.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("new Proxy({ done: true, value: 10 }, {})").return
};
};
testUncaughtException();
// Correct resumption value.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true, value: 10 })").return
};
};
var val = g.eval(`
var val;
f().then(v => { val = v });
drainJobQueue();
val;
`);
assertEq(val, 10);

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

@ -0,0 +1,117 @@
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = Debugger(g);
g.eval(`
function* f() {
e;
}
`);
// To continue testing after uncaught exception, remember the exception and
// return normal completeion.
var currentFrame;
var uncaughtException;
dbg.uncaughtExceptionHook = function(e) {
uncaughtException = e;
return {
return: currentFrame.eval("({ done: true, value: 'uncaught' })").return
};
};
function testUncaughtException() {
uncaughtException = undefined;
var obj = g.eval(`f().next()`);
assertEq(obj.done, true);
assertEq(obj.value, 'uncaught');
assertEq(uncaughtException instanceof TypeError, true);
}
// Just continue
dbg.onExceptionUnwind = function(frame) {
return undefined;
};
assertThrowsInstanceOf(() => g.eval(`f().next();`), g.ReferenceError);
// Should return object.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: "foo"
};
};
testUncaughtException();
// The object should have `done` property and `value` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({})").return
};
};
testUncaughtException();
// The object should have `done` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ value: 10 })").return
};
};
testUncaughtException();
// The object should have `value` property.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true })").return
};
};
testUncaughtException();
// `done` property should be a boolean value.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: 10, value: 10 })").return
};
};
testUncaughtException();
// `done` property shouldn't be an accessor.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ get done() { return true; }, value: 10 })").return
};
};
testUncaughtException();
// `value` property shouldn't be an accessor.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true, get value() { return 10; } })").return
};
};
testUncaughtException();
// The object shouldn't be a Proxy.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("new Proxy({ done: true, value: 10 }, {})").return
};
};
testUncaughtException();
// Correct resumption value.
dbg.onExceptionUnwind = function(frame) {
currentFrame = frame;
return {
return: frame.eval("({ done: true, value: 10 })").return
};
};
var obj = g.eval(`f().next()`);
assertEq(obj.done, true);
assertEq(obj.value, 10);

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

@ -7,7 +7,7 @@ load(libdir + 'iteration.js')
var g = newGlobal(); var g = newGlobal();
g.debuggeeGlobal = this; g.debuggeeGlobal = this;
g.eval("var dbg = new Debugger(debuggeeGlobal);" + g.eval("var dbg = new Debugger(debuggeeGlobal);" +
"dbg.onDebuggerStatement = function () { return {return: '!'}; };"); "dbg.onDebuggerStatement = function (frame) { return { return: frame.eval(\"({ done: true, value: '!' })\").return }; };");
function* gen() { function* gen() {
yield '1'; yield '1';
@ -16,6 +16,6 @@ function* gen() {
} }
var iter = gen(); var iter = gen();
assertIteratorNext(iter, '1'); assertIteratorNext(iter, '1');
assertEq(iter.next(), '!'); assertIteratorDone(iter, '!');
iter.next(); iter.next();
assertEq(0, 1); assertEq(0, 1);

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

@ -432,10 +432,12 @@ MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not
// Debugger // Debugger
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null") MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value")
MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number") MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number")
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset") MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}") MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null") MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
MSG_DEF(JSMSG_DEBUG_BAD_YIELD, 0, JSEXN_TYPEERR, "generator yielded invalid value")
MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_TYPEERR, "passing non-debuggable global to addDebuggee") MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_TYPEERR, "passing non-debuggable global to addDebuggee")
MSG_DEF(JSMSG_DEBUG_CCW_REQUIRED, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment") MSG_DEF(JSMSG_DEBUG_CCW_REQUIRED, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object") MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")

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

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

@ -9,6 +9,7 @@
#include "jscompartment.h" #include "jscompartment.h"
#include "builtin/Promise.h" #include "builtin/Promise.h"
#include "vm/GeneratorObject.h"
#include "vm/GlobalObject.h" #include "vm/GlobalObject.h"
#include "vm/Interpreter.h" #include "vm/Interpreter.h"
#include "vm/SelfHosting.h" #include "vm/SelfHosting.h"
@ -232,3 +233,8 @@ js::IsWrappedAsyncFunction(JSFunction* fun)
return fun->maybeNative() == WrappedAsyncFunction; return fun->maybeNative() == WrappedAsyncFunction;
} }
MOZ_MUST_USE bool
js::CheckAsyncResumptionValue(JSContext* cx, HandleValue v)
{
return CheckStarGeneratorResumptionValue(cx, v);
}

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

@ -32,6 +32,9 @@ MOZ_MUST_USE bool
AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise, AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
HandleValue generatorVal, HandleValue reason); HandleValue generatorVal, HandleValue reason);
MOZ_MUST_USE bool
CheckAsyncResumptionValue(JSContext* cx, HandleValue v);
} // namespace js } // namespace js
#endif /* vm_AsyncFunction_h */ #endif /* vm_AsyncFunction_h */

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

@ -32,7 +32,9 @@
#include "js/Vector.h" #include "js/Vector.h"
#include "proxy/ScriptedProxyHandler.h" #include "proxy/ScriptedProxyHandler.h"
#include "vm/ArgumentsObject.h" #include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
#include "vm/DebuggerMemory.h" #include "vm/DebuggerMemory.h"
#include "vm/GeneratorObject.h"
#include "vm/SPSProfiler.h" #include "vm/SPSProfiler.h"
#include "vm/TraceLogging.h" #include "vm/TraceLogging.h"
#include "vm/WrapperObject.h" #include "vm/WrapperObject.h"
@ -1557,6 +1559,24 @@ static bool
CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleValue>& maybeThisv, CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleValue>& maybeThisv,
JSTrapStatus status, MutableHandleValue vp) JSTrapStatus status, MutableHandleValue vp)
{ {
if (status == JSTRAP_RETURN && frame && frame.isFunctionFrame()) {
// Don't let a { return: ... } resumption value make a generator or
// async function violate the iterator protocol. The return value from
// such a frame must have the form { done: <bool>, value: <anything> }.
RootedFunction callee(cx, frame.callee());
if (callee->isAsync()) {
if (!CheckAsyncResumptionValue(cx, vp)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_AWAIT);
return false;
}
} else if (callee->isStarGenerator()) {
if (!CheckStarGeneratorResumptionValue(cx, vp)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_YIELD);
return false;
}
}
}
if (maybeThisv.isSome()) { if (maybeThisv.isSome()) {
const HandleValue& thisv = maybeThisv.ref(); const HandleValue& thisv = maybeThisv.ref();
if (status == JSTRAP_RETURN && vp.isPrimitive()) { if (status == JSTRAP_RETURN && vp.isPrimitive()) {

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

@ -6,6 +6,8 @@
#include "vm/GeneratorObject.h" #include "vm/GeneratorObject.h"
#include "jsobj.h"
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -334,3 +336,32 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
global->setReservedSlot(STAR_GENERATOR_FUNCTION_PROTO, ObjectValue(*genFunctionProto)); global->setReservedSlot(STAR_GENERATOR_FUNCTION_PROTO, ObjectValue(*genFunctionProto));
return true; return true;
} }
MOZ_MUST_USE bool
js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
{
// yield/return value should be an Object.
if (!v.isObject())
return false;
JSObject* obj = &v.toObject();
// It should have `done` data property with boolean value.
Value doneVal;
if (!GetPropertyPure(cx, obj, NameToId(cx->names().done), &doneVal))
return false;
if (!doneVal.isBoolean())
return false;
// It should have `value` data property, but the type doesn't matter
JSObject* ignored;
Shape* shape;
if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &shape))
return false;
if (!shape)
return false;
if (!shape->hasDefaultGetter())
return false;
return true;
}

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

@ -216,6 +216,9 @@ bool GeneratorThrowOrClose(JSContext* cx, AbstractFramePtr frame, Handle<Generat
HandleValue val, uint32_t resumeKind); HandleValue val, uint32_t resumeKind);
void SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame); void SetReturnValueForClosingGenerator(JSContext* cx, AbstractFramePtr frame);
MOZ_MUST_USE bool
CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v);
} // namespace js } // namespace js
template<> template<>

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

@ -147,7 +147,6 @@ using namespace mozilla::gfx;
#define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled" #define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled"
#define GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME "layout.css.grid-template-subgrid-value.enabled" #define GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME "layout.css.grid-template-subgrid-value.enabled"
#define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit" #define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit"
#define DISPLAY_CONTENTS_ENABLED_PREF_NAME "layout.css.display-contents.enabled"
#define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled" #define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled"
#define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled" #define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled"
#define BG_CLIP_TEXT_ENABLED_PREF_NAME "layout.css.background-clip-text.enabled" #define BG_CLIP_TEXT_ENABLED_PREF_NAME "layout.css.background-clip-text.enabled"
@ -312,36 +311,6 @@ WebkitPrefixEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
} }
} }
// When the pref "layout.css.display-contents.enabled" changes, this function is
// invoked to let us update kDisplayKTable, to selectively disable or restore
// the entries for "contents" in that table.
static void
DisplayContentsEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
{
NS_ASSERTION(strcmp(aPrefName, DISPLAY_CONTENTS_ENABLED_PREF_NAME) == 0,
"Did you misspell " DISPLAY_CONTENTS_ENABLED_PREF_NAME " ?");
static bool sIsDisplayContentsKeywordIndexInitialized;
static int32_t sIndexOfContentsInDisplayTable;
bool isDisplayContentsEnabled =
Preferences::GetBool(DISPLAY_CONTENTS_ENABLED_PREF_NAME, false);
if (!sIsDisplayContentsKeywordIndexInitialized) {
// First run: find the position of "contents" in kDisplayKTable.
sIndexOfContentsInDisplayTable =
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_contents,
nsCSSProps::kDisplayKTable);
sIsDisplayContentsKeywordIndexInitialized = true;
}
// OK -- now, stomp on or restore the "contents" entry in kDisplayKTable,
// depending on whether the pref is enabled vs. disabled.
if (sIndexOfContentsInDisplayTable >= 0) {
nsCSSProps::kDisplayKTable[sIndexOfContentsInDisplayTable].mKeyword =
isDisplayContentsEnabled ? eCSSKeyword_contents : eCSSKeyword_UNKNOWN;
}
}
// When the pref "layout.css.text-align-unsafe-value.enabled" changes, this // When the pref "layout.css.text-align-unsafe-value.enabled" changes, this
// function is called to let us update kTextAlignKTable & kTextAlignLastKTable, // function is called to let us update kTextAlignKTable & kTextAlignLastKTable,
// to selectively disable or restore the entries for "unsafe" in those tables. // to selectively disable or restore the entries for "unsafe" in those tables.
@ -7536,8 +7505,6 @@ static const PrefCallbacks kPrefCallbacks[] = {
WebkitPrefixEnabledPrefChangeCallback }, WebkitPrefixEnabledPrefChangeCallback },
{ TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME, { TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
TextAlignUnsafeEnabledPrefChangeCallback }, TextAlignUnsafeEnabledPrefChangeCallback },
{ DISPLAY_CONTENTS_ENABLED_PREF_NAME,
DisplayContentsEnabledPrefChangeCallback },
{ FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME, { FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
FloatLogicalValuesEnabledPrefChangeCallback }, FloatLogicalValuesEnabledPrefChangeCallback },
{ BG_CLIP_TEXT_ENABLED_PREF_NAME, { BG_CLIP_TEXT_ENABLED_PREF_NAME,

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

@ -2,36 +2,36 @@
# Tests for CSS Display spec features. # Tests for CSS Display spec features.
# http://dev.w3.org/csswg/css-display # http://dev.w3.org/csswg/css-display
fuzzy-if(Android,8,604) pref(layout.css.display-contents.enabled,true) == display-contents-acid.html display-contents-acid.html fuzzy-if(Android,8,604) == display-contents-acid.html display-contents-acid.html
random pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-1.html display-contents-acid-dyn-1.html random == display-contents-acid-dyn-1.html display-contents-acid-dyn-1.html
random pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-2.html display-contents-acid-dyn-2.html random == display-contents-acid-dyn-2.html display-contents-acid-dyn-2.html
random pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-3.html display-contents-acid-dyn-3.html random == display-contents-acid-dyn-3.html display-contents-acid-dyn-3.html
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content.html display-contents-generated-content.html == display-contents-generated-content.html display-contents-generated-content.html
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content-2.html display-contents-generated-content-2.html == display-contents-generated-content-2.html display-contents-generated-content-2.html
pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1.html display-contents-style-inheritance-1.html == display-contents-style-inheritance-1.html display-contents-style-inheritance-1.html
skip pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-stylechange.html skip == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-stylechange.html
skip pref(layout.css.display-contents.enabled,true) fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-dom-mutations.html skip fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-dom-mutations.html
pref(layout.css.display-contents.enabled,true) == display-contents-tables.xhtml display-contents-tables.xhtml == display-contents-tables.xhtml display-contents-tables.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-tables-2.xhtml display-contents-tables-2.xhtml == display-contents-tables-2.xhtml display-contents-tables-2.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-tables-3.xhtml display-contents-tables-3.xhtml == display-contents-tables-3.xhtml display-contents-tables-3.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-visibility-hidden.html display-contents-visibility-hidden.html == display-contents-visibility-hidden.html display-contents-visibility-hidden.html
pref(layout.css.display-contents.enabled,true) == display-contents-visibility-hidden-2.html display-contents-visibility-hidden-2.html == display-contents-visibility-hidden-2.html display-contents-visibility-hidden-2.html
random pref(layout.css.display-contents.enabled,true) == display-contents-495385-2d.html display-contents-495385-2d.html random == display-contents-495385-2d.html display-contents-495385-2d.html
skip-if(B2G||Mulet) fuzzy-if(Android,7,3935) pref(layout.css.display-contents.enabled,true) == display-contents-xbl.xhtml display-contents-xbl.xhtml skip-if(B2G||Mulet) fuzzy-if(Android,7,3935) == display-contents-xbl.xhtml display-contents-xbl.xhtml
# Initial mulet triage: parity with B2G/B2G Desktop # Initial mulet triage: parity with B2G/B2G Desktop
# fuzzy-if(Android,7,1186) pref(layout.css.display-contents.enabled,true) pref(dom.webcomponents.enabled,true) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1.html # fuzzy-if(Android,7,1186) pref(dom.webcomponents.enabled,true) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1.html
skip-if(B2G||Mulet) pref(layout.css.display-contents.enabled,true) == display-contents-xbl-2.xul display-contents-xbl-2.xul skip-if(B2G||Mulet) == display-contents-xbl-2.xul display-contents-xbl-2.xul
# Initial mulet triage: parity with B2G/B2G Desktop # Initial mulet triage: parity with B2G/B2G Desktop
skip-if(B2G||Mulet) asserts(1) pref(layout.css.display-contents.enabled,true) == display-contents-xbl-3.xul display-contents-xbl-3.xul skip-if(B2G||Mulet) asserts(1) == display-contents-xbl-3.xul display-contents-xbl-3.xul
# bug 1089223 # bug 1089223
# Initial mulet triage: parity with B2G/B2G Desktop # Initial mulet triage: parity with B2G/B2G Desktop
skip pref(layout.css.display-contents.enabled,true) == display-contents-xbl-4.xul display-contents-xbl-4.xul skip == display-contents-xbl-4.xul display-contents-xbl-4.xul
# fails (not just asserts) due to bug 1089223 # fails (not just asserts) due to bug 1089223
asserts(0-1) fuzzy-if(Android,8,3216) pref(layout.css.display-contents.enabled,true) == display-contents-fieldset.html display-contents-fieldset.html asserts(0-1) fuzzy-if(Android,8,3216) == display-contents-fieldset.html display-contents-fieldset.html
# bug 1089223 # bug 1089223
skip-if(B2G||Mulet) asserts(1) pref(layout.css.display-contents.enabled,true) == display-contents-xbl-5.xul display-contents-xbl-5.xul skip-if(B2G||Mulet) asserts(1) == display-contents-xbl-5.xul display-contents-xbl-5.xul
# bug 1089223 # bug 1089223
# Initial mulet triage: parity with B2G/B2G Desktop # Initial mulet triage: parity with B2G/B2G Desktop
pref(layout.css.display-contents.enabled,true) == display-contents-list-item-child.html display-contents-list-item-child.html == display-contents-list-item-child.html display-contents-list-item-child.html
pref(layout.css.display-contents.enabled,true) == display-contents-writing-mode-1.html display-contents-writing-mode-1.html == display-contents-writing-mode-1.html display-contents-writing-mode-1.html
pref(layout.css.display-contents.enabled,true) == display-contents-writing-mode-2.html display-contents-writing-mode-2.html == display-contents-writing-mode-2.html display-contents-writing-mode-2.html

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

@ -1,28 +1,28 @@
# Tests for CSS Display spec features. # Tests for CSS Display spec features.
# http://dev.w3.org/csswg/css-display # http://dev.w3.org/csswg/css-display
fuzzy-if(Android,8,604) pref(layout.css.display-contents.enabled,true) == display-contents-acid.html display-contents-acid-ref.html fuzzy-if(Android,8,604) == display-contents-acid.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-1.html display-contents-acid-ref.html fuzzy-if(Android,8,604) == display-contents-acid-dyn-1.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-2.html display-contents-acid-ref.html fuzzy-if(Android,8,604) == display-contents-acid-dyn-2.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) pref(layout.css.display-contents.enabled,true) == display-contents-acid-dyn-3.html display-contents-acid-ref.html fuzzy-if(Android,8,604) == display-contents-acid-dyn-3.html display-contents-acid-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content.html display-contents-generated-content-ref.html == display-contents-generated-content.html display-contents-generated-content-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content-2.html display-contents-generated-content-ref.html == display-contents-generated-content-2.html display-contents-generated-content-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1.html display-contents-style-inheritance-1-ref.html == display-contents-style-inheritance-1.html display-contents-style-inheritance-1-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-ref.html == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-ref.html
pref(layout.css.display-contents.enabled,true) fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-ref.html fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-tables.xhtml display-contents-tables-ref.xhtml == display-contents-tables.xhtml display-contents-tables-ref.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-tables-2.xhtml display-contents-tables-ref.xhtml == display-contents-tables-2.xhtml display-contents-tables-ref.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-tables-3.xhtml display-contents-tables-3-ref.xhtml == display-contents-tables-3.xhtml display-contents-tables-3-ref.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-visibility-hidden.html display-contents-visibility-hidden-ref.html == display-contents-visibility-hidden.html display-contents-visibility-hidden-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-visibility-hidden-2.html display-contents-visibility-hidden-ref.html == display-contents-visibility-hidden-2.html display-contents-visibility-hidden-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-495385-2d.html display-contents-495385-2d-ref.html == display-contents-495385-2d.html display-contents-495385-2d-ref.html
fuzzy-if(Android,7,3935) pref(layout.css.display-contents.enabled,true) == display-contents-xbl.xhtml display-contents-xbl-ref.html fuzzy-if(Android,7,3935) == display-contents-xbl.xhtml display-contents-xbl-ref.html
fuzzy-if(Android,7,1186) pref(layout.css.display-contents.enabled,true) pref(dom.webcomponents.enabled,true) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1-ref.html fuzzy-if(Android,7,1186) pref(dom.webcomponents.enabled,true) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-xbl-2.xul display-contents-xbl-2-ref.xul == display-contents-xbl-2.xul display-contents-xbl-2-ref.xul
asserts(1) pref(layout.css.display-contents.enabled,true) == display-contents-xbl-3.xul display-contents-xbl-3-ref.xul # bug 1089223 asserts(1) == display-contents-xbl-3.xul display-contents-xbl-3-ref.xul # bug 1089223
skip pref(layout.css.display-contents.enabled,true) == display-contents-xbl-4.xul display-contents-xbl-4-ref.xul # fails (not just asserts) due to bug 1089223 skip == display-contents-xbl-4.xul display-contents-xbl-4-ref.xul # fails (not just asserts) due to bug 1089223
asserts(0-1) fuzzy-if(Android,8,3216) pref(layout.css.display-contents.enabled,true) == display-contents-fieldset.html display-contents-fieldset-ref.html # bug 1089223 asserts(0-1) fuzzy-if(Android,8,3216) == display-contents-fieldset.html display-contents-fieldset-ref.html # bug 1089223
asserts(1) pref(layout.css.display-contents.enabled,true) == display-contents-xbl-5.xul display-contents-xbl-3-ref.xul # bug 1089223 asserts(1) == display-contents-xbl-5.xul display-contents-xbl-3-ref.xul # bug 1089223
pref(layout.css.display-contents.enabled,true) == display-contents-list-item-child.html display-contents-list-item-child-ref.html == display-contents-list-item-child.html display-contents-list-item-child-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-writing-mode-1.html display-contents-writing-mode-1-ref.html == display-contents-writing-mode-1.html display-contents-writing-mode-1-ref.html
pref(layout.css.display-contents.enabled,true) == display-contents-writing-mode-2.html display-contents-writing-mode-2-ref.html == display-contents-writing-mode-2.html display-contents-writing-mode-2-ref.html

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

@ -1330,8 +1330,6 @@ KTableEntry nsCSSProps::kDisplayKTable[] = {
{ eCSSKeyword__webkit_inline_box, StyleDisplay::WebkitInlineBox }, { eCSSKeyword__webkit_inline_box, StyleDisplay::WebkitInlineBox },
{ eCSSKeyword__webkit_flex, StyleDisplay::Flex }, { eCSSKeyword__webkit_flex, StyleDisplay::Flex },
{ eCSSKeyword__webkit_inline_flex, StyleDisplay::InlineFlex }, { eCSSKeyword__webkit_inline_flex, StyleDisplay::InlineFlex },
// The next entry is controlled by the layout.css.display-contents.enabled
// pref.
{ eCSSKeyword_contents, StyleDisplay::Contents }, { eCSSKeyword_contents, StyleDisplay::Contents },
{ eCSSKeyword_UNKNOWN, -1 } { eCSSKeyword_UNKNOWN, -1 }
}; };

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

@ -6671,9 +6671,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
}; };
} }
if (IsCSSPropertyPrefEnabled("layout.css.display-contents.enabled")) {
gCSSProperties["display"].other_values.push("contents"); gCSSProperties["display"].other_values.push("contents");
}
if (IsCSSPropertyPrefEnabled("layout.css.contain.enabled")) { if (IsCSSPropertyPrefEnabled("layout.css.contain.enabled")) {
gCSSProperties["contain"] = { gCSSProperties["contain"] = {

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

@ -25,6 +25,7 @@
#define PNG_LINKAGE_DATA extern #define PNG_LINKAGE_DATA extern
#define PNG_LINKAGE_FUNCTION extern #define PNG_LINKAGE_FUNCTION extern
#define PNG_MAX_GAMMA_8 11 #define PNG_MAX_GAMMA_8 11
#define PNG_SET_OPTION_SUPPORTED
#define PNG_sRGB_PROFILE_CHECKS -1 #define PNG_sRGB_PROFILE_CHECKS -1
#define PNG_USER_CHUNK_CACHE_MAX 128 #define PNG_USER_CHUNK_CACHE_MAX 128
#define PNG_USER_CHUNK_MALLOC_MAX 4000000L #define PNG_USER_CHUNK_MALLOC_MAX 4000000L

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

@ -2619,9 +2619,6 @@ pref("layout.css.grid-template-subgrid-value.enabled", false);
// Is support for CSS contain enabled? // Is support for CSS contain enabled?
pref("layout.css.contain.enabled", false); pref("layout.css.contain.enabled", false);
// Is support for CSS display:contents enabled?
pref("layout.css.display-contents.enabled", true);
// Is support for CSS box-decoration-break enabled? // Is support for CSS box-decoration-break enabled?
pref("layout.css.box-decoration-break.enabled", true); pref("layout.css.box-decoration-break.enabled", true);

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

@ -95,7 +95,7 @@ mochitest:
instance-size: xlarge instance-size: xlarge
chunks: chunks:
by-test-platform: by-test-platform:
android-4.3-arm7-api-15/debug: 26 android-4.3-arm7-api-15/debug: 32
default: 20 default: 20
loopback-video: true loopback-video: true
e10s: false e10s: false

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

@ -130,6 +130,7 @@ class ChecksumsGenerator(BaseScript, VirtualenvMixin, SigningMixin, VCSMixin, Bu
r"^.*\.mar$", r"^.*\.mar$",
r"^.*Setup.*\.exe$", r"^.*Setup.*\.exe$",
r"^.*\.xpi$", r"^.*\.xpi$",
r"^.*fennec.*\.apk$",
] ]
def _get_bucket_name(self): def _get_bucket_name(self):

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

@ -49,6 +49,7 @@ class ReleasePusher(BaseScript, VirtualenvMixin):
r"^.*/host.*$", r"^.*/host.*$",
r"^.*/mar-tools/.*$", r"^.*/mar-tools/.*$",
r"^.*robocop.apk$", r"^.*robocop.apk$",
r"^.*bouncer.apk$",
r"^.*contrib.*", r"^.*contrib.*",
r"^.*/beetmover-checksums/.*$", r"^.*/beetmover-checksums/.*$",
], ],

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

@ -115,6 +115,22 @@ public:
return ent->mData; return ent->mData;
} }
/**
* Add key to the table if not already present, and return a reference to its
* value. If key is not already in the table then the value is default
* constructed.
*/
DataType& GetOrInsert(const KeyType& aKey)
{
EntryType* ent = this->GetEntry(aKey);
if (ent) {
return ent->mData;
}
ent = this->PutEntry(aKey);
return ent->mData;
}
/** /**
* put a new value for the associated key * put a new value for the associated key
* @param aKey the key to put * @param aKey the key to put