зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
17a7875e17
|
@ -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,89 +24,71 @@ 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) {
|
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
|
||||||
// 404 doesn't work on HTTPS test harness.
|
"GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
|
||||||
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
|
status: 404,
|
||||||
"GET", sjsURL + "?fmt=bogus", {
|
statusText: "Not Found",
|
||||||
status: 404,
|
type: "html",
|
||||||
statusText: "Not Found",
|
fullMimeType: "text/html; charset=utf-8",
|
||||||
type: "html",
|
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
|
||||||
fullMimeType: "text/html; charset=utf-8",
|
time: true
|
||||||
size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
|
});
|
||||||
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(¤tLevel);
|
|
||||||
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();
|
||||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче