зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-central to Places.
This commit is contained in:
Коммит
3bf8642bdb
|
@ -306,8 +306,8 @@ AccTextChangeEvent::CreateXPCOMObject()
|
|||
|
||||
AccMutationEvent::
|
||||
AccMutationEvent(PRUint32 aEventType, nsAccessible* aTarget,
|
||||
nsINode* aTargetNode, EIsFromUserInput aIsFromUserInput) :
|
||||
AccEvent(aEventType, aTarget, aIsFromUserInput, eCoalesceFromSameSubtree)
|
||||
nsINode* aTargetNode) :
|
||||
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceFromSameSubtree)
|
||||
{
|
||||
mNode = aTargetNode;
|
||||
}
|
||||
|
@ -318,10 +318,8 @@ AccMutationEvent::
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AccHideEvent::
|
||||
AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
|
||||
EIsFromUserInput aIsFromUserInput) :
|
||||
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode,
|
||||
aIsFromUserInput)
|
||||
AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
|
||||
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
|
||||
{
|
||||
mParent = mAccessible->GetCachedParent();
|
||||
mNextSibling = mAccessible->GetCachedNextSibling();
|
||||
|
@ -334,10 +332,8 @@ AccHideEvent::
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AccShowEvent::
|
||||
AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode,
|
||||
EIsFromUserInput aIsFromUserInput) :
|
||||
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode,
|
||||
aIsFromUserInput)
|
||||
AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode) :
|
||||
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ protected:
|
|||
nsRefPtr<nsAccessible> mAccessible;
|
||||
nsCOMPtr<nsINode> mNode;
|
||||
|
||||
friend class nsAccEventQueue;
|
||||
friend class NotificationController;
|
||||
};
|
||||
|
||||
|
||||
|
@ -230,7 +230,7 @@ private:
|
|||
PRBool mIsInserted;
|
||||
nsString mModifiedText;
|
||||
|
||||
friend class nsAccEventQueue;
|
||||
friend class NotificationController;
|
||||
};
|
||||
|
||||
|
||||
|
@ -241,7 +241,7 @@ class AccMutationEvent: public AccEvent
|
|||
{
|
||||
public:
|
||||
AccMutationEvent(PRUint32 aEventType, nsAccessible* aTarget,
|
||||
nsINode* aTargetNode, EIsFromUserInput aIsFromUserInput);
|
||||
nsINode* aTargetNode);
|
||||
|
||||
// Event
|
||||
static const EventGroup kEventGroup = eMutationEvent;
|
||||
|
@ -257,7 +257,7 @@ public:
|
|||
protected:
|
||||
nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
|
||||
|
||||
friend class nsAccEventQueue;
|
||||
friend class NotificationController;
|
||||
};
|
||||
|
||||
|
||||
|
@ -267,8 +267,7 @@ protected:
|
|||
class AccHideEvent: public AccMutationEvent
|
||||
{
|
||||
public:
|
||||
AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode,
|
||||
EIsFromUserInput aIsFromUserInput);
|
||||
AccHideEvent(nsAccessible* aTarget, nsINode* aTargetNode);
|
||||
|
||||
// Event
|
||||
static const EventGroup kEventGroup = eHideEvent;
|
||||
|
@ -282,7 +281,7 @@ protected:
|
|||
nsRefPtr<nsAccessible> mNextSibling;
|
||||
nsRefPtr<nsAccessible> mPrevSibling;
|
||||
|
||||
friend class nsAccEventQueue;
|
||||
friend class NotificationController;
|
||||
};
|
||||
|
||||
|
||||
|
@ -292,8 +291,7 @@ protected:
|
|||
class AccShowEvent: public AccMutationEvent
|
||||
{
|
||||
public:
|
||||
AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode,
|
||||
EIsFromUserInput aIsFromUserInput);
|
||||
AccShowEvent(nsAccessible* aTarget, nsINode* aTargetNode);
|
||||
|
||||
// Event
|
||||
static const EventGroup kEventGroup = eShowEvent;
|
||||
|
|
|
@ -53,6 +53,7 @@ CPPSRCS = \
|
|||
AccGroupInfo.cpp \
|
||||
AccIterator.cpp \
|
||||
filters.cpp \
|
||||
NotificationController.cpp \
|
||||
nsAccDocManager.cpp \
|
||||
nsAccessNode.cpp \
|
||||
nsARIAGridAccessible.cpp \
|
||||
|
|
|
@ -0,0 +1,556 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsEventShell.h"
|
||||
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsDocAccessible.h"
|
||||
|
||||
#include "NotificationController.h"
|
||||
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsDocAccessible.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationCollector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NotificationController::NotificationController(nsDocAccessible* aDocument,
|
||||
nsIPresShell* aPresShell) :
|
||||
mObservingState(eNotObservingRefresh), mDocument(aDocument),
|
||||
mPresShell(aPresShell)
|
||||
{
|
||||
}
|
||||
|
||||
NotificationController::~NotificationController()
|
||||
{
|
||||
NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
|
||||
if (mDocument)
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationCollector: AddRef/Release and cycle collection
|
||||
|
||||
NS_IMPL_ADDREF(NotificationController)
|
||||
NS_IMPL_RELEASE(NotificationController)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController)
|
||||
tmp->Shutdown();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(NotificationController)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mContentInsertions,
|
||||
ContentInsertion)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mEvents, AccEvent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController, Release)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationCollector: public
|
||||
|
||||
void
|
||||
NotificationController::Shutdown()
|
||||
{
|
||||
if (mObservingState != eNotObservingRefresh &&
|
||||
mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingState = eNotObservingRefresh;
|
||||
}
|
||||
|
||||
mDocument = nsnull;
|
||||
mPresShell = nsnull;
|
||||
mContentInsertions.Clear();
|
||||
mNotifications.Clear();
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::QueueEvent(AccEvent* aEvent)
|
||||
{
|
||||
if (!mEvents.AppendElement(aEvent))
|
||||
return;
|
||||
|
||||
// Filter events.
|
||||
CoalesceEvents();
|
||||
|
||||
// Associate text change with hide event if it wasn't stolen from hiding
|
||||
// siblings during coalescence.
|
||||
AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
|
||||
if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
|
||||
CreateTextChangeEventFor(showOrHideEvent);
|
||||
|
||||
ScheduleProcessing();
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::ScheduleContentInsertion(nsAccessible* aContainer,
|
||||
nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode)
|
||||
{
|
||||
nsRefPtr<ContentInsertion> insertion =
|
||||
new ContentInsertion(mDocument, aContainer, aStartChildNode, aEndChildNode);
|
||||
|
||||
if (insertion && mContentInsertions.AppendElement(insertion))
|
||||
ScheduleProcessing();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationCollector: protected
|
||||
|
||||
void
|
||||
NotificationController::ScheduleProcessing()
|
||||
{
|
||||
// If notification flush isn't planed yet start notification flush
|
||||
// asynchronously (after style and layout).
|
||||
if (mObservingState == eNotObservingRefresh) {
|
||||
if (mPresShell->AddRefreshObserver(this, Flush_Display))
|
||||
mObservingState = eRefreshObserving;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NotificationController::IsUpdatePending()
|
||||
{
|
||||
nsCOMPtr<nsIPresShell_MOZILLA_2_0_BRANCH2> presShell =
|
||||
do_QueryInterface(mPresShell);
|
||||
return presShell->IsLayoutFlushObserver() ||
|
||||
mObservingState == eRefreshProcessingForUpdate ||
|
||||
mContentInsertions.Length() != 0 || mNotifications.Length() != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationCollector: private
|
||||
|
||||
void
|
||||
NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
// If the document accessible that notification collector was created for is
|
||||
// now shut down, don't process notifications anymore.
|
||||
NS_ASSERTION(mDocument,
|
||||
"The document was shut down while refresh observer is attached!");
|
||||
if (!mDocument)
|
||||
return;
|
||||
|
||||
// Any generic notifications should be queued if we're processing content
|
||||
// insertions or generic notifications.
|
||||
mObservingState = eRefreshProcessingForUpdate;
|
||||
|
||||
// Process content inserted notifications to update the tree. Process other
|
||||
// notifications like DOM events and then flush event queue. If any new
|
||||
// notifications are queued during this processing then they will be processed
|
||||
// on next refresh. If notification processing queues up new events then they
|
||||
// are processed in this refresh. If events processing queues up new events
|
||||
// then new events are processed on next refresh.
|
||||
// Note: notification processing or event handling may shut down the owning
|
||||
// document accessible.
|
||||
|
||||
// Process only currently queued content inserted notifications.
|
||||
nsTArray<nsRefPtr<ContentInsertion> > contentInsertions;
|
||||
contentInsertions.SwapElements(mContentInsertions);
|
||||
|
||||
PRUint32 insertionCount = contentInsertions.Length();
|
||||
for (PRUint32 idx = 0; idx < insertionCount; idx++) {
|
||||
contentInsertions[idx]->Process();
|
||||
if (!mDocument)
|
||||
return;
|
||||
}
|
||||
|
||||
// Process only currently queued generic notifications.
|
||||
nsTArray < nsRefPtr<Notification> > notifications;
|
||||
notifications.SwapElements(mNotifications);
|
||||
|
||||
PRUint32 notificationCount = notifications.Length();
|
||||
for (PRUint32 idx = 0; idx < notificationCount; idx++) {
|
||||
notifications[idx]->Process();
|
||||
if (!mDocument)
|
||||
return;
|
||||
}
|
||||
|
||||
// If a generic notification occurs after this point then we may be allowed to
|
||||
// process it synchronously.
|
||||
mObservingState = eRefreshObserving;
|
||||
|
||||
// Process only currently queued events.
|
||||
nsTArray<nsRefPtr<AccEvent> > events;
|
||||
events.SwapElements(mEvents);
|
||||
|
||||
PRUint32 eventCount = events.Length();
|
||||
for (PRUint32 idx = 0; idx < eventCount; idx++) {
|
||||
AccEvent* accEvent = events[idx];
|
||||
if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
|
||||
mDocument->ProcessPendingEvent(accEvent);
|
||||
|
||||
AccMutationEvent* showOrhideEvent = downcast_accEvent(accEvent);
|
||||
if (showOrhideEvent) {
|
||||
if (showOrhideEvent->mTextChangeEvent)
|
||||
mDocument->ProcessPendingEvent(showOrhideEvent->mTextChangeEvent);
|
||||
}
|
||||
}
|
||||
if (!mDocument)
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop further processing if there are no newly queued insertions,
|
||||
// notifications or events.
|
||||
if (mContentInsertions.Length() == 0 && mNotifications.Length() == 0 &&
|
||||
mEvents.Length() == 0 &&
|
||||
mPresShell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingState = eNotObservingRefresh;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationController: event queue
|
||||
|
||||
void
|
||||
NotificationController::CoalesceEvents()
|
||||
{
|
||||
PRUint32 numQueuedEvents = mEvents.Length();
|
||||
PRInt32 tail = numQueuedEvents - 1;
|
||||
AccEvent* tailEvent = mEvents[tail];
|
||||
|
||||
// No node means this is application accessible (which can be a subject
|
||||
// of reorder events), we do not coalesce events for it currently.
|
||||
if (!tailEvent->mNode)
|
||||
return;
|
||||
|
||||
switch(tailEvent->mEventRule) {
|
||||
case AccEvent::eCoalesceFromSameSubtree:
|
||||
{
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* thisEvent = mEvents[index];
|
||||
|
||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||
continue; // Different type
|
||||
|
||||
// Skip event for application accessible since no coalescence for it
|
||||
// is supported. Ignore events from different documents since we don't
|
||||
// coalesce them.
|
||||
if (!thisEvent->mNode ||
|
||||
thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
|
||||
continue;
|
||||
|
||||
// Coalesce earlier event for the same target.
|
||||
if (thisEvent->mNode == tailEvent->mNode) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// If event queue contains an event of the same type and having target
|
||||
// that is sibling of target of newly appended event then apply its
|
||||
// event rule to the newly appended event.
|
||||
|
||||
// Coalesce hide and show events for sibling targets.
|
||||
if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
|
||||
AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
|
||||
if (thisHideEvent->mParent == tailHideEvent->mParent) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
|
||||
// Coalesce text change events for hide events.
|
||||
if (tailEvent->mEventRule != AccEvent::eDoNotEmit)
|
||||
CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
} else if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||
if (thisEvent->mAccessible->GetParent() ==
|
||||
tailEvent->mAccessible->GetParent()) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
|
||||
// Coalesce text change events for show events.
|
||||
if (tailEvent->mEventRule != AccEvent::eDoNotEmit) {
|
||||
AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
|
||||
AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
|
||||
CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore events unattached from DOM since we don't coalesce them.
|
||||
if (!thisEvent->mNode->IsInDoc())
|
||||
continue;
|
||||
|
||||
// Coalesce events by sibling targets (this is a case for reorder
|
||||
// events).
|
||||
if (thisEvent->mNode->GetNodeParent() ==
|
||||
tailEvent->mNode->GetNodeParent()) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
return;
|
||||
}
|
||||
|
||||
// This and tail events can be anywhere in the tree, make assumptions
|
||||
// for mutation events.
|
||||
|
||||
// Coalesce tail event if tail node is descendant of this node. Stop
|
||||
// processing if tail event is coalesced since all possible descendants
|
||||
// of this node was coalesced before.
|
||||
// Note: more older hide event target (thisNode) can't contain recent
|
||||
// hide event target (tailNode), i.e. be ancestor of tailNode. Skip
|
||||
// this check for hide events.
|
||||
if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
|
||||
nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
|
||||
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this node is a descendant of tail node then coalesce this event,
|
||||
// check other events in the queue. Do not emit thisEvent, also apply
|
||||
// this result to sibling nodes of thisNode.
|
||||
if (nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(0, index, thisEvent->mEventType,
|
||||
thisEvent->mNode, AccEvent::eDoNotEmit);
|
||||
continue;
|
||||
}
|
||||
|
||||
} // for (index)
|
||||
|
||||
} break; // case eCoalesceFromSameSubtree
|
||||
|
||||
case AccEvent::eCoalesceFromSameDocument:
|
||||
{
|
||||
// Used for focus event, coalesce more older event since focus event
|
||||
// for accessible can be duplicated by event for its document, we are
|
||||
// interested in focus event for accessible.
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* thisEvent = mEvents[index];
|
||||
if (thisEvent->mEventType == tailEvent->mEventType &&
|
||||
thisEvent->mEventRule == tailEvent->mEventRule &&
|
||||
thisEvent->GetDocAccessible() == tailEvent->GetDocAccessible()) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break; // case eCoalesceFromSameDocument
|
||||
|
||||
case AccEvent::eRemoveDupes:
|
||||
{
|
||||
// Check for repeat events, coalesce newly appended event by more older
|
||||
// event.
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||
accEvent->mNode == tailEvent->mNode) {
|
||||
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break; // case eRemoveDupes
|
||||
|
||||
default:
|
||||
break; // case eAllowDupes, eDoNotEmit
|
||||
} // switch
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
AccEvent::EEventRule aEventRule)
|
||||
{
|
||||
for (PRUint32 index = aStart; index < aEnd; index ++) {
|
||||
AccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == aEventType &&
|
||||
accEvent->mEventRule != AccEvent::eDoNotEmit && accEvent->mNode &&
|
||||
accEvent->mNode->GetNodeParent() == aNode->GetNodeParent()) {
|
||||
accEvent->mEventRule = aEventRule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
|
||||
AccHideEvent* aThisEvent)
|
||||
{
|
||||
// XXX: we need a way to ignore SplitNode and JoinNode() when they do not
|
||||
// affect the text within the hypertext.
|
||||
|
||||
AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
|
||||
if (!textEvent)
|
||||
return;
|
||||
|
||||
if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
|
||||
} else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
|
||||
PRUint32 oldLen = textEvent->GetLength();
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
textEvent->mStart -= textEvent->GetLength() - oldLen;
|
||||
}
|
||||
|
||||
aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
|
||||
AccShowEvent* aThisEvent)
|
||||
{
|
||||
AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
|
||||
if (!textEvent)
|
||||
return;
|
||||
|
||||
if (aTailEvent->mAccessible->GetIndexInParent() ==
|
||||
aThisEvent->mAccessible->GetIndexInParent() + 1) {
|
||||
// If tail target was inserted after this target, i.e. tail target is next
|
||||
// sibling of this target.
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
|
||||
} else if (aTailEvent->mAccessible->GetIndexInParent() ==
|
||||
aThisEvent->mAccessible->GetIndexInParent() -1) {
|
||||
// If tail target was inserted before this target, i.e. tail target is
|
||||
// previous sibling of this target.
|
||||
nsAutoString startText;
|
||||
aTailEvent->mAccessible->AppendTextTo(startText, 0, PR_UINT32_MAX);
|
||||
textEvent->mModifiedText = startText + textEvent->mModifiedText;
|
||||
textEvent->mStart -= startText.Length();
|
||||
}
|
||||
|
||||
aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
|
||||
}
|
||||
|
||||
void
|
||||
NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
|
||||
{
|
||||
nsRefPtr<nsHyperTextAccessible> textAccessible = do_QueryObject(
|
||||
GetAccService()->GetContainerAccessible(aEvent->mNode,
|
||||
aEvent->mAccessible->GetWeakShell()));
|
||||
if (!textAccessible)
|
||||
return;
|
||||
|
||||
// Don't fire event for the first html:br in an editor.
|
||||
if (aEvent->mAccessible->Role() == nsIAccessibleRole::ROLE_WHITESPACE) {
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
|
||||
if (editor) {
|
||||
PRBool isEmpty = PR_FALSE;
|
||||
editor->GetDocumentIsEmpty(&isEmpty);
|
||||
if (isEmpty)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 offset = textAccessible->GetChildOffset(aEvent->mAccessible);
|
||||
|
||||
nsAutoString text;
|
||||
aEvent->mAccessible->AppendTextTo(text, 0, PR_UINT32_MAX);
|
||||
if (text.IsEmpty())
|
||||
return;
|
||||
|
||||
aEvent->mTextChangeEvent =
|
||||
new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
|
||||
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NotificationController: content inserted notification
|
||||
|
||||
NotificationController::ContentInsertion::
|
||||
ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
|
||||
nsIContent* aStartChildNode, nsIContent* aEndChildNode) :
|
||||
mDocument(aDocument), mContainer(aContainer)
|
||||
{
|
||||
nsIContent* node = aStartChildNode;
|
||||
while (node != aEndChildNode) {
|
||||
mInsertedContent.AppendElement(node);
|
||||
node = node->GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController::ContentInsertion)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController::ContentInsertion)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContainer)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(NotificationController::ContentInsertion)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContainer");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mContainer.get()));
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController::ContentInsertion,
|
||||
AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController::ContentInsertion,
|
||||
Release)
|
||||
|
||||
void
|
||||
NotificationController::ContentInsertion::Process()
|
||||
{
|
||||
#ifdef DEBUG_NOTIFICATIONS
|
||||
nsIContent* firstChildNode = mInsertedContent[0];
|
||||
|
||||
nsCAutoString tag;
|
||||
firstChildNode->Tag()->ToUTF8String(tag);
|
||||
|
||||
nsIAtom* atomid = firstChildNode->GetID();
|
||||
nsCAutoString id;
|
||||
if (atomid)
|
||||
atomid->ToUTF8String(id);
|
||||
|
||||
nsCAutoString ctag;
|
||||
nsCAutoString cid;
|
||||
nsIAtom* catomid = nsnull;
|
||||
if (mContainer->IsContent()) {
|
||||
mContainer->GetContent()->Tag()->ToUTF8String(ctag);
|
||||
catomid = mContainer->GetContent()->GetID();
|
||||
if (catomid)
|
||||
catomid->ToUTF8String(cid);
|
||||
}
|
||||
|
||||
printf("\npending content insertion process: %s@id='%s', container: %s@id='%s', inserted content amount: %d\n\n",
|
||||
tag.get(), id.get(), ctag.get(), cid.get(), mInsertedContent.Length());
|
||||
#endif
|
||||
|
||||
mDocument->ProcessContentInserted(mContainer, &mInsertedContent);
|
||||
|
||||
mDocument = nsnull;
|
||||
mContainer = nsnull;
|
||||
mInsertedContent.Clear();
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef NotificationController_h_
|
||||
#define NotificationController_h_
|
||||
|
||||
#include "AccEvent.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsAccessible;
|
||||
class nsDocAccessible;
|
||||
class nsIContent;
|
||||
|
||||
// Uncomment to log notifications processing.
|
||||
//#define DEBUG_NOTIFICATIONS
|
||||
|
||||
#ifdef DEBUG_NOTIFICATIONS
|
||||
#define DEBUG_CONTENTMUTATION
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Notification interface.
|
||||
*/
|
||||
class Notification
|
||||
{
|
||||
public:
|
||||
virtual ~Notification() { };
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(Notification)
|
||||
|
||||
/**
|
||||
* Process notification.
|
||||
*/
|
||||
virtual void Process() = 0;
|
||||
|
||||
protected:
|
||||
Notification() { }
|
||||
|
||||
private:
|
||||
Notification(const Notification&);
|
||||
Notification& operator = (const Notification&);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Template class for generic notification.
|
||||
*
|
||||
* @note Instance is kept as a weak ref, the caller must guarantee it exists
|
||||
* longer than the document accessible owning the notification controller
|
||||
* that this notification is processed by.
|
||||
*/
|
||||
template<class Class, class Arg>
|
||||
class TNotification : public Notification
|
||||
{
|
||||
public:
|
||||
typedef void (Class::*Callback)(Arg*);
|
||||
|
||||
TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
|
||||
mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
|
||||
virtual ~TNotification() { mInstance = nsnull; }
|
||||
|
||||
virtual void Process()
|
||||
{
|
||||
(mInstance->*mCallback)(mArg);
|
||||
|
||||
mInstance = nsnull;
|
||||
mCallback = nsnull;
|
||||
mArg = nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
TNotification(const TNotification&);
|
||||
TNotification& operator = (const TNotification&);
|
||||
|
||||
Class* mInstance;
|
||||
Callback mCallback;
|
||||
nsCOMPtr<Arg> mArg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to process notifications from core for the document accessible.
|
||||
*/
|
||||
class NotificationController : public nsARefreshObserver
|
||||
{
|
||||
public:
|
||||
NotificationController(nsDocAccessible* aDocument, nsIPresShell* aPresShell);
|
||||
virtual ~NotificationController();
|
||||
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void);
|
||||
NS_IMETHOD_(nsrefcnt) Release(void);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
|
||||
|
||||
/**
|
||||
* Shutdown the notification controller.
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* Put an accessible event into the queue to process it later.
|
||||
*/
|
||||
void QueueEvent(AccEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Pend accessible tree update for content insertion.
|
||||
*/
|
||||
void ScheduleContentInsertion(nsAccessible* aContainer,
|
||||
nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode);
|
||||
|
||||
/**
|
||||
* Process the generic notification synchronously if there are no pending
|
||||
* layout changes and no notifications are pending or being processed right
|
||||
* now. Otherwise, queue it up to process asynchronously.
|
||||
*
|
||||
* @note The caller must guarantee that the given instance still exists when
|
||||
* the notification is processed.
|
||||
*/
|
||||
template<class Class, class Arg>
|
||||
inline void HandleNotification(Class* aInstance,
|
||||
typename TNotification<Class, Arg>::Callback aMethod,
|
||||
Arg* aArg)
|
||||
{
|
||||
if (!IsUpdatePending()) {
|
||||
#ifdef DEBUG_NOTIFICATIONS
|
||||
printf("\nsync notification processing\n");
|
||||
#endif
|
||||
(aInstance->*aMethod)(aArg);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Notification> notification =
|
||||
new TNotification<Class, Arg>(aInstance, aMethod, aArg);
|
||||
if (notification && mNotifications.AppendElement(notification))
|
||||
ScheduleProcessing();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
/**
|
||||
* Start to observe refresh to make notifications and events processing after
|
||||
* layout.
|
||||
*/
|
||||
void ScheduleProcessing();
|
||||
|
||||
/**
|
||||
* Return true if the accessible tree state update is pending.
|
||||
*/
|
||||
bool IsUpdatePending();
|
||||
|
||||
private:
|
||||
NotificationController(const NotificationController&);
|
||||
NotificationController& operator = (const NotificationController&);
|
||||
|
||||
// nsARefreshObserver
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
|
||||
// Event queue processing
|
||||
/**
|
||||
* Coalesce redundant events from the queue.
|
||||
*/
|
||||
void CoalesceEvents();
|
||||
|
||||
/**
|
||||
* Apply aEventRule to same type event that from sibling nodes of aDOMNode.
|
||||
* @param aEventsToFire array of pending events
|
||||
* @param aStart start index of pending events to be scanned
|
||||
* @param aEnd end index to be scanned (not included)
|
||||
* @param aEventType target event type
|
||||
* @param aDOMNode target are siblings of this node
|
||||
* @param aEventRule the event rule to be applied
|
||||
* (should be eDoNotEmit or eAllowDupes)
|
||||
*/
|
||||
void ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
AccEvent::EEventRule aEventRule);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for DOM nodes in the case
|
||||
* when one DOM node is in parent chain of second one.
|
||||
*/
|
||||
void CoalesceReorderEventsFromSameTree(AccEvent* aAccEvent,
|
||||
AccEvent* aDescendantAccEvent);
|
||||
|
||||
/**
|
||||
* Coalesce text change events caused by sibling hide events.
|
||||
*/
|
||||
void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
|
||||
AccHideEvent* aThisEvent);
|
||||
void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
|
||||
AccShowEvent* aThisEvent);
|
||||
|
||||
/**
|
||||
* Create text change event caused by hide or show event. When a node is
|
||||
* hidden/removed or shown/appended, the text in an ancestor hyper text will
|
||||
* lose or get new characters.
|
||||
*/
|
||||
void CreateTextChangeEventFor(AccMutationEvent* aEvent);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Indicates whether we're waiting on an event queue processing from our
|
||||
* notification controller to flush events.
|
||||
*/
|
||||
enum eObservingState {
|
||||
eNotObservingRefresh,
|
||||
eRefreshObserving,
|
||||
eRefreshProcessingForUpdate
|
||||
};
|
||||
eObservingState mObservingState;
|
||||
|
||||
/**
|
||||
* The document accessible reference owning this queue.
|
||||
*/
|
||||
nsRefPtr<nsDocAccessible> mDocument;
|
||||
|
||||
/**
|
||||
* The presshell of the document accessible.
|
||||
*/
|
||||
nsIPresShell* mPresShell;
|
||||
|
||||
/**
|
||||
* Storage for content inserted notification information.
|
||||
*/
|
||||
class ContentInsertion
|
||||
{
|
||||
public:
|
||||
ContentInsertion(nsDocAccessible* aDocument, nsAccessible* aContainer,
|
||||
nsIContent* aStartChildNode, nsIContent* aEndChildNode);
|
||||
virtual ~ContentInsertion() { mDocument = nsnull; }
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(ContentInsertion)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
|
||||
|
||||
void Process();
|
||||
|
||||
private:
|
||||
ContentInsertion();
|
||||
ContentInsertion(const ContentInsertion&);
|
||||
ContentInsertion& operator = (const ContentInsertion&);
|
||||
|
||||
// The document used to process content insertion, matched to document of
|
||||
// the notification controller that this notification belongs to, therefore
|
||||
// it's ok to keep it as weak ref.
|
||||
nsDocAccessible* mDocument;
|
||||
|
||||
// The container accessible that content insertion occurs within.
|
||||
nsRefPtr<nsAccessible> mContainer;
|
||||
|
||||
// Array of inserted contents.
|
||||
nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A pending accessible tree update notifications for content insertions.
|
||||
* Don't make this an nsAutoTArray; we use SwapElements() on it.
|
||||
*/
|
||||
nsTArray<nsRefPtr<ContentInsertion> > mContentInsertions;
|
||||
|
||||
/**
|
||||
* Other notifications like DOM events. Don't make this an nsAutoTArray; we
|
||||
* use SwapElements() on it.
|
||||
*/
|
||||
nsTArray<nsRefPtr<Notification> > mNotifications;
|
||||
|
||||
/**
|
||||
* Pending events array. Don't make this an nsAutoTArray; we use
|
||||
* SwapElements() on it.
|
||||
*/
|
||||
nsTArray<nsRefPtr<AccEvent> > mEvents;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -503,7 +503,7 @@ nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
|
|||
|
||||
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
|
||||
if (docAccessible)
|
||||
docAccessible->UpdateTree(aContainer, aStartChild, aEndChild, PR_TRUE);
|
||||
docAccessible->ContentInserted(aContainer, aStartChild, aEndChild);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -537,8 +537,7 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
|
|||
|
||||
nsDocAccessible* docAccessible = GetDocAccessible(aPresShell->GetDocument());
|
||||
if (docAccessible)
|
||||
docAccessible->UpdateTree(aContainer, aChild, aChild->GetNextSibling(),
|
||||
PR_FALSE);
|
||||
docAccessible->ContentRemoved(aContainer, aChild);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -251,7 +251,7 @@ public:
|
|||
/**
|
||||
* Return parent accessible.
|
||||
*/
|
||||
nsAccessible* GetParent();
|
||||
virtual nsAccessible* GetParent();
|
||||
|
||||
/**
|
||||
* Return child accessible at the given index.
|
||||
|
|
|
@ -410,6 +410,12 @@ nsApplicationAccessible::InvalidateChildren()
|
|||
// and RemoveChild() method calls.
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsApplicationAccessible::GetParent()
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccessible protected methods
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ public:
|
|||
|
||||
virtual void InvalidateChildren();
|
||||
|
||||
virtual nsAccessible* GetParent();
|
||||
|
||||
protected:
|
||||
|
||||
// nsAccessible
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsRootAccessible.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISelection2.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
@ -211,27 +210,55 @@ nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
|
|||
nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
|
||||
nsDocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
|
||||
|
||||
// Don't fire events until document is loaded.
|
||||
if (!document || !document->IsContentLoaded())
|
||||
return NS_OK;
|
||||
#ifdef DEBUG_NOTIFICATIONS
|
||||
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
|
||||
|
||||
PRInt16 type = 0;
|
||||
sel2->GetType(&type);
|
||||
|
||||
if (type == nsISelectionController::SELECTION_NORMAL ||
|
||||
type == nsISelectionController::SELECTION_SPELLCHECK) {
|
||||
|
||||
bool isNormalSelection =
|
||||
(type == nsISelectionController::SELECTION_NORMAL);
|
||||
|
||||
bool isIgnored = !document || !document->IsContentLoaded();
|
||||
printf("\nSelection changed, selection type: %s, notification %s\n",
|
||||
(isNormalSelection ? "normal" : "spellcheck"),
|
||||
(isIgnored ? "ignored" : "pending"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't fire events until document is loaded.
|
||||
if (document && document->IsContentLoaded()) {
|
||||
// The caret accessible has the same lifetime as the root accessible, and
|
||||
// this outlives all its descendant document accessibles, so that we are
|
||||
// guaranteed that the notification is processed before the caret accessible
|
||||
// is destroyed.
|
||||
document->HandleNotification<nsCaretAccessible, nsISelection>
|
||||
(this, &nsCaretAccessible::ProcessSelectionChanged, aSelection);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsCaretAccessible::ProcessSelectionChanged(nsISelection* aSelection)
|
||||
{
|
||||
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
|
||||
|
||||
PRInt16 type = 0;
|
||||
sel2->GetType(&type);
|
||||
|
||||
if (type == nsISelectionController::SELECTION_NORMAL)
|
||||
NormalSelectionChanged(document, aSelection);
|
||||
NormalSelectionChanged(aSelection);
|
||||
|
||||
else if (type == nsISelectionController::SELECTION_SPELLCHECK)
|
||||
SpellcheckSelectionChanged(document, aSelection);
|
||||
|
||||
return NS_OK;
|
||||
SpellcheckSelectionChanged(aSelection);
|
||||
}
|
||||
|
||||
void
|
||||
nsCaretAccessible::NormalSelectionChanged(nsDocAccessible* aDocument,
|
||||
nsISelection* aSelection)
|
||||
nsCaretAccessible::NormalSelectionChanged(nsISelection* aSelection)
|
||||
{
|
||||
mLastUsedSelection = do_GetWeakReference(aSelection);
|
||||
|
||||
|
@ -265,12 +292,11 @@ nsCaretAccessible::NormalSelectionChanged(nsDocAccessible* aDocument,
|
|||
nsRefPtr<AccEvent> event =
|
||||
new AccCaretMoveEvent(mLastTextAccessible->GetNode());
|
||||
if (event)
|
||||
aDocument->FireDelayedAccessibleEvent(event);
|
||||
mLastTextAccessible->GetDocAccessible()->FireDelayedAccessibleEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
nsCaretAccessible::SpellcheckSelectionChanged(nsDocAccessible* aDocument,
|
||||
nsISelection* aSelection)
|
||||
nsCaretAccessible::SpellcheckSelectionChanged(nsISelection* aSelection)
|
||||
{
|
||||
// XXX: fire an event for accessible of focus node of the selection. If
|
||||
// spellchecking is enabled then we will fire the number of events for
|
||||
|
@ -286,7 +312,7 @@ nsCaretAccessible::SpellcheckSelectionChanged(nsDocAccessible* aDocument,
|
|||
nsRefPtr<AccEvent> event =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED, textAcc);
|
||||
if (event)
|
||||
aDocument->FireDelayedAccessibleEvent(event);
|
||||
textAcc->GetDocAccessible()->FireDelayedAccessibleEvent(event);
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
|
|
|
@ -38,9 +38,11 @@
|
|||
#ifndef __nsCaretAccessible_h__
|
||||
#define __nsCaretAccessible_h__
|
||||
|
||||
#include "NotificationController.h"
|
||||
#include "nsHyperTextAccessible.h"
|
||||
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsISelection2.h"
|
||||
|
||||
class nsRootAccessible;
|
||||
|
||||
|
@ -116,18 +118,21 @@ public:
|
|||
nsIntRect GetCaretRect(nsIWidget **aOutWidget);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Process DOM selection change. Fire selection and caret move events.
|
||||
*/
|
||||
void ProcessSelectionChanged(nsISelection* aSelection);
|
||||
|
||||
/**
|
||||
* Process normal selection change and fire caret move event.
|
||||
*/
|
||||
void NormalSelectionChanged(nsDocAccessible* aDocument,
|
||||
nsISelection* aSelection);
|
||||
void NormalSelectionChanged(nsISelection* aSelection);
|
||||
|
||||
/**
|
||||
* Process spellcheck selection change and fire text attribute changed event
|
||||
* for invalid text attribute.
|
||||
*/
|
||||
void SpellcheckSelectionChanged(nsDocAccessible* aDocument,
|
||||
nsISelection* aSelection);
|
||||
void SpellcheckSelectionChanged(nsISelection* aSelection);
|
||||
|
||||
/**
|
||||
* Return selection controller for the given node.
|
||||
|
|
|
@ -133,8 +133,8 @@ nsDocAccessible::~nsDocAccessible()
|
|||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
|
||||
cb.NoteXPCOMChild(tmp->mEventQueue.get());
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNotificationController,
|
||||
NotificationController)
|
||||
|
||||
PRUint32 i, length = tmp->mChildDocuments.Length();
|
||||
for (i = 0; i < length; ++i) {
|
||||
|
@ -146,7 +146,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
|
||||
tmp->mNotificationController->Shutdown();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNotificationController)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
|
||||
tmp->mDependentIDsHash.Clear();
|
||||
tmp->mNodeToAccessibleMap.Clear();
|
||||
|
@ -621,9 +622,10 @@ nsDocAccessible::Init()
|
|||
{
|
||||
NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this)
|
||||
|
||||
// Initialize event queue.
|
||||
mEventQueue = new nsAccEventQueue(this);
|
||||
if (!mEventQueue)
|
||||
// Initialize notification controller.
|
||||
nsCOMPtr<nsIPresShell> shell(GetPresShell());
|
||||
mNotificationController = new NotificationController(this, shell);
|
||||
if (!mNotificationController)
|
||||
return PR_FALSE;
|
||||
|
||||
AddEventListeners();
|
||||
|
@ -653,9 +655,9 @@ nsDocAccessible::Shutdown()
|
|||
|
||||
NS_LOG_ACCDOCDESTROY_FOR("document shutdown", mDocument, this)
|
||||
|
||||
if (mEventQueue) {
|
||||
mEventQueue->Shutdown();
|
||||
mEventQueue = nsnull;
|
||||
if (mNotificationController) {
|
||||
mNotificationController->Shutdown();
|
||||
mNotificationController = nsnull;
|
||||
}
|
||||
|
||||
RemoveEventListeners();
|
||||
|
@ -966,6 +968,9 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument,
|
|||
PRInt32 aNameSpaceID, nsIAtom* aAttribute,
|
||||
PRInt32 aModType)
|
||||
{
|
||||
NS_ASSERTION(!IsDefunct(),
|
||||
"Attribute changed called on defunct document accessible!");
|
||||
|
||||
// Proceed even if the element is not accessible because element may become
|
||||
// accessible if it gets certain attribute.
|
||||
if (UpdateAccessibleOnAttrChange(aElement, aAttribute))
|
||||
|
@ -974,6 +979,8 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument,
|
|||
// Ignore attribute change if the element doesn't have an accessible (at all
|
||||
// or still) iff the element is not a root content of this document accessible
|
||||
// (which is treated as attribute change on this document accessible).
|
||||
// Note: we don't bail if all the content hasn't finished loading because
|
||||
// these attributes are changing for a loaded part of the content.
|
||||
nsAccessible* accessible = GetCachedAccessible(aElement);
|
||||
if (!accessible && (mContent != aElement))
|
||||
return;
|
||||
|
@ -1017,22 +1024,6 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
|
|||
// XXX todo: invalidate accessible when aria state changes affect exposed role
|
||||
// filed as bug 472143
|
||||
|
||||
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsContentLoaded())
|
||||
return; // Still loading, ignore setting of initial attributes
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = GetPresShell();
|
||||
if (!shell) {
|
||||
return; // Document has been shut down
|
||||
}
|
||||
|
||||
NS_ASSERTION(aContent, "No node for attr modified");
|
||||
|
||||
// Universal boolean properties that don't require a role. Fire the state
|
||||
// change when disabled or aria-disabled attribute is set.
|
||||
if (aAttribute == nsAccessibilityAtoms::disabled ||
|
||||
|
@ -1404,116 +1395,35 @@ nsDocAccessible::UnbindFromDocument(nsAccessible* aAccessible)
|
|||
}
|
||||
|
||||
void
|
||||
nsDocAccessible::UpdateTree(nsIContent* aContainerNode,
|
||||
nsIContent* aStartNode,
|
||||
nsIContent* aEndNode,
|
||||
PRBool aIsInsert)
|
||||
nsDocAccessible::ContentInserted(nsIContent* aContainerNode,
|
||||
nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode)
|
||||
{
|
||||
// Content change notification mostly are async, thus we can't detect whether
|
||||
// these actions are from user. This information is used to fire or do not
|
||||
// fire events to avoid events that are generated because of document loading.
|
||||
// Since this information may be not correct then we need to fire some events
|
||||
// regardless the document loading state.
|
||||
|
||||
// Update the whole tree of this document accessible when the container is
|
||||
// null (document element is inserted or removed).
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
|
||||
PRBool fireAllEvents = PR_TRUE;//IsContentLoaded() || esm->IsHandlingUserInputExternal();
|
||||
|
||||
// XXX: bug 608887 reconsider accessible tree update logic because
|
||||
// 1) elements appended outside the HTML body don't get accessibles;
|
||||
// 2) the document having elements that should be accessible may function
|
||||
// without body.
|
||||
nsAccessible* container = nsnull;
|
||||
if (aIsInsert) {
|
||||
container = aContainerNode ?
|
||||
GetAccService()->GetAccessibleOrContainer(aContainerNode, mWeakShell) :
|
||||
this;
|
||||
|
||||
// The document children were changed; the root content might be affected.
|
||||
if (container == this) {
|
||||
// If new root content has been inserted then update it.
|
||||
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
|
||||
if (rootContent && rootContent != mContent)
|
||||
mContent = rootContent;
|
||||
|
||||
// Continue to update the tree even if we don't have root content.
|
||||
// For example, elements may be inserted under the document element while
|
||||
// there is no HTML body element.
|
||||
}
|
||||
|
||||
// XXX: Invalidate parent-child relations for container accessible and its
|
||||
// children because there's no good way to find insertion point of new child
|
||||
// accessibles into accessible tree. We need to invalidate children even
|
||||
// there's no inserted accessibles in the end because accessible children
|
||||
// are created while parent recaches child accessibles.
|
||||
container->InvalidateChildren();
|
||||
|
||||
} else {
|
||||
// Don't create new accessibles on content removal.
|
||||
container = aContainerNode ?
|
||||
/// Pend tree update on content insertion until layout.
|
||||
if (mNotificationController) {
|
||||
// Update the whole tree of this document accessible when the container is
|
||||
// null (document element is inserted or removed).
|
||||
nsAccessible* container = aContainerNode ?
|
||||
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
|
||||
this;
|
||||
|
||||
mNotificationController->ScheduleContentInsertion(container,
|
||||
aStartChildNode,
|
||||
aEndChildNode);
|
||||
}
|
||||
}
|
||||
|
||||
EIsFromUserInput fromUserInput = esm->IsHandlingUserInputExternal() ?
|
||||
eFromUserInput : eNoUserInput;
|
||||
void
|
||||
nsDocAccessible::ContentRemoved(nsIContent* aContainerNode,
|
||||
nsIContent* aChildNode)
|
||||
{
|
||||
// Update the whole tree of this document accessible when the container is
|
||||
// null (document element is removed).
|
||||
nsAccessible* container = aContainerNode ?
|
||||
GetAccService()->GetCachedAccessibleOrContainer(aContainerNode) :
|
||||
this;
|
||||
|
||||
// Update the accessible tree in the case of content removal and fire events
|
||||
// if allowed.
|
||||
PRUint32 updateFlags =
|
||||
UpdateTreeInternal(container, aStartNode, aEndNode,
|
||||
aIsInsert, fireAllEvents, fromUserInput);
|
||||
|
||||
// Content insertion/removal is not cause of accessible tree change.
|
||||
if (updateFlags == eNoAccessible)
|
||||
return;
|
||||
|
||||
// Check to see if change occurred inside an alert, and fire an EVENT_ALERT
|
||||
// if it did.
|
||||
if (aIsInsert && !(updateFlags & eAlertAccessible)) {
|
||||
// XXX: tree traversal is perf issue, accessible should know if they are
|
||||
// children of alert accessible to avoid this.
|
||||
nsAccessible* ancestor = container;
|
||||
while (ancestor) {
|
||||
if (ancestor->ARIARole() == nsIAccessibleRole::ROLE_ALERT) {
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
|
||||
ancestor->GetNode(), AccEvent::eRemoveDupes,
|
||||
fromUserInput);
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't climb above this document.
|
||||
if (ancestor == this)
|
||||
break;
|
||||
|
||||
ancestor = ancestor->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
// Fire nether value change nor reorder events if action is not from user
|
||||
// input and document is loading. We are notified about changes in editor
|
||||
// synchronously, so from user input flag is correct for value change events.
|
||||
if (!fireAllEvents)
|
||||
return;
|
||||
|
||||
// Fire value change event.
|
||||
if (container->Role() == nsIAccessibleRole::ROLE_ENTRY) {
|
||||
nsRefPtr<AccEvent> valueChangeEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, container,
|
||||
fromUserInput, AccEvent::eRemoveDupes);
|
||||
FireDelayedAccessibleEvent(valueChangeEvent);
|
||||
}
|
||||
|
||||
// Fire reorder event so the MSAA clients know the children have changed. Also
|
||||
// the event is used internally by MSAA part.
|
||||
nsRefPtr<AccEvent> reorderEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, container->GetNode(),
|
||||
fromUserInput, AccEvent::eCoalesceFromSameSubtree);
|
||||
if (reorderEvent)
|
||||
FireDelayedAccessibleEvent(reorderEvent);
|
||||
UpdateTree(container, aChildNode, PR_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1532,8 +1442,7 @@ nsDocAccessible::RecreateAccessible(nsINode* aNode)
|
|||
if (oldAccessible) {
|
||||
parent = oldAccessible->GetParent();
|
||||
|
||||
nsRefPtr<AccEvent> hideEvent = new AccHideEvent(oldAccessible, aNode,
|
||||
eAutoDetect);
|
||||
nsRefPtr<AccEvent> hideEvent = new AccHideEvent(oldAccessible, aNode);
|
||||
if (hideEvent)
|
||||
FireDelayedAccessibleEvent(hideEvent);
|
||||
|
||||
|
@ -1554,8 +1463,7 @@ nsDocAccessible::RecreateAccessible(nsINode* aNode)
|
|||
nsAccessible* newAccessible =
|
||||
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell);
|
||||
if (newAccessible) {
|
||||
nsRefPtr<AccEvent> showEvent = new AccShowEvent(newAccessible, aNode,
|
||||
eAutoDetect);
|
||||
nsRefPtr<AccEvent> showEvent = new AccShowEvent(newAccessible, aNode);
|
||||
if (showEvent)
|
||||
FireDelayedAccessibleEvent(showEvent);
|
||||
}
|
||||
|
@ -1738,7 +1646,9 @@ nsDocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
|||
// Recreate the accessible when role is changed because we might require a
|
||||
// different accessible class for the new role or the accessible may expose
|
||||
// a different sets of interfaces (COM restriction).
|
||||
RecreateAccessible(aElement);
|
||||
HandleNotification<nsDocAccessible, nsINode>
|
||||
(this, &nsDocAccessible::RecreateAccessible, aElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1747,7 +1657,9 @@ nsDocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
|||
// Not worth the expense to ensure which namespace these are in
|
||||
// It doesn't kill use to recreate the accessible even if the attribute was used
|
||||
// in the wrong namespace or an element that doesn't support it
|
||||
RecreateAccessible(aElement);
|
||||
HandleNotification<nsDocAccessible, nsINode>
|
||||
(this, &nsDocAccessible::RecreateAccessible, aElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1756,7 +1668,9 @@ nsDocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
|
|||
// This affects whether the accessible supports SelectAccessible.
|
||||
// COM says we cannot change what interfaces are supported on-the-fly,
|
||||
// so invalidate this object. A new one will be created on demand.
|
||||
RecreateAccessible(aElement);
|
||||
HandleNotification<nsDocAccessible, nsINode>
|
||||
(this, &nsDocAccessible::RecreateAccessible, aElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1855,13 +1769,12 @@ nsDocAccessible::FireDelayedAccessibleEvent(AccEvent* aEvent)
|
|||
NS_ENSURE_ARG(aEvent);
|
||||
NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent)
|
||||
|
||||
if (mEventQueue)
|
||||
mEventQueue->Push(aEvent);
|
||||
if (mNotificationController)
|
||||
mNotificationController->QueueEvent(aEvent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsDocAccessible public member
|
||||
void
|
||||
nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
|
||||
{
|
||||
|
@ -1912,13 +1825,104 @@ nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocAccessible::ProcessContentInserted(nsAccessible* aContainer,
|
||||
const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent)
|
||||
{
|
||||
// Process the notification if the container accessible is still in tree.
|
||||
if (!GetCachedAccessible(aContainer->GetNode()))
|
||||
return;
|
||||
|
||||
if (aContainer == this) {
|
||||
// If new root content has been inserted then update it.
|
||||
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocument);
|
||||
if (rootContent && rootContent != mContent)
|
||||
mContent = rootContent;
|
||||
|
||||
// Continue to update the tree even if we don't have root content.
|
||||
// For example, elements may be inserted under the document element while
|
||||
// there is no HTML body element.
|
||||
}
|
||||
|
||||
// XXX: Invalidate parent-child relations for container accessible and its
|
||||
// children because there's no good way to find insertion point of new child
|
||||
// accessibles into accessible tree. We need to invalidate children even
|
||||
// there's no inserted accessibles in the end because accessible children
|
||||
// are created while parent recaches child accessibles.
|
||||
aContainer->InvalidateChildren();
|
||||
|
||||
// The container might be changed, for example, because of the subsequent
|
||||
// overlapping content insertion (i.e. other content was inserted between this
|
||||
// inserted content and its container or the content was reinserted into
|
||||
// different container of unrelated part of tree). These cases result in
|
||||
// double processing, however generated events are coalesced and we don't
|
||||
// harm an AT. On the another hand container can be different because direct
|
||||
// container wasn't cached yet when we handled content insertion notification
|
||||
// and therefore we can't ignore the case when container has been changed.
|
||||
// Theoretically the element might be not in tree at all at this point what
|
||||
// means there's no container.
|
||||
for (PRUint32 idx = 0; idx < aInsertedContent->Length(); idx++) {
|
||||
nsAccessible* directContainer =
|
||||
GetAccService()->GetContainerAccessible(aInsertedContent->ElementAt(idx),
|
||||
mWeakShell);
|
||||
if (directContainer)
|
||||
UpdateTree(directContainer, aInsertedContent->ElementAt(idx), PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocAccessible::UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
|
||||
PRBool aIsInsert)
|
||||
{
|
||||
PRUint32 updateFlags =
|
||||
UpdateTreeInternal(aContainer, aChildNode, aChildNode->GetNextSibling(),
|
||||
aIsInsert);
|
||||
|
||||
// Content insertion/removal is not cause of accessible tree change.
|
||||
if (updateFlags == eNoAccessible)
|
||||
return;
|
||||
|
||||
// Check to see if change occurred inside an alert, and fire an EVENT_ALERT
|
||||
// if it did.
|
||||
if (aIsInsert && !(updateFlags & eAlertAccessible)) {
|
||||
// XXX: tree traversal is perf issue, accessible should know if they are
|
||||
// children of alert accessible to avoid this.
|
||||
nsAccessible* ancestor = aContainer;
|
||||
while (ancestor) {
|
||||
if (ancestor->ARIARole() == nsIAccessibleRole::ROLE_ALERT) {
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT,
|
||||
ancestor->GetNode());
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't climb above this document.
|
||||
if (ancestor == this)
|
||||
break;
|
||||
|
||||
ancestor = ancestor->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
// Fire value change event.
|
||||
if (aContainer->Role() == nsIAccessibleRole::ROLE_ENTRY) {
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
|
||||
aContainer->GetNode());
|
||||
}
|
||||
|
||||
// Fire reorder event so the MSAA clients know the children have changed. Also
|
||||
// the event is used internally by MSAA layer.
|
||||
nsRefPtr<AccEvent> reorderEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, aContainer->GetNode(),
|
||||
eAutoDetect, AccEvent::eCoalesceFromSameSubtree);
|
||||
if (reorderEvent)
|
||||
FireDelayedAccessibleEvent(reorderEvent);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
||||
nsIContent* aStartNode,
|
||||
nsIContent* aEndNode,
|
||||
PRBool aIsInsert,
|
||||
PRBool aFireAllEvents,
|
||||
EIsFromUserInput aFromUserInput)
|
||||
PRBool aIsInsert)
|
||||
{
|
||||
PRUint32 updateFlags = eNoAccessible;
|
||||
for (nsIContent* node = aStartNode; node != aEndNode;
|
||||
|
@ -1936,8 +1940,7 @@ nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
|||
|
||||
if (!accessible) {
|
||||
updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),
|
||||
nsnull, aIsInsert, aFireAllEvents,
|
||||
aFromUserInput);
|
||||
nsnull, aIsInsert);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1963,29 +1966,27 @@ nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
|||
}
|
||||
|
||||
// Fire show/hide event.
|
||||
if (aFireAllEvents) {
|
||||
nsRefPtr<AccEvent> event;
|
||||
if (aIsInsert)
|
||||
event = new AccShowEvent(accessible, node, aFromUserInput);
|
||||
else
|
||||
event = new AccHideEvent(accessible, node, aFromUserInput);
|
||||
nsRefPtr<AccEvent> event;
|
||||
if (aIsInsert)
|
||||
event = new AccShowEvent(accessible, node);
|
||||
else
|
||||
event = new AccHideEvent(accessible, node);
|
||||
|
||||
if (event)
|
||||
FireDelayedAccessibleEvent(event);
|
||||
}
|
||||
if (event)
|
||||
FireDelayedAccessibleEvent(event);
|
||||
|
||||
if (aIsInsert) {
|
||||
PRUint32 ariaRole = accessible->ARIARole();
|
||||
if (ariaRole == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
||||
// Fire EVENT_MENUPOPUP_START if ARIA menu appears.
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
||||
node, AccEvent::eRemoveDupes, aFromUserInput);
|
||||
node, AccEvent::eRemoveDupes);
|
||||
|
||||
} else if (ariaRole == nsIAccessibleRole::ROLE_ALERT) {
|
||||
// Fire EVENT_ALERT if ARIA alert appears.
|
||||
updateFlags = eAlertAccessible;
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, node,
|
||||
AccEvent::eRemoveDupes, aFromUserInput);
|
||||
AccEvent::eRemoveDupes);
|
||||
}
|
||||
|
||||
// If focused node has been shown then it means its frame was recreated
|
||||
|
@ -1994,8 +1995,7 @@ nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
|||
// this one.
|
||||
if (node == gLastFocusedNode) {
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
||||
node, AccEvent::eCoalesceFromSameDocument,
|
||||
aFromUserInput);
|
||||
node, AccEvent::eCoalesceFromSameDocument);
|
||||
}
|
||||
} else {
|
||||
// Update the tree for content removal.
|
||||
|
@ -2045,4 +2045,3 @@ nsDocAccessible::ShutdownChildrenInSubtree(nsAccessible* aAccessible)
|
|||
|
||||
UnbindFromDocument(aAccessible);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,9 @@
|
|||
|
||||
#include "nsIAccessibleDocument.h"
|
||||
|
||||
#include "nsHyperTextAccessibleWrap.h"
|
||||
#include "nsEventShell.h"
|
||||
#include "nsHyperTextAccessibleWrap.h"
|
||||
#include "NotificationController.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
@ -188,6 +189,24 @@ public:
|
|||
*/
|
||||
nsresult FireDelayedAccessibleEvent(AccEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Process the generic notification.
|
||||
*
|
||||
* @note The caller must guarantee that the given instance still exists when
|
||||
* notification is processed.
|
||||
* @see NotificationController::HandleNotification
|
||||
*/
|
||||
template<class Class, class Arg>
|
||||
inline void HandleNotification(Class* aInstance,
|
||||
typename TNotification<Class, Arg>::Callback aMethod,
|
||||
Arg* aArg)
|
||||
{
|
||||
if (mNotificationController) {
|
||||
mNotificationController->HandleNotification<Class, Arg>(aInstance,
|
||||
aMethod, aArg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cached accessible by the given DOM node if it's in subtree of
|
||||
* this document accessible or the document accessible itself, otherwise null.
|
||||
|
@ -240,16 +259,16 @@ public:
|
|||
void UnbindFromDocument(nsAccessible* aAccessible);
|
||||
|
||||
/**
|
||||
* Process the event when the queue of pending events is untwisted. Fire
|
||||
* accessible events as result of the processing.
|
||||
* Notify the document accessible that content was inserted.
|
||||
*/
|
||||
void ProcessPendingEvent(AccEvent* aEvent);
|
||||
void ContentInserted(nsIContent* aContainerNode,
|
||||
nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode);
|
||||
|
||||
/**
|
||||
* Update the accessible tree.
|
||||
* Notify the document accessible that content was removed.
|
||||
*/
|
||||
void UpdateTree(nsIContent* aContainerNode, nsIContent* aStartChildNode,
|
||||
nsIContent* aEndChildNode, PRBool aIsInsert);
|
||||
void ContentRemoved(nsIContent* aContainerNode, nsIContent* aChildNode);
|
||||
|
||||
/**
|
||||
* Recreate an accessible, results in hide/show events pair.
|
||||
|
@ -365,6 +384,24 @@ protected:
|
|||
*/
|
||||
void FireValueChangeForTextFields(nsAccessible *aAccessible);
|
||||
|
||||
/**
|
||||
* Process the event when the queue of pending events is untwisted. Fire
|
||||
* accessible events as result of the processing.
|
||||
*/
|
||||
void ProcessPendingEvent(AccEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Update the accessible tree for inserted content.
|
||||
*/
|
||||
void ProcessContentInserted(nsAccessible* aContainer,
|
||||
const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent);
|
||||
|
||||
/**
|
||||
* Update the accessible tree for content insertion or removal.
|
||||
*/
|
||||
void UpdateTree(nsAccessible* aContainer, nsIContent* aChildNode,
|
||||
PRBool aIsInsert);
|
||||
|
||||
/**
|
||||
* Helper for UpdateTree() method. Go down to DOM subtree and updates
|
||||
* accessible tree. Return one of these flags.
|
||||
|
@ -378,9 +415,7 @@ protected:
|
|||
PRUint32 UpdateTreeInternal(nsAccessible* aContainer,
|
||||
nsIContent* aStartNode,
|
||||
nsIContent* aEndNode,
|
||||
PRBool aIsInsert,
|
||||
PRBool aFireEvents,
|
||||
EIsFromUserInput aFromUserInput);
|
||||
PRBool aIsInsert);
|
||||
|
||||
/**
|
||||
* Remove accessibles in subtree from node to accessible map.
|
||||
|
@ -416,15 +451,12 @@ protected:
|
|||
|
||||
protected:
|
||||
|
||||
nsRefPtr<nsAccEventQueue> mEventQueue;
|
||||
|
||||
/**
|
||||
* Specifies if the document was loaded, used for error pages only.
|
||||
*/
|
||||
PRPackedBool mIsLoaded;
|
||||
|
||||
static PRUint32 gLastFocusedAccessiblesState;
|
||||
static nsIAtom *gLastFocusedFrameType;
|
||||
|
||||
nsTArray<nsRefPtr<nsDocAccessible> > mChildDocuments;
|
||||
|
||||
|
@ -464,6 +496,12 @@ protected:
|
|||
nsAccessible* mCacheRoot;
|
||||
nsTArray<nsIContent*> mInvalidationList;
|
||||
PRBool mIsPostCacheProcessing;
|
||||
|
||||
/**
|
||||
* Used to process notification from core and accessible events.
|
||||
*/
|
||||
nsRefPtr<NotificationController> mNotificationController;
|
||||
friend class NotificationController;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible,
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
#include "nsEventShell.h"
|
||||
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsDocAccessible.h"
|
||||
//#include "nsDocAccessible.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsEventShell
|
||||
|
@ -95,387 +94,3 @@ nsEventShell::GetEventAttributes(nsINode *aNode,
|
|||
|
||||
PRBool nsEventShell::sEventFromUserInput = PR_FALSE;
|
||||
nsCOMPtr<nsINode> nsEventShell::sEventTargetNode;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
|
||||
mObservingRefresh(PR_FALSE), mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
nsAccEventQueue::~nsAccEventQueue()
|
||||
{
|
||||
NS_ASSERTION(!mDocument, "Queue wasn't shut down!");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: nsISupports and cycle collection
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEventQueue)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccEventQueue)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mEvents, AccEvent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAccEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEventQueue)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: public
|
||||
|
||||
void
|
||||
nsAccEventQueue::Push(AccEvent* aEvent)
|
||||
{
|
||||
mEvents.AppendElement(aEvent);
|
||||
|
||||
// Filter events.
|
||||
CoalesceEvents();
|
||||
|
||||
// Associate text change with hide event if it wasn't stolen from hiding
|
||||
// siblings during coalescence.
|
||||
AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
|
||||
if (showOrHideEvent && !showOrHideEvent->mTextChangeEvent)
|
||||
CreateTextChangeEventFor(showOrHideEvent);
|
||||
|
||||
// Process events.
|
||||
PrepareFlush();
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::Shutdown()
|
||||
{
|
||||
if (mObservingRefresh) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
if (!shell ||
|
||||
shell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_FALSE;
|
||||
}
|
||||
}
|
||||
mDocument = nsnull;
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: private
|
||||
|
||||
void
|
||||
nsAccEventQueue::PrepareFlush()
|
||||
{
|
||||
// If there are pending events in the queue and events flush isn't planed
|
||||
// yet start events flush asynchronously.
|
||||
if (mEvents.Length() > 0 && !mObservingRefresh) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
// Use a Flush_Display observer so that it will get called after
|
||||
// style and ayout have been flushed.
|
||||
if (shell &&
|
||||
shell->AddRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
// If the document accessible is now shut down, don't fire events in it
|
||||
// anymore.
|
||||
if (!mDocument)
|
||||
return;
|
||||
|
||||
// Process only currently queued events. Newly appended events during events
|
||||
// flushing won't be processed.
|
||||
nsTArray < nsRefPtr<AccEvent> > events;
|
||||
events.SwapElements(mEvents);
|
||||
PRUint32 length = events.Length();
|
||||
NS_ASSERTION(length, "How did we get here without events to fire?");
|
||||
|
||||
for (PRUint32 index = 0; index < length; index ++) {
|
||||
|
||||
AccEvent* accEvent = events[index];
|
||||
if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
|
||||
mDocument->ProcessPendingEvent(accEvent);
|
||||
|
||||
AccMutationEvent* showOrhideEvent = downcast_accEvent(accEvent);
|
||||
if (showOrhideEvent) {
|
||||
if (showOrhideEvent->mTextChangeEvent)
|
||||
mDocument->ProcessPendingEvent(showOrhideEvent->mTextChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// No document means it was shut down during event handling by AT
|
||||
if (!mDocument)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEvents.Length() == 0) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
if (!shell ||
|
||||
shell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceEvents()
|
||||
{
|
||||
PRUint32 numQueuedEvents = mEvents.Length();
|
||||
PRInt32 tail = numQueuedEvents - 1;
|
||||
AccEvent* tailEvent = mEvents[tail];
|
||||
|
||||
// No node means this is application accessible (which can be a subject
|
||||
// of reorder events), we do not coalesce events for it currently.
|
||||
if (!tailEvent->mNode)
|
||||
return;
|
||||
|
||||
switch(tailEvent->mEventRule) {
|
||||
case AccEvent::eCoalesceFromSameSubtree:
|
||||
{
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* thisEvent = mEvents[index];
|
||||
|
||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||
continue; // Different type
|
||||
|
||||
// Skip event for application accessible since no coalescence for it
|
||||
// is supported. Ignore events from different documents since we don't
|
||||
// coalesce them.
|
||||
if (!thisEvent->mNode ||
|
||||
thisEvent->mNode->GetOwnerDoc() != tailEvent->mNode->GetOwnerDoc())
|
||||
continue;
|
||||
|
||||
// If event queue contains an event of the same type and having target
|
||||
// that is sibling of target of newly appended event then apply its
|
||||
// event rule to the newly appended event.
|
||||
|
||||
// XXX: deal with show events separately because they can't be
|
||||
// coalesced by accessible tree the same as hide events since target
|
||||
// accessibles can't be created at this point because of lazy frame
|
||||
// construction (bug 570275).
|
||||
|
||||
// Coalesce hide and show events for sibling targets.
|
||||
if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
AccHideEvent* tailHideEvent = downcast_accEvent(tailEvent);
|
||||
AccHideEvent* thisHideEvent = downcast_accEvent(thisEvent);
|
||||
if (thisHideEvent->mParent == tailHideEvent->mParent) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
|
||||
// Coalesce text change events for hide events.
|
||||
if (tailEvent->mEventRule != AccEvent::eDoNotEmit)
|
||||
CoalesceTextChangeEventsFor(tailHideEvent, thisHideEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
} else if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||
if (thisEvent->mAccessible->GetParent() ==
|
||||
tailEvent->mAccessible->GetParent()) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
|
||||
// Coalesce text change events for show events.
|
||||
if (tailEvent->mEventRule != AccEvent::eDoNotEmit) {
|
||||
AccShowEvent* tailShowEvent = downcast_accEvent(tailEvent);
|
||||
AccShowEvent* thisShowEvent = downcast_accEvent(thisEvent);
|
||||
CoalesceTextChangeEventsFor(tailShowEvent, thisShowEvent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore events unattached from DOM since we don't coalesce them.
|
||||
if (!thisEvent->mNode->IsInDoc())
|
||||
continue;
|
||||
|
||||
// Coalesce earlier event for the same target.
|
||||
if (thisEvent->mNode == tailEvent->mNode) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Coalesce events by sibling targets (this is a case for reorder
|
||||
// events).
|
||||
if (thisEvent->mNode->GetNodeParent() ==
|
||||
tailEvent->mNode->GetNodeParent()) {
|
||||
tailEvent->mEventRule = thisEvent->mEventRule;
|
||||
return;
|
||||
}
|
||||
|
||||
// This and tail events can be anywhere in the tree, make assumptions
|
||||
// for mutation events.
|
||||
|
||||
// Coalesce tail event if tail node is descendant of this node. Stop
|
||||
// processing if tail event is coalesced since all possible descendants
|
||||
// of this node was coalesced before.
|
||||
// Note: more older hide event target (thisNode) can't contain recent
|
||||
// hide event target (tailNode), i.e. be ancestor of tailNode. Skip
|
||||
// this check for hide events.
|
||||
if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
|
||||
nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
|
||||
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this node is a descendant of tail node then coalesce this event,
|
||||
// check other events in the queue. Do not emit thisEvent, also apply
|
||||
// this result to sibling nodes of thisNode.
|
||||
if (nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(0, index, thisEvent->mEventType,
|
||||
thisEvent->mNode, AccEvent::eDoNotEmit);
|
||||
continue;
|
||||
}
|
||||
|
||||
} // for (index)
|
||||
|
||||
} break; // case eCoalesceFromSameSubtree
|
||||
|
||||
case AccEvent::eCoalesceFromSameDocument:
|
||||
{
|
||||
// Used for focus event, coalesce more older event since focus event
|
||||
// for accessible can be duplicated by event for its document, we are
|
||||
// interested in focus event for accessible.
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* thisEvent = mEvents[index];
|
||||
if (thisEvent->mEventType == tailEvent->mEventType &&
|
||||
thisEvent->mEventRule == tailEvent->mEventRule &&
|
||||
thisEvent->GetDocAccessible() == tailEvent->GetDocAccessible()) {
|
||||
thisEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break; // case eCoalesceFromSameDocument
|
||||
|
||||
case AccEvent::eRemoveDupes:
|
||||
{
|
||||
// Check for repeat events, coalesce newly appended event by more older
|
||||
// event.
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
AccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||
accEvent->mNode == tailEvent->mNode) {
|
||||
tailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break; // case eRemoveDupes
|
||||
|
||||
default:
|
||||
break; // case eAllowDupes, eDoNotEmit
|
||||
} // switch
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
AccEvent::EEventRule aEventRule)
|
||||
{
|
||||
for (PRUint32 index = aStart; index < aEnd; index ++) {
|
||||
AccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == aEventType &&
|
||||
accEvent->mEventRule != AccEvent::eDoNotEmit && accEvent->mNode &&
|
||||
accEvent->mNode->GetNodeParent() == aNode->GetNodeParent()) {
|
||||
accEvent->mEventRule = aEventRule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
|
||||
AccHideEvent* aThisEvent)
|
||||
{
|
||||
// XXX: we need a way to ignore SplitNode and JoinNode() when they do not
|
||||
// affect the text within the hypertext.
|
||||
|
||||
AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
|
||||
if (!textEvent)
|
||||
return;
|
||||
|
||||
if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
|
||||
} else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
|
||||
PRUint32 oldLen = textEvent->GetLength();
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
textEvent->mStart -= textEvent->GetLength() - oldLen;
|
||||
}
|
||||
|
||||
aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
|
||||
AccShowEvent* aThisEvent)
|
||||
{
|
||||
AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
|
||||
if (!textEvent)
|
||||
return;
|
||||
|
||||
if (aTailEvent->mAccessible->GetIndexInParent() ==
|
||||
aThisEvent->mAccessible->GetIndexInParent() + 1) {
|
||||
// If tail target was inserted after this target, i.e. tail target is next
|
||||
// sibling of this target.
|
||||
aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText,
|
||||
0, PR_UINT32_MAX);
|
||||
|
||||
} else if (aTailEvent->mAccessible->GetIndexInParent() ==
|
||||
aThisEvent->mAccessible->GetIndexInParent() -1) {
|
||||
// If tail target was inserted before this target, i.e. tail target is
|
||||
// previous sibling of this target.
|
||||
nsAutoString startText;
|
||||
aTailEvent->mAccessible->AppendTextTo(startText, 0, PR_UINT32_MAX);
|
||||
textEvent->mModifiedText = startText + textEvent->mModifiedText;
|
||||
textEvent->mStart -= startText.Length();
|
||||
}
|
||||
|
||||
aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
|
||||
{
|
||||
nsRefPtr<nsHyperTextAccessible> textAccessible = do_QueryObject(
|
||||
GetAccService()->GetContainerAccessible(aEvent->mNode,
|
||||
aEvent->mAccessible->GetWeakShell()));
|
||||
if (!textAccessible)
|
||||
return;
|
||||
|
||||
// Don't fire event for the first html:br in an editor.
|
||||
if (aEvent->mAccessible->Role() == nsIAccessibleRole::ROLE_WHITESPACE) {
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
|
||||
if (editor) {
|
||||
PRBool isEmpty = PR_FALSE;
|
||||
editor->GetDocumentIsEmpty(&isEmpty);
|
||||
if (isEmpty)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 offset = textAccessible->GetChildOffset(aEvent->mAccessible);
|
||||
|
||||
nsAutoString text;
|
||||
aEvent->mAccessible->AppendTextTo(text, 0, PR_UINT32_MAX);
|
||||
if (text.IsEmpty())
|
||||
return;
|
||||
|
||||
aEvent->mTextChangeEvent =
|
||||
new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
|
||||
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
|
||||
}
|
||||
|
|
|
@ -41,12 +41,6 @@
|
|||
|
||||
#include "AccEvent.h"
|
||||
|
||||
#include "a11yGeneric.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
class nsIPersistentProperties;
|
||||
|
||||
/**
|
||||
|
@ -85,100 +79,4 @@ private:
|
|||
static PRBool sEventFromUserInput;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event queue.
|
||||
*/
|
||||
class nsAccEventQueue : public nsISupports,
|
||||
public nsARefreshObserver
|
||||
{
|
||||
public:
|
||||
nsAccEventQueue(nsDocAccessible *aDocument);
|
||||
~nsAccEventQueue();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
|
||||
|
||||
/**
|
||||
* Push event to queue, coalesce it if necessary. Start pending processing.
|
||||
*/
|
||||
void Push(AccEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Shutdown the queue.
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Start pending events processing asynchronously.
|
||||
*/
|
||||
void PrepareFlush();
|
||||
|
||||
/**
|
||||
* Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
|
||||
* where the real event processing is happen.
|
||||
*/
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
|
||||
/**
|
||||
* Coalesce redundant events from the queue.
|
||||
*/
|
||||
void CoalesceEvents();
|
||||
|
||||
/**
|
||||
* Apply aEventRule to same type event that from sibling nodes of aDOMNode.
|
||||
* @param aEventsToFire array of pending events
|
||||
* @param aStart start index of pending events to be scanned
|
||||
* @param aEnd end index to be scanned (not included)
|
||||
* @param aEventType target event type
|
||||
* @param aDOMNode target are siblings of this node
|
||||
* @param aEventRule the event rule to be applied
|
||||
* (should be eDoNotEmit or eAllowDupes)
|
||||
*/
|
||||
void ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
AccEvent::EEventRule aEventRule);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for DOM nodes in the case
|
||||
* when one DOM node is in parent chain of second one.
|
||||
*/
|
||||
void CoalesceReorderEventsFromSameTree(AccEvent* aAccEvent,
|
||||
AccEvent* aDescendantAccEvent);
|
||||
|
||||
/**
|
||||
* Coalesce text change events caused by sibling hide events.
|
||||
*/
|
||||
void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
|
||||
AccHideEvent* aThisEvent);
|
||||
void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
|
||||
AccShowEvent* aThisEvent);
|
||||
|
||||
/**
|
||||
* Create text change event caused by hide or show event. When a node is
|
||||
* hidden/removed or shown/appended, the text in an ancestor hyper text will
|
||||
* lose or get new characters.
|
||||
*/
|
||||
void CreateTextChangeEventFor(AccMutationEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Indicates whether we're waiting on a refresh notification from our
|
||||
* presshell to flush events
|
||||
*/
|
||||
PRBool mObservingRefresh;
|
||||
|
||||
/**
|
||||
* The document accessible reference owning this queue.
|
||||
*/
|
||||
nsRefPtr<nsDocAccessible> mDocument;
|
||||
|
||||
/**
|
||||
* Pending events array. Don't make this an nsAutoTArray; we use
|
||||
* SwapElements() on it.
|
||||
*/
|
||||
nsTArray<nsRefPtr<AccEvent> > mEvents;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -439,32 +439,77 @@ nsRootAccessible::FireCurrentFocusEvent()
|
|||
// nsIDOMEventListener
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
||||
nsRootAccessible::HandleEvent(nsIDOMEvent* aDOMEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aEvent));
|
||||
NS_ENSURE_STATE(nsevent);
|
||||
nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
|
||||
nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
|
||||
DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
|
||||
nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
|
||||
if (!origTargetNode)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
||||
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
||||
nsCOMPtr<nsINode> origTarget(do_QueryInterface(domEventTarget));
|
||||
NS_ENSURE_STATE(origTarget);
|
||||
nsDocAccessible* document =
|
||||
GetAccService()->GetDocAccessible(origTargetNode->GetOwnerDoc());
|
||||
|
||||
if (document) {
|
||||
#ifdef DEBUG_NOTIFICATIONS
|
||||
if (origTargetNode->IsElement()) {
|
||||
nsIContent* elm = origTargetNode->AsElement();
|
||||
|
||||
nsAutoString tag;
|
||||
elm->Tag()->ToString(tag);
|
||||
|
||||
nsIAtom* atomid = elm->GetID();
|
||||
nsCAutoString id;
|
||||
if (atomid)
|
||||
atomid->ToUTF8String(id);
|
||||
|
||||
nsAutoString eventType;
|
||||
aDOMEvent->GetType(eventType);
|
||||
|
||||
printf("\nPend DOM event processing for %s@id='%s', type: %s\n\n",
|
||||
NS_ConvertUTF16toUTF8(tag).get(), id.get(),
|
||||
NS_ConvertUTF16toUTF8(eventType).get());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Root accessible exists longer than any of its descendant documents so
|
||||
// that we are guaranteed notification is processed before root accessible
|
||||
// is destroyed.
|
||||
document->HandleNotification<nsRootAccessible, nsIDOMEvent>
|
||||
(this, &nsRootAccessible::ProcessDOMEvent, aDOMEvent);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsRootAccessible protected
|
||||
void
|
||||
nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent));
|
||||
nsCOMPtr<nsIDOMEventTarget> DOMEventTarget;
|
||||
DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget));
|
||||
nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget));
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
aDOMEvent->GetType(eventType);
|
||||
|
||||
nsCOMPtr<nsIWeakReference> weakShell =
|
||||
nsCoreUtils::GetWeakShellFor(origTarget);
|
||||
nsCoreUtils::GetWeakShellFor(origTargetNode);
|
||||
if (!weakShell)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
nsAccessible* accessible =
|
||||
GetAccService()->GetAccessibleOrContainer(origTarget, weakShell);
|
||||
GetAccService()->GetAccessibleOrContainer(origTargetNode, weakShell);
|
||||
|
||||
if (eventType.EqualsLiteral("popuphiding"))
|
||||
return HandlePopupHidingEvent(origTarget, accessible);
|
||||
if (eventType.EqualsLiteral("popuphiding")) {
|
||||
HandlePopupHidingEvent(origTargetNode, accessible);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!accessible)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
nsDocAccessible* targetDocument = accessible->GetDocAccessible();
|
||||
NS_ASSERTION(targetDocument, "No document while accessible is in document?!");
|
||||
|
@ -485,14 +530,18 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
if (treeAcc) {
|
||||
if (eventType.EqualsLiteral("TreeViewChanged")) {
|
||||
treeAcc->TreeViewChanged();
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("TreeRowCountChanged"))
|
||||
return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
|
||||
if (eventType.EqualsLiteral("TreeRowCountChanged")) {
|
||||
HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("TreeInvalidated"))
|
||||
return HandleTreeInvalidatedEvent(aEvent, treeAcc);
|
||||
if (eventType.EqualsLiteral("TreeInvalidated")) {
|
||||
HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -515,7 +564,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
if (isEnabled)
|
||||
FireAccessibleFocusEvent(accessible, targetContent);
|
||||
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("CheckboxStateChange")) {
|
||||
|
@ -528,7 +577,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
PR_FALSE, isEnabled);
|
||||
|
||||
nsEventShell::FireEvent(accEvent);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
nsAccessible *treeItemAccessible = nsnull;
|
||||
|
@ -561,7 +610,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
new AccStateChangeEvent(accessible, nsIAccessibleStates::STATE_EXPANDED,
|
||||
PR_FALSE, isEnabled);
|
||||
nsEventShell::FireEvent(accEvent);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (treeItemAccessible && eventType.EqualsLiteral("select")) {
|
||||
|
@ -578,12 +627,12 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
// that state changes. nsXULTreeAccessible::UpdateTreeSelection();
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
|
||||
accessible);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION,
|
||||
treeItemAccessible);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -608,12 +657,12 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
focusedItem = do_QueryInterface(selectedItem);
|
||||
|
||||
if (!focusedItem)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
accessible = GetAccService()->GetAccessibleInWeakShell(focusedItem,
|
||||
weakShell);
|
||||
if (!accessible)
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,11 +689,12 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
if (!treeItemAccessible) {
|
||||
#ifdef MOZ_XUL
|
||||
if (isTree) {
|
||||
return NS_OK; // Tree with nothing selected
|
||||
return; // Tree with nothing selected
|
||||
}
|
||||
#endif
|
||||
nsIFrame* menuFrame = accessible->GetFrame();
|
||||
NS_ENSURE_TRUE(menuFrame, NS_ERROR_FAILURE);
|
||||
if (!menuFrame)
|
||||
return;
|
||||
|
||||
nsIMenuFrame* imenuFrame = do_QueryFrame(menuFrame);
|
||||
if (imenuFrame)
|
||||
|
@ -654,18 +704,20 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
!imenuFrame->IsOnActiveMenuBar()) {
|
||||
// It is a top level menuitem. Only fire a focus event when the menu bar
|
||||
// is active.
|
||||
return NS_OK;
|
||||
return;
|
||||
} else {
|
||||
nsAccessible *containerAccessible = accessible->GetParent();
|
||||
NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
|
||||
if (!containerAccessible)
|
||||
return;
|
||||
// It is not top level menuitem
|
||||
// Only fire focus event if it is not inside collapsed popup
|
||||
// and not a listitem of a combo box
|
||||
if (nsAccUtils::State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED) {
|
||||
nsAccessible *containerParent = containerAccessible->GetParent();
|
||||
NS_ENSURE_TRUE(containerParent, NS_ERROR_FAILURE);
|
||||
if (!containerParent)
|
||||
return;
|
||||
if (containerParent->Role() != nsIAccessibleRole::ROLE_COMBOBOX) {
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -712,7 +764,6 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
accessible);
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -811,8 +862,8 @@ nsRootAccessible::GetRelationByType(PRUint32 aRelationType,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Protected members
|
||||
|
||||
nsresult
|
||||
nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
|
||||
void
|
||||
nsRootAccessible::HandlePopupShownEvent(nsAccessible* aAccessible)
|
||||
{
|
||||
PRUint32 role = aAccessible->Role();
|
||||
|
||||
|
@ -820,7 +871,7 @@ nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
|
|||
// Don't fire menupopup events for combobox and autocomplete lists.
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
||||
aAccessible);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_TOOLTIP) {
|
||||
|
@ -829,13 +880,14 @@ nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
|
|||
// AT's expect to get an EVENT_SHOW for the tooltip.
|
||||
// In event callback the tooltip's accessible will be ready.
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (role == nsIAccessibleRole::ROLE_COMBOBOX_LIST) {
|
||||
// Fire expanded state change event for comboboxes and autocompeletes.
|
||||
nsAccessible* combobox = aAccessible->GetParent();
|
||||
NS_ENSURE_STATE(combobox);
|
||||
if (!combobox)
|
||||
return;
|
||||
|
||||
PRUint32 comboboxRole = combobox->Role();
|
||||
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
||||
|
@ -844,19 +896,15 @@ nsRootAccessible::HandlePopupShownEvent(nsAccessible *aAccessible)
|
|||
new AccStateChangeEvent(combobox,
|
||||
nsIAccessibleStates::STATE_EXPANDED,
|
||||
PR_FALSE, PR_TRUE);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsEventShell::FireEvent(event);
|
||||
return NS_OK;
|
||||
if (event)
|
||||
nsEventShell::FireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRootAccessible::HandlePopupHidingEvent(nsINode *aNode,
|
||||
nsAccessible *aAccessible)
|
||||
void
|
||||
nsRootAccessible::HandlePopupHidingEvent(nsINode* aNode,
|
||||
nsAccessible* aAccessible)
|
||||
{
|
||||
// If accessible focus was on or inside popup that closes, then restore it
|
||||
// to true current focus. This is the case when we've been getting
|
||||
|
@ -871,14 +919,13 @@ nsRootAccessible::HandlePopupHidingEvent(nsINode *aNode,
|
|||
}
|
||||
|
||||
// Fire expanded state change event for comboboxes and autocompletes.
|
||||
if (!aAccessible)
|
||||
return NS_OK;
|
||||
|
||||
if (aAccessible->Role() != nsIAccessibleRole::ROLE_COMBOBOX_LIST)
|
||||
return NS_OK;
|
||||
if (!aAccessible ||
|
||||
aAccessible->Role() != nsIAccessibleRole::ROLE_COMBOBOX_LIST)
|
||||
return;
|
||||
|
||||
nsAccessible* combobox = aAccessible->GetParent();
|
||||
NS_ENSURE_STATE(combobox);
|
||||
if (!combobox)
|
||||
return;
|
||||
|
||||
PRUint32 comboboxRole = combobox->Role();
|
||||
if (comboboxRole == nsIAccessibleRole::ROLE_COMBOBOX ||
|
||||
|
@ -887,51 +934,46 @@ nsRootAccessible::HandlePopupHidingEvent(nsINode *aNode,
|
|||
new AccStateChangeEvent(combobox,
|
||||
nsIAccessibleStates::STATE_EXPANDED,
|
||||
PR_FALSE, PR_FALSE);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsEventShell::FireEvent(event);
|
||||
return NS_OK;
|
||||
if (event)
|
||||
nsEventShell::FireEvent(event);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsresult
|
||||
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsXULTreeAccessible *aAccessible)
|
||||
void
|
||||
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
|
||||
nsXULTreeAccessible* aAccessible)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
||||
if (!dataEvent)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIVariant> indexVariant;
|
||||
dataEvent->GetData(NS_LITERAL_STRING("index"),
|
||||
getter_AddRefs(indexVariant));
|
||||
if (!indexVariant)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIVariant> countVariant;
|
||||
dataEvent->GetData(NS_LITERAL_STRING("count"),
|
||||
getter_AddRefs(countVariant));
|
||||
if (!countVariant)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
PRInt32 index, count;
|
||||
indexVariant->GetAsInt32(&index);
|
||||
countVariant->GetAsInt32(&count);
|
||||
|
||||
aAccessible->InvalidateCache(index, count);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
nsXULTreeAccessible *aAccessible)
|
||||
void
|
||||
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
|
||||
nsXULTreeAccessible* aAccessible)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
||||
if (!dataEvent)
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
PRInt32 startRow = 0, endRow = -1, startCol = 0, endCol = -1;
|
||||
|
||||
|
@ -960,7 +1002,5 @@ nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
|||
endColVariant->GetAsInt32(&endCol);
|
||||
|
||||
aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -127,24 +127,32 @@ public:
|
|||
protected:
|
||||
NS_DECL_RUNNABLEMETHOD(nsRootAccessible, FireCurrentFocusEvent)
|
||||
|
||||
nsresult AddEventListeners();
|
||||
nsresult RemoveEventListeners();
|
||||
/**
|
||||
* Add/remove DOM event listeners.
|
||||
*/
|
||||
virtual nsresult AddEventListeners();
|
||||
virtual nsresult RemoveEventListeners();
|
||||
|
||||
/**
|
||||
* Process the DOM event.
|
||||
*/
|
||||
void ProcessDOMEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
/**
|
||||
* Process "popupshown" event. Used by HandleEvent().
|
||||
*/
|
||||
void HandlePopupShownEvent(nsAccessible* aAccessible);
|
||||
|
||||
nsresult HandlePopupShownEvent(nsAccessible *aAccessible);
|
||||
/*
|
||||
* Process "popuphiding" event. Used by HandleEvent().
|
||||
*/
|
||||
nsresult HandlePopupHidingEvent(nsINode *aNode, nsAccessible *aAccessible);
|
||||
void HandlePopupHidingEvent(nsINode* aNode, nsAccessible* aAccessible);
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsXULTreeAccessible *aAccessible);
|
||||
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
nsXULTreeAccessible *aAccessible);
|
||||
void HandleTreeRowCountChangedEvent(nsIDOMEvent* aEvent,
|
||||
nsXULTreeAccessible* aAccessible);
|
||||
void HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
|
||||
nsXULTreeAccessible* aAccessible);
|
||||
|
||||
PRUint32 GetChromeFlags();
|
||||
#endif
|
||||
|
@ -156,4 +164,4 @@ protected:
|
|||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsRootAccessible, NS_ROOTACCESSIBLE_IMPL_CID)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -371,11 +371,6 @@ protected:
|
|||
nsIPersistentProperties *aAttributes);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Embedded objects collector.
|
||||
*/
|
||||
nsAutoPtr<AccCollector> mLinks;
|
||||
|
||||
/**
|
||||
* End text offsets array.
|
||||
*/
|
||||
|
|
|
@ -295,13 +295,13 @@ nsXULTreeAccessible::SelectedItems()
|
|||
if (!selectedItems)
|
||||
return nsnull;
|
||||
|
||||
PRInt32 rowIndex, rowCount;
|
||||
PRBool isSelected;
|
||||
mTreeView->GetRowCount(&rowCount);
|
||||
for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||
selection->IsSelected(rowIndex, &isSelected);
|
||||
if (isSelected) {
|
||||
nsIAccessible* item = GetTreeItemAccessible(rowIndex);
|
||||
PRInt32 rangeCount = 0;
|
||||
selection->GetRangeCount(&rangeCount);
|
||||
for (PRInt32 rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
|
||||
PRInt32 firstIdx = 0, lastIdx = -1;
|
||||
selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
|
||||
for (PRInt32 rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
|
||||
nsIAccessible* item = GetTreeItemAccessible(rowIdx);
|
||||
if (item)
|
||||
selectedItems->AppendElement(item, PR_FALSE);
|
||||
}
|
||||
|
@ -391,15 +391,15 @@ nsXULTreeAccessible::GetSelectedItem(PRUint32 aIndex)
|
|||
if (!selection)
|
||||
return nsnull;
|
||||
|
||||
PRInt32 rowIndex, rowCount;
|
||||
PRInt32 selCount = 0;
|
||||
PRBool isSelected;
|
||||
mTreeView->GetRowCount(&rowCount);
|
||||
for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||
selection->IsSelected(rowIndex, &isSelected);
|
||||
if (isSelected) {
|
||||
PRUint32 selCount = 0;
|
||||
PRInt32 rangeCount = 0;
|
||||
selection->GetRangeCount(&rangeCount);
|
||||
for (PRInt32 rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
|
||||
PRInt32 firstIdx = 0, lastIdx = -1;
|
||||
selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
|
||||
for (PRInt32 rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
|
||||
if (selCount == aIndex)
|
||||
return GetTreeItemAccessible(rowIndex);
|
||||
return GetTreeItemAccessible(rowIdx);
|
||||
|
||||
selCount++;
|
||||
}
|
||||
|
|
|
@ -120,6 +120,12 @@ function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq)
|
|||
}
|
||||
|
||||
this.eventSeq = aEventSeq;
|
||||
|
||||
this.getID = function actionInvoker_getID()
|
||||
{
|
||||
return "invoke an action " + aActionName + " at index " + aActionIndex +
|
||||
" on " + prettyName(aAccOrElmOrId);
|
||||
}
|
||||
}
|
||||
|
||||
function checkerOfActionInvoker(aType, aTarget, aActionObj)
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
}
|
||||
|
||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
gA11yEventDumpToConsole = true;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
{
|
||||
is(aEvent.QueryInterface(nsIAccessibleCaretMoveEvent).caretOffset,
|
||||
aCaretOffset,
|
||||
"Wrong caret offset for " + prettyName(aEvent.target));
|
||||
"Wrong caret offset for " + prettyName(aEvent.accessible));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -243,6 +243,71 @@
|
|||
this.setTarget(kShowEvent, this.newElm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger content insertion, removal and insertion of the same element
|
||||
* for the same parent.
|
||||
*/
|
||||
function test1(aContainerID)
|
||||
{
|
||||
this.divNode = document.createElement("div");
|
||||
this.divNode.setAttribute("id", "div-test1");
|
||||
this.containerNode = getNode(aContainerID);
|
||||
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_SHOW, this.divNode),
|
||||
new invokerChecker(EVENT_REORDER, this.containerNode)
|
||||
];
|
||||
|
||||
this.invoke = function test1_invoke()
|
||||
{
|
||||
this.containerNode.appendChild(this.divNode);
|
||||
getComputedStyle(this.divNode, "").color;
|
||||
this.containerNode.removeChild(this.divNode);
|
||||
this.containerNode.appendChild(this.divNode);
|
||||
}
|
||||
|
||||
this.getID = function test1_getID()
|
||||
{
|
||||
return "test1";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger content insertion, removal and insertion of the same element
|
||||
* for the different parents.
|
||||
*/
|
||||
function test2(aContainerID, aTmpContainerID)
|
||||
{
|
||||
this.divNode = document.createElement("div");
|
||||
this.divNode.setAttribute("id", "div-test2");
|
||||
this.containerNode = getNode(aContainerID);
|
||||
this.tmpContainerNode = getNode(aTmpContainerID);
|
||||
this.container = getAccessible(this.containerNode);
|
||||
this.tmpContainer = getAccessible(this.tmpContainerNode);
|
||||
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_SHOW, this.divNode),
|
||||
new invokerChecker(EVENT_REORDER, this.containerNode)
|
||||
];
|
||||
|
||||
this.unexpectedEventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, this.tmpContainerNode)
|
||||
];
|
||||
|
||||
this.invoke = function test2_invoke()
|
||||
{
|
||||
this.tmpContainerNode.appendChild(this.divNode);
|
||||
getComputedStyle(this.divNode, "").color;
|
||||
this.tmpContainerNode.removeChild(this.divNode);
|
||||
this.containerNode.appendChild(this.divNode);
|
||||
}
|
||||
|
||||
this.getID = function test2_getID()
|
||||
{
|
||||
return "test2";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Target getters.
|
||||
*/
|
||||
|
@ -361,6 +426,10 @@
|
|||
gQueue.push(new changeClass("container3", "link8", "visibilityHidden",
|
||||
kHideEvents));
|
||||
|
||||
gQueue.push(new test1("testContainer"));
|
||||
gQueue.push(new test2("testContainer", "testContainer2"));
|
||||
gQueue.push(new test2("testContainer", "testNestedContainer"));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -374,23 +443,23 @@
|
|||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=469985"
|
||||
title=" turn the test from bug 354745 into mochitest">
|
||||
Mozilla Bug 469985
|
||||
</a><br>
|
||||
Mozilla Bug 469985</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=472662"
|
||||
title="no reorder event when html:link display property is changed from 'none' to 'inline'">
|
||||
Mozilla Bug 472662
|
||||
</a><br>
|
||||
Mozilla Bug 472662</a>
|
||||
<a target="_blank"
|
||||
title="Rework accessible tree update code"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
|
||||
Mozilla Bug 570275
|
||||
</a><br>
|
||||
Mozilla Bug 570275</a>
|
||||
<a target="_blank"
|
||||
title="Develop a way to handle visibility style"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=606125">
|
||||
Mozilla Bug 606125
|
||||
</a>
|
||||
Mozilla Bug 606125</a>
|
||||
<a target="_blank"
|
||||
title="Update accessible tree on content insertion after layout"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=498015">
|
||||
Mozilla Bug 498015</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
@ -416,6 +485,8 @@
|
|||
|
||||
<div id="container2" class="displayNone"><a id="link7">Link #7</a></div>
|
||||
<div id="container3" class="visibilityHidden"><a id="link8">Link #8</a></div>
|
||||
<div id="testNestedContainer"></div>
|
||||
</div>
|
||||
<div id="testContainer2"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
tabcontainer="tabbrowser-tabs"
|
||||
flex="1"/>
|
||||
</vbox>
|
||||
<toolbar id="addon-bar"/>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
const nsIDOMNSEditableElement =
|
||||
Components.interfaces.nsIDOMNSEditableElement;
|
||||
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
|
||||
function spelledTextInvoker(aID)
|
||||
{
|
||||
this.DOMNode = getNode(aID);
|
||||
|
@ -35,12 +37,14 @@
|
|||
|
||||
this.invoke = function spelledTextInvoker_invoke()
|
||||
{
|
||||
this.DOMNode.setAttribute("value", "valid text inalid tixt");
|
||||
this.DOMNode.focus();
|
||||
|
||||
var editor = this.DOMNode.QueryInterface(nsIDOMNSEditableElement).editor;
|
||||
var spellchecker = editor.getInlineSpellChecker(true);
|
||||
spellchecker.enableRealTimeSpell = true;
|
||||
var spellChecker = new InlineSpellChecker(editor);
|
||||
spellChecker.enabled = true;
|
||||
|
||||
//var spellchecker = editor.getInlineSpellChecker(true);
|
||||
//spellchecker.enableRealTimeSpell = true;
|
||||
|
||||
this.DOMNode.value = "valid text inalid tixt";
|
||||
}
|
||||
|
||||
this.finalCheck = function spelledTextInvoker_finalCheck()
|
||||
|
@ -69,12 +73,17 @@
|
|||
* Do tests.
|
||||
*/
|
||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
//gA11yEventDumpToConsole = true;
|
||||
|
||||
var gQueue = null;
|
||||
function doTests()
|
||||
{
|
||||
// Synth focus before spellchecking turning on to make sure editor
|
||||
// gets a time for initialization.
|
||||
|
||||
gQueue = new eventQueue();
|
||||
gQueue.push(new spelledTextInvoker("area8"));
|
||||
gQueue.push(new synthFocus("input", null, EVENT_FOCUS));
|
||||
gQueue.push(new spelledTextInvoker("input"));
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -95,7 +104,7 @@
|
|||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<input id="area8"/>
|
||||
<input id="input"/>
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
type="content-primary"
|
||||
tabcontainer="tabbrowser-tabs"
|
||||
flex="1"/>
|
||||
<toolbar id="addon-bar"/>
|
||||
</vbox>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
src="../role.js" />
|
||||
<script type="application/javascript"
|
||||
src="../states.js" />
|
||||
<script type="application/javascript"
|
||||
src="../selectable.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
@ -53,7 +55,7 @@
|
|||
if (seltype != "single" && seltype != "cell" && seltype != "text")
|
||||
isTreeMultiSelectable = true;
|
||||
|
||||
// test SelectAllSelection correctly discerns multiselect vs single
|
||||
// selectAllSelection
|
||||
var accSelectable = getAccessible(this.DOMNode,
|
||||
[nsIAccessibleSelectable]);
|
||||
ok(accSelectable, "tree is not selectable!");
|
||||
|
@ -62,15 +64,39 @@
|
|||
"SelectAllSelection is not correct for seltype: " + seltype);
|
||||
}
|
||||
|
||||
// test that the selection worked as expected
|
||||
var rows = tree.children;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var selectedChildren = [];
|
||||
if (isTreeMultiSelectable) {
|
||||
var rows = tree.children;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var row = rows.queryElementAt(i, nsIAccessible);
|
||||
if (getRole(row) == (ROLE_OUTLINEITEM || ROLE_ROW)){
|
||||
testStates(row, isTreeMultiSelectable? STATE_SELECTED : 0, 0, 0,
|
||||
isTreeMultiSelectable? 0: STATE_SELECTED);
|
||||
if (getRole(row) == ROLE_OUTLINEITEM || getRole(row) == ROLE_ROW)
|
||||
selectedChildren.push(row);
|
||||
}
|
||||
}
|
||||
testSelectableSelection(accSelectable, selectedChildren,
|
||||
"selectAllSelection test. ");
|
||||
|
||||
// clearSelection
|
||||
accSelectable.clearSelection();
|
||||
testSelectableSelection(accSelectable, [], "clearSelection test. ");
|
||||
|
||||
// addChildToSelection
|
||||
accSelectable.addChildToSelection(1);
|
||||
accSelectable.addChildToSelection(3);
|
||||
|
||||
selectedChildren = isTreeMultiSelectable ?
|
||||
[ accSelectable.getChildAt(2), accSelectable.getChildAt(4) ] :
|
||||
[ accSelectable.getChildAt(2) ];
|
||||
testSelectableSelection(accSelectable, selectedChildren,
|
||||
"addChildToSelection test. ");
|
||||
|
||||
// removeChildFromSelection
|
||||
accSelectable.removeChildFromSelection(1);
|
||||
|
||||
selectedChildren = isTreeMultiSelectable ?
|
||||
[ accSelectable.getChildAt(4) ] : [ ];
|
||||
testSelectableSelection(accSelectable, selectedChildren,
|
||||
"removeChildFromSelection test. ");
|
||||
}
|
||||
|
||||
this.getID = function getID()
|
||||
|
@ -104,6 +130,11 @@
|
|||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=523118"
|
||||
title="we mistake 'cell' and text' xul tree seltypes for multiselects">
|
||||
Mozilla Bug 523118
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=624977"
|
||||
title="Optimize nsXulTreeAccessible selectedItems()">
|
||||
Mozilla Bug 624977
|
||||
</a><br/>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
|
|
@ -154,6 +154,7 @@
|
|||
type="content-primary"
|
||||
tabcontainer="tabbrowser-tabs"
|
||||
flex="1"/>
|
||||
<toolbar id="addon-bar"/>
|
||||
</vbox>
|
||||
|
||||
</window>
|
||||
|
|
|
@ -172,6 +172,16 @@
|
|||
|
||||
testAccessibleTree("c7", accTree);
|
||||
|
||||
// only whitespace between images should be exposed
|
||||
accTree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree("c8", accTree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -184,13 +194,16 @@
|
|||
<a target="_blank"
|
||||
title="overflowed content doesn't expose child text accessibles"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489306">
|
||||
Mozilla Bug 489306
|
||||
</a><br>
|
||||
Mozilla Bug 489306</a>
|
||||
<a target="_blank"
|
||||
title="Create child accessibles for text controls from native anonymous content"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=542824">
|
||||
Mozilla Bug 542824
|
||||
</a><br>
|
||||
Mozilla Bug 542824</a>
|
||||
<a target="_blank"
|
||||
title="Update accessible tree on content insertion after layout"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=498015">
|
||||
Mozilla Bug 498015</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
|
@ -216,5 +229,8 @@
|
|||
<div id="c5"><blockquote>Hello</blockquote></div>
|
||||
<div id="c6">This <abbr title="accessibility">a11y</abbr> test</div>
|
||||
<div id="c7">This <acronym title="personal computer">PC</acronym> is broken</div>
|
||||
|
||||
<!-- only whitespace between images should be exposed -->
|
||||
<div id="c8"> <img src="../moz.png"> <img src="../moz.png"> </div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -126,8 +126,8 @@
|
|||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_HIDE, getNode(aParentID)),
|
||||
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
|
||||
new invokerChecker(EVENT_HIDE, getNode(aParent2ID)),
|
||||
new invokerChecker(EVENT_SHOW, getNode(aChildID)),
|
||||
new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
|
||||
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
|
||||
];
|
||||
|
|
|
@ -70,7 +70,7 @@ pref("extensions.blocklist.interval", 86400);
|
|||
// Controls what level the blocklist switches from warning about items to forcibly
|
||||
// blocking them.
|
||||
pref("extensions.blocklist.level", 2);
|
||||
pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/");
|
||||
pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
|
||||
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
|
||||
|
||||
pref("extensions.update.autoUpdateDefault", true);
|
||||
|
@ -539,6 +539,9 @@ pref("alerts.totalOpenTime", 4000);
|
|||
pref("browser.xul.error_pages.enabled", true);
|
||||
pref("browser.xul.error_pages.expert_bad_cert", false);
|
||||
|
||||
// Work Offline is best manually managed by the user.
|
||||
pref("network.manage-offline-status", false);
|
||||
|
||||
// We want to make sure mail URLs are handled externally...
|
||||
pref("network.protocol-handler.external.mailto", true); // for mail
|
||||
pref("network.protocol-handler.external.news", true); // for news
|
||||
|
|
|
@ -76,8 +76,8 @@ function init(aEvent)
|
|||
#ifdef MOZ_OFFICIAL_BRANDING
|
||||
// Hide the Charlton trademark attribution for non-en-US/en-GB
|
||||
// DO NOT REMOVE without consulting people involved with bug 616193
|
||||
let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIXULChromeRegistry);
|
||||
let chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Components.interfaces.nsIXULChromeRegistry);
|
||||
let currentLocale = chromeRegistry.getSelectedLocale("global");
|
||||
if (currentLocale != "en-US" && currentLocale != "en-GB") {
|
||||
document.getElementById("extra-trademark").hidden = true;
|
||||
|
|
|
@ -347,7 +347,7 @@
|
|||
|
||||
<key id="key_switchTextDirection" key="&bidiSwitchTextDirectionItem.commandkey;" command="cmd_switchTextDirection" modifiers="accel,shift" />
|
||||
|
||||
<key id="key_tabview" key="&tabView.commandkey;" command="Browser:ToggleTabView" modifiers="accel"/>
|
||||
<key id="key_tabview" key="&tabView.commandkey;" command="Browser:ToggleTabView" modifiers="accel,shift"/>
|
||||
|
||||
<key id="key_privatebrowsing" command="Tools:PrivateBrowsing" key="&privateBrowsingCmd.commandkey;" modifiers="accel,shift"/>
|
||||
<key id="key_sanitize" command="Tools:Sanitize" keycode="VK_DELETE" modifiers="accel,shift"/>
|
||||
|
|
|
@ -39,7 +39,7 @@ let TabView = {
|
|||
_deck: null,
|
||||
_window: null,
|
||||
_sessionstore: null,
|
||||
_visibilityID: "tabview-visibility",
|
||||
VISIBILITY_IDENTIFIER: "tabview-visibility",
|
||||
|
||||
// ----------
|
||||
get windowTitle() {
|
||||
|
@ -60,7 +60,8 @@ let TabView = {
|
|||
Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
||||
let data = this._sessionstore.getWindowValue(window, this._visibilityID);
|
||||
let data = this._sessionstore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
|
||||
|
||||
if (data && data == "true") {
|
||||
this.show();
|
||||
} else {
|
||||
|
@ -78,12 +79,6 @@ let TabView = {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
uninit: function TabView_uninit() {
|
||||
if (this._window)
|
||||
Services.obs.removeObserver(this, "quit-application-requested");
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Creates the frame and calls the callback once it's loaded.
|
||||
// If the frame already exists, calls the callback immediately.
|
||||
|
@ -108,9 +103,6 @@ let TabView = {
|
|||
this._deck.appendChild(iframe);
|
||||
this._window = iframe.contentWindow;
|
||||
|
||||
// ___ visibility storage handler
|
||||
Services.obs.addObserver(this, "quit-application-requested", false);
|
||||
|
||||
if (this._tabShowEventListener) {
|
||||
gBrowser.tabContainer.removeEventListener(
|
||||
"TabShow", this._tabShowEventListener, true);
|
||||
|
@ -118,14 +110,6 @@ let TabView = {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
observe: function TabView_observe(subject, topic, data) {
|
||||
if (topic == "quit-application-requested") {
|
||||
let data = (this.isVisible() ? "true" : "false");
|
||||
this._sessionstore.setWindowValue(window, this._visibilityID, data);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
getContentWindow: function TabView_getContentWindow() {
|
||||
return this._window;
|
||||
|
|
|
@ -40,7 +40,7 @@ tabbrowser {
|
|||
opacity: 0 !important;
|
||||
-moz-transition: min-width 200ms ease-out,
|
||||
max-width 250ms ease-out,
|
||||
opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
|
||||
opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
|
||||
}
|
||||
|
||||
.tab-throbber:not([fadein]):not([pinned]),
|
||||
|
@ -57,8 +57,8 @@ tabbrowser {
|
|||
-moz-transition: opacity 250ms;
|
||||
}
|
||||
|
||||
.tabbrowser-tabs:not([pinnedonly]) > .tabbrowser-tab[pinned] {
|
||||
position: fixed;
|
||||
.tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
|
||||
position: fixed !important;
|
||||
display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
|
||||
}
|
||||
|
||||
|
@ -480,6 +480,9 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/* We use the iconBox as the notification anchor when a popup notification is
|
||||
created with a null anchorID, so in that case use a default anchor icon. */
|
||||
#notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon,
|
||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
|
||||
#notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
|
||||
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
|
||||
|
@ -506,7 +509,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
}
|
||||
|
||||
/* Remove the resizer from the statusbar compatibility shim */
|
||||
#status-bar > .statusbar-resizerpanel {
|
||||
#status-bar[hideresizer] > .statusbar-resizerpanel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -873,7 +873,27 @@ const gFormSubmitObserver = {
|
|||
}, false);
|
||||
|
||||
this.panel.hidden = false;
|
||||
this.panel.openPopup(element, "after_start", 0, 0);
|
||||
|
||||
// We want to show the popup at the middle of checkbox and radio buttons
|
||||
// and where the content begin for the other elements.
|
||||
let offset = 0;
|
||||
let position = "";
|
||||
|
||||
if (element.tagName == 'INPUT' &&
|
||||
(element.type == 'radio' || element.type == 'checkbox')) {
|
||||
position = "bottomcenter topleft";
|
||||
} else {
|
||||
let style = element.ownerDocument.defaultView.getComputedStyle(element, null);
|
||||
if (style.direction == 'rtl') {
|
||||
offset = parseInt(style.paddingRight) + parseInt(style.borderRightWidth);
|
||||
} else {
|
||||
offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
|
||||
}
|
||||
|
||||
position = "after_start";
|
||||
}
|
||||
|
||||
this.panel.openPopup(element, position, offset, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1264,6 +1284,9 @@ function BrowserStartup() {
|
|||
document.documentElement.setAttribute("height", defaultHeight);
|
||||
}
|
||||
|
||||
if (!gShowPageResizers)
|
||||
document.getElementById("status-bar").setAttribute("hideresizer", "true");
|
||||
|
||||
if (!window.toolbar.visible) {
|
||||
// adjust browser UI for popups
|
||||
if (gURLBar) {
|
||||
|
@ -1672,7 +1695,6 @@ function BrowserShutdown()
|
|||
Components.utils.reportError(ex);
|
||||
}
|
||||
|
||||
TabView.uninit();
|
||||
BrowserOffline.uninit();
|
||||
OfflineApps.uninit();
|
||||
gPrivateBrowsingUI.uninit();
|
||||
|
@ -2776,6 +2798,7 @@ var PrintPreviewListener = {
|
|||
var addonBar = document.getElementById("addon-bar");
|
||||
this._chromeState.addonBarOpen = !addonBar.collapsed;
|
||||
addonBar.collapsed = true;
|
||||
gBrowser.updateWindowResizers();
|
||||
|
||||
this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden;
|
||||
if (gFindBarInitialized)
|
||||
|
@ -2792,8 +2815,10 @@ var PrintPreviewListener = {
|
|||
if (this._chromeState.notificationsOpen)
|
||||
gBrowser.getNotificationBox().notificationsHidden = false;
|
||||
|
||||
if (this._chromeState.addonBarOpen)
|
||||
if (this._chromeState.addonBarOpen) {
|
||||
document.getElementById("addon-bar").collapsed = false;
|
||||
gBrowser.updateWindowResizers();
|
||||
}
|
||||
|
||||
if (this._chromeState.findOpen)
|
||||
gFindBar.open();
|
||||
|
@ -4767,6 +4792,7 @@ function setToolbarVisibility(toolbar, isVisible) {
|
|||
|
||||
PlacesToolbarHelper.init();
|
||||
BookmarksMenuButton.updatePosition();
|
||||
gBrowser.updateWindowResizers();
|
||||
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
updateAppButtonDisplay();
|
||||
|
@ -8227,8 +8253,8 @@ var TabContextMenu = {
|
|||
document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1;
|
||||
document.getElementById("context_closeOtherTabs").hidden = this.contextTab.pinned;
|
||||
|
||||
// Disable "Move to Group" if it's a pinned tab.
|
||||
document.getElementById("context_tabViewMenu").disabled = this.contextTab.pinned;
|
||||
// Hide "Move to Group" if it's a pinned tab.
|
||||
document.getElementById("context_tabViewMenu").hidden = this.contextTab.pinned;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8329,3 +8355,15 @@ let AddonsMgrListener = {
|
|||
setToolbarVisibility(this.addonBar, false);
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
|
||||
#ifdef XP_WIN
|
||||
// Only show resizers on Windows 2000 and XP
|
||||
let sysInfo = Components.classes["@mozilla.org/system-info;1"]
|
||||
.getService(Components.interfaces.nsIPropertyBag2);
|
||||
return parseFloat(sysInfo.getProperty("version")) < 6;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
});
|
||||
|
||||
|
|
|
@ -543,6 +543,7 @@
|
|||
onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
|
||||
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
|
||||
<box id="notification-popup-box" hidden="true" align="center">
|
||||
<image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
|
@ -1014,6 +1015,10 @@
|
|||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
<svg:svg height="0">
|
||||
<svg:mask id="pinstripe-keyhole-forward-mask" maskContentUnits="objectBoundingBox">
|
||||
<svg:rect x="0" y="0" width="1" height="1" fill="white"/>
|
||||
<svg:circle cx="-0.46" cy="0.48" r="0.65"/>
|
||||
</svg:mask>
|
||||
<svg:mask id="pinstripe-tab-ontop-left-curve-mask" maskContentUnits="userSpaceOnUse">
|
||||
<svg:circle cx="9" cy="3" r="3" fill="white"/>
|
||||
<svg:rect x="9" y="0" width="3" height="3" fill="white"/>
|
||||
|
|
|
@ -94,7 +94,7 @@ let Change = {
|
|||
document.getElementById("passphraseBackupButtons").hidden = true;
|
||||
document.getElementById("generatePassphraseButton").hidden = true;
|
||||
document.title = this._str("new.synckey.title");
|
||||
introText.textContent = this._str("new.synckey.introText");
|
||||
introText.textContent = this._str("new.synckey2.introText");
|
||||
this._dialog.getButton("accept")
|
||||
.setAttribute("label", this._str("new.synckey.acceptButton"));
|
||||
}
|
||||
|
|
|
@ -312,14 +312,15 @@
|
|||
<spacer/>
|
||||
<hbox>
|
||||
<image class="statusIcon"/>
|
||||
<vbox>
|
||||
<label class="status" value=" "/>
|
||||
<label class="text-link"
|
||||
value="&resetPassword.label;"
|
||||
onclick="gSyncUtils.resetPassword(); return false;"/>
|
||||
</vbox>
|
||||
<label class="status" value=" "/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row align="center">
|
||||
<spacer/>
|
||||
<label class="text-link"
|
||||
value="&resetPassword.label;"
|
||||
onclick="gSyncUtils.resetPassword(); return false;"/>
|
||||
</row>
|
||||
<row align="center">
|
||||
<label control="existingServer"
|
||||
value="&server.label;"/>
|
||||
|
@ -360,12 +361,7 @@
|
|||
<vbox align="left" id="existingPassphraseFeedbackRow" hidden="true">
|
||||
<hbox>
|
||||
<image class="statusIcon"/>
|
||||
<vbox>
|
||||
<label class="status" value=" "/>
|
||||
<label class="text-link"
|
||||
value="&lostSyncKey.label;"
|
||||
onclick="gSyncUtils.resetPassphrase(); return false;"/>
|
||||
</vbox>
|
||||
<label class="status" value=" "/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
@ -376,6 +372,9 @@
|
|||
<label class="text-link"
|
||||
value="&addDevice.showMeHow.label;"
|
||||
href="https://services.mozilla.com/sync/help/manual-setup"/>
|
||||
<label class="text-link"
|
||||
value="&resetSyncKey.label;"
|
||||
onclick="gSyncUtils.resetPassphrase(); return false;"/>
|
||||
</description>
|
||||
</vbox>
|
||||
</wizardpage>
|
||||
|
|
|
@ -177,6 +177,18 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="updateWindowResizers">
|
||||
<body><![CDATA[
|
||||
if (!window.gShowPageResizers)
|
||||
return;
|
||||
|
||||
var show = document.getElementById("addon-bar").collapsed;
|
||||
for (let i = 0; i < this.browsers.length; i++) {
|
||||
this.browsers[i].showWindowResizer = show;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="pinTab">
|
||||
<parameter name="aTab"/>
|
||||
<body><![CDATA[
|
||||
|
@ -1212,8 +1224,6 @@
|
|||
}
|
||||
|
||||
this.tabContainer.appendChild(t);
|
||||
if (this.tabContainer.getAttribute("pinnedonly") == "true")
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
|
||||
if (this.tabContainer.mTabstrip._isRTLScrollbox) {
|
||||
/* In RTL UI, the tab is visually added to the left side of the
|
||||
|
@ -1238,6 +1248,11 @@
|
|||
b.setAttribute("message", "true");
|
||||
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
|
||||
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
|
||||
|
||||
if (window.gShowPageResizers && document.getElementById("addon-bar").collapsed) {
|
||||
b.setAttribute("showresizer", "true");
|
||||
}
|
||||
|
||||
if (this.hasAttribute("autocompletepopup"))
|
||||
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
|
||||
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
|
@ -1611,6 +1626,8 @@
|
|||
if (browser == this.mCurrentBrowser)
|
||||
this.mCurrentBrowser = null;
|
||||
|
||||
var wasPinned = aTab.pinned;
|
||||
|
||||
// Invalidate browsers cache, as the tab is removed from the
|
||||
// tab container.
|
||||
this._browsers = null;
|
||||
|
@ -1623,7 +1640,8 @@
|
|||
this.tabs[i]._tPos = i;
|
||||
|
||||
if (!this._windowIsClosing) {
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
if (wasPinned)
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
|
||||
// update tab close buttons state
|
||||
this.tabContainer.adjustTabstrip();
|
||||
|
@ -1672,6 +1690,7 @@
|
|||
return;
|
||||
|
||||
if (aTab.owner &&
|
||||
!aTab.owner.hidden &&
|
||||
this._removingTabs.indexOf(aTab.owner) == -1 &&
|
||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")) {
|
||||
this.selectedTab = aTab.owner;
|
||||
|
@ -2431,6 +2450,7 @@
|
|||
this.appendChild(this._autoScrollPopup);
|
||||
this.mCurrentBrowser.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
this.mCurrentBrowser.droppedLinkHandler = handleDroppedLink;
|
||||
this.updateWindowResizers();
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
|
@ -2796,30 +2816,36 @@
|
|||
<method name="_positionPinnedTabs">
|
||||
<body><![CDATA[
|
||||
var numPinned = this.tabbrowser._numPinnedTabs;
|
||||
var pinnedOnly = (numPinned == this.tabbrowser.visibleTabs.length);
|
||||
var doPosition = this.getAttribute("overflow") == "true" &&
|
||||
numPinned > 0 &&
|
||||
numPinned < this.tabbrowser.visibleTabs.length;
|
||||
|
||||
if (pinnedOnly)
|
||||
this.setAttribute("pinnedonly", "true");
|
||||
else
|
||||
this.removeAttribute("pinnedonly");
|
||||
if (doPosition) {
|
||||
this.setAttribute("positionpinnedtabs", "true");
|
||||
|
||||
var scrollButtonWidth = (this.getAttribute("overflow") != "true" || pinnedOnly) ? 0 :
|
||||
this.mTabstrip._scrollButtonDown.scrollWidth;
|
||||
var paddingStart = this.mTabstrip.scrollboxPaddingStart;
|
||||
var width = 0;
|
||||
let scrollButtonWidth = this.mTabstrip._scrollButtonDown.scrollWidth;
|
||||
let paddingStart = this.mTabstrip.scrollboxPaddingStart;
|
||||
let width = 0;
|
||||
|
||||
for (var i = numPinned - 1; i >= 0; i--) {
|
||||
let tab = this.childNodes[i];
|
||||
width += pinnedOnly ? 0 : tab.scrollWidth;
|
||||
if (this.getAttribute("overflow") != "true")
|
||||
tab.style.MozMarginStart = - (width + scrollButtonWidth) + "px";
|
||||
else
|
||||
for (let i = numPinned - 1; i >= 0; i--) {
|
||||
let tab = this.childNodes[i];
|
||||
width += tab.scrollWidth;
|
||||
tab.style.MozMarginStart = - (width + scrollButtonWidth + paddingStart) + "px";
|
||||
}
|
||||
if (width == 0 || this.getAttribute("overflow") != "true")
|
||||
this.style.MozMarginStart = width + "px";
|
||||
else
|
||||
}
|
||||
|
||||
this.style.MozMarginStart = width + paddingStart + "px";
|
||||
|
||||
} else {
|
||||
this.removeAttribute("positionpinnedtabs");
|
||||
|
||||
for (let i = 0; i < numPinned; i++) {
|
||||
let tab = this.childNodes[i];
|
||||
tab.style.MozMarginStart = "";
|
||||
}
|
||||
|
||||
this.style.MozMarginStart = "";
|
||||
}
|
||||
|
||||
this.mTabstrip.ensureElementIsVisible(this.selectedItem, false);
|
||||
]]></body>
|
||||
</method>
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
// dontPush - true if this groupItem shouldn't push away or snap on creation; default is false
|
||||
// immediately - true if we want all placement immediately, not with animation
|
||||
function GroupItem(listOfEls, options) {
|
||||
if (typeof options == 'undefined')
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
this._inited = false;
|
||||
|
@ -76,7 +76,6 @@ function GroupItem(listOfEls, options) {
|
|||
this.isAGroupItem = true;
|
||||
this.id = options.id || GroupItems.getNextID();
|
||||
this._isStacked = false;
|
||||
this._stackAngles = [0];
|
||||
this.expanded = null;
|
||||
this.locked = (options.locked ? Utils.copy(options.locked) : {});
|
||||
this.topChild = null;
|
||||
|
@ -813,7 +812,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
item.removeTrenches();
|
||||
|
||||
if (typeof options == 'undefined')
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
var self = this;
|
||||
|
@ -897,7 +896,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
item = Items.item($el);
|
||||
}
|
||||
|
||||
if (typeof options == 'undefined')
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
var index = this._children.indexOf(item);
|
||||
|
@ -1036,8 +1035,6 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
this.$expander
|
||||
.show()
|
||||
.css({
|
||||
opacity: .2,
|
||||
top: childBB.top + childBB.height - parentBB.top + padding,
|
||||
left: parentBB.width/2 - this.$expander.width()/2
|
||||
});
|
||||
},
|
||||
|
@ -1054,10 +1051,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
return: 'widthAndColumns',
|
||||
count: count || this._children.length
|
||||
};
|
||||
let {childWidth, columns} = Items.arrange(null, bb, options);
|
||||
|
||||
let shouldStack = childWidth < TabItems.minTabWidth * 1.35;
|
||||
this._columns = shouldStack ? null : columns;
|
||||
let arrObj = Items.arrange(null, bb, options);
|
||||
|
||||
let shouldStack = arrObj.childWidth < TabItems.minTabWidth * 1.35;
|
||||
this._columns = shouldStack ? null : arrObj.columns;
|
||||
|
||||
return shouldStack;
|
||||
},
|
||||
|
@ -1094,67 +1091,22 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
if (GroupItems._arrangePaused) {
|
||||
GroupItems.pushArrange(this, options);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
var dropIndex = false;
|
||||
if (this.expanded) {
|
||||
this.topChild = null;
|
||||
var box = new Rect(this.expanded.bounds);
|
||||
box.inset(8, 8);
|
||||
let result = Items.arrange(childrenToArrange, box, Utils.extend({}, options, {z: 99999}));
|
||||
dropIndex = result.dropIndex;
|
||||
} else {
|
||||
var count = childrenToArrange.length;
|
||||
var bb = this.getContentBounds();
|
||||
if (!this.shouldStack(count + (options.addTab ? 1 : 0))) {
|
||||
childrenToArrange.forEach(function(child) {
|
||||
child.removeClass("stacked")
|
||||
});
|
||||
|
||||
this.topChild = null;
|
||||
|
||||
if (!childrenToArrange.length)
|
||||
return;
|
||||
|
||||
var arrangeOptions = Utils.extend({}, options, {
|
||||
columns: this._columns
|
||||
});
|
||||
|
||||
// Items.arrange will rearrange the children, but also return an array
|
||||
// of the Rect's used.
|
||||
|
||||
let result = Items.arrange(childrenToArrange, bb, arrangeOptions);
|
||||
dropIndex = result.dropIndex;
|
||||
if ("oldDropIndex" in options && options.oldDropIndex === dropIndex)
|
||||
return dropIndex;
|
||||
var rects = result.rects;
|
||||
|
||||
let index = 0;
|
||||
let self = this;
|
||||
childrenToArrange.forEach(function GroupItem_arrange_children_each(child, i) {
|
||||
// If dropIndex spacing is active and this is a child after index,
|
||||
// bump it up one so we actually use the correct rect
|
||||
// (and skip one for the dropPos)
|
||||
if (self._dropSpaceActive && index === dropIndex)
|
||||
index++;
|
||||
if (!child.locked.bounds) {
|
||||
child.setBounds(rects[index], !options.animate);
|
||||
child.setRotation(0);
|
||||
if (options.z)
|
||||
child.setZ(options.z);
|
||||
}
|
||||
index++;
|
||||
});
|
||||
|
||||
this._isStacked = false;
|
||||
} else
|
||||
this._stackArrange(bb, options);
|
||||
}
|
||||
|
||||
if (this._isStacked && !this.expanded) this.showExpandControl();
|
||||
else this.hideExpandControl();
|
||||
|
||||
return dropIndex;
|
||||
let shouldStack = this.shouldStack(childrenToArrange.length + (options.addTab ? 1 : 0));
|
||||
let box = this.getContentBounds();
|
||||
|
||||
// if we should stack and we're not expanded
|
||||
if (shouldStack && !this.expanded) {
|
||||
this.showExpandControl();
|
||||
this._stackArrange(childrenToArrange, box, options);
|
||||
return false;
|
||||
} else {
|
||||
this.hideExpandControl();
|
||||
// a dropIndex is returned
|
||||
return this._gridArrange(childrenToArrange, box, options);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -1162,27 +1114,22 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// Arranges the children in a stack.
|
||||
//
|
||||
// Parameters:
|
||||
// childrenToArrange - array of <TabItem> children
|
||||
// bb - <Rect> to arrange within
|
||||
// options - see below
|
||||
//
|
||||
// Possible "options" properties:
|
||||
// animate - whether to animate; default: true.
|
||||
_stackArrange: function GroupItem__stackArrange(bb, options) {
|
||||
var animate;
|
||||
if (!options || typeof options.animate == 'undefined')
|
||||
animate = true;
|
||||
else
|
||||
animate = options.animate;
|
||||
|
||||
if (typeof options == 'undefined')
|
||||
_stackArrange: function GroupItem__stackArrange(childrenToArrange, bb, options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
var animate = "animate" in options ? options.animate : true;
|
||||
|
||||
var count = this._children.length;
|
||||
var count = childrenToArrange.length;
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
var zIndex = this.getZ() + count + 1;
|
||||
|
||||
var maxRotation = 35; // degress
|
||||
var scale = 0.8;
|
||||
var newTabsPad = 10;
|
||||
|
@ -1211,7 +1158,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
var self = this;
|
||||
var children = [];
|
||||
this._children.forEach(function GroupItem__stackArrange_order(child) {
|
||||
childrenToArrange.forEach(function GroupItem__stackArrange_order(child) {
|
||||
if (child == self.topChild)
|
||||
children.unshift(child);
|
||||
else
|
||||
|
@ -1225,26 +1172,77 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
child.addClass("stacked");
|
||||
child.setBounds(box, !animate);
|
||||
child.setRotation((UI.rtl ? -1 : 1) * self._randRotate(maxRotation, index));
|
||||
child.setRotation((UI.rtl ? -1 : 1) * Math.min(index, 5) * 5);
|
||||
}
|
||||
});
|
||||
|
||||
self._isStacked = true;
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: _randRotate
|
||||
// Random rotation generator for <_stackArrange>
|
||||
_randRotate: function GroupItem__randRotate(spread, index) {
|
||||
if (index >= this._stackAngles.length) {
|
||||
var randAngle = 5*index + parseInt((Math.random()-.5)*1);
|
||||
this._stackAngles.push(randAngle);
|
||||
return randAngle;
|
||||
// Function: _gridArrange
|
||||
// Arranges the children into a grid.
|
||||
//
|
||||
// Parameters:
|
||||
// childrenToArrange - array of <TabItem> children
|
||||
// box - <Rect> to arrange within
|
||||
// options - see below
|
||||
//
|
||||
// Possible "options" properties:
|
||||
// animate - whether to animate; default: true.
|
||||
// z - (int) a z-index to assign the children
|
||||
// columns - the number of columns to use in the layout, if known in advance
|
||||
//
|
||||
// Returns:
|
||||
// dropIndex - (int) the index at which a dragged item (if there is one) should be added
|
||||
// if it is dropped. Otherwise (boolean) false.
|
||||
_gridArrange: function GroupItem__gridArrange(childrenToArrange, box, options) {
|
||||
this.topChild = null;
|
||||
let arrangeOptions;
|
||||
if (this.expanded) {
|
||||
// if we're expanded, we actually want to use the expanded tray's bounds.
|
||||
box = new Rect(this.expanded.bounds);
|
||||
box.inset(8, 8);
|
||||
arrangeOptions = Utils.extend({}, options, {z: 99999});
|
||||
} else {
|
||||
this._isStacked = false;
|
||||
arrangeOptions = Utils.extend({}, options, {
|
||||
columns: this._columns
|
||||
});
|
||||
|
||||
childrenToArrange.forEach(function(child) {
|
||||
child.removeClass("stacked")
|
||||
});
|
||||
}
|
||||
|
||||
if (!childrenToArrange.length)
|
||||
return false;
|
||||
|
||||
if (index > 5) index = 5;
|
||||
// Items.arrange will determine where/how the child items should be
|
||||
// placed, but will *not* actually move them for us. This is our job.
|
||||
let result = Items.arrange(childrenToArrange, box, arrangeOptions);
|
||||
let {dropIndex, rects} = result;
|
||||
if ("oldDropIndex" in options && options.oldDropIndex === dropIndex)
|
||||
return dropIndex;
|
||||
|
||||
return this._stackAngles[index];
|
||||
let index = 0;
|
||||
let self = this;
|
||||
childrenToArrange.forEach(function GroupItem_arrange_children_each(child, i) {
|
||||
// If dropIndex spacing is active and this is a child after index,
|
||||
// bump it up one so we actually use the correct rect
|
||||
// (and skip one for the dropPos)
|
||||
if (self._dropSpaceActive && index === dropIndex)
|
||||
index++;
|
||||
if (!child.locked.bounds) {
|
||||
child.setBounds(rects[index], !options.animate);
|
||||
child.setRotation(0);
|
||||
if (arrangeOptions.z)
|
||||
child.setZ(arrangeOptions.z);
|
||||
}
|
||||
index++;
|
||||
});
|
||||
|
||||
return dropIndex;
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -1275,6 +1273,9 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
var self = this;
|
||||
// ___ we're stacked, and command is held down so expand
|
||||
GroupItems.setActiveGroupItem(self);
|
||||
let activeTab = this.topChild || this.getChildren()[0];
|
||||
UI.setActiveTab(activeTab);
|
||||
|
||||
var startBounds = this.getChild(0).getBounds();
|
||||
var $tray = iQ("<div>").css({
|
||||
top: startBounds.top,
|
||||
|
@ -1284,7 +1285,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
position: "absolute",
|
||||
zIndex: 99998
|
||||
}).appendTo("body");
|
||||
|
||||
$tray[0].id = "expandedTray";
|
||||
|
||||
var w = 180;
|
||||
var h = w * (TabItems.tabHeight / TabItems.tabWidth) * 1.1;
|
||||
|
@ -1316,7 +1317,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
left: pos.left
|
||||
}, {
|
||||
duration: 200,
|
||||
easing: "tabviewBounce"
|
||||
easing: "tabviewBounce",
|
||||
complete: function GroupItem_expand_animate_complete() {
|
||||
self._sendToSubscribers("expanded");
|
||||
}
|
||||
})
|
||||
.addClass("overlay");
|
||||
|
||||
|
@ -1361,6 +1365,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
if (this.expanded) {
|
||||
var z = this.getZ();
|
||||
var box = this.getBounds();
|
||||
let self = this;
|
||||
this.expanded.$tray
|
||||
.css({
|
||||
zIndex: z + 1
|
||||
|
@ -1374,8 +1379,9 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
}, {
|
||||
duration: 350,
|
||||
easing: "tabviewBounce",
|
||||
complete: function() {
|
||||
complete: function GroupItem_collapse_animate_complete() {
|
||||
iQ(this).remove();
|
||||
self._sendToSubscribers("collapsed");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1428,7 +1434,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
let options = {dropPos: dropPos,
|
||||
addTab: self._dropSpaceActive && drag.info.item.parent != self,
|
||||
oldDropIndex: oldDropIndex};
|
||||
newDropIndex = self.arrange(options);
|
||||
let newDropIndex = self.arrange(options);
|
||||
// If this is a new drop index, start a timer!
|
||||
if (newDropIndex !== oldDropIndex) {
|
||||
dropIndex = newDropIndex;
|
||||
|
@ -1627,6 +1633,7 @@ let GroupItems = {
|
|||
_arrangePaused: false,
|
||||
_arrangesPending: [],
|
||||
_removingHiddenGroups: false,
|
||||
_delayedModUpdates: [],
|
||||
minGroupHeight: 110,
|
||||
minGroupWidth: 125,
|
||||
|
||||
|
@ -1640,9 +1647,18 @@ let GroupItems = {
|
|||
self._handleAttrModified(xulTab);
|
||||
}
|
||||
|
||||
// make sure any closed tabs are removed from the delay update list
|
||||
function handleClose(xulTab) {
|
||||
let idx = self._delayedModUpdates.indexOf(xulTab);
|
||||
if (idx != -1)
|
||||
self._delayedModUpdates.splice(idx, 1);
|
||||
}
|
||||
|
||||
AllTabs.register("attrModified", handleAttrModified);
|
||||
AllTabs.register("close", handleClose);
|
||||
this._cleanupFunctions.push(function() {
|
||||
AllTabs.unregister("attrModified", handleAttrModified);
|
||||
AllTabs.unregister("close", handleClose);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1697,18 +1713,42 @@ let GroupItems = {
|
|||
// Function: resumeArrange
|
||||
// Resolve bypassed and collected arrange() calls
|
||||
resumeArrange: function GroupItems_resumeArrange() {
|
||||
this._arrangePaused = false;
|
||||
for (let i = 0; i < this._arrangesPending.length; i++) {
|
||||
let g = this._arrangesPending[i];
|
||||
g.groupItem.arrange(g.options);
|
||||
}
|
||||
this._arrangesPending = [];
|
||||
this._arrangePaused = false;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _handleAttrModified
|
||||
// watch for icon changes on app tabs
|
||||
_handleAttrModified: function GroupItems__handleAttrModified(xulTab) {
|
||||
if (!UI.isTabViewVisible()) {
|
||||
if (this._delayedModUpdates.indexOf(xulTab) == -1) {
|
||||
this._delayedModUpdates.push(xulTab);
|
||||
}
|
||||
} else
|
||||
this._updateAppTabIcons(xulTab);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: flushTabUpdates
|
||||
// Update apptab icons based on xulTabs which have been updated
|
||||
// while the TabView hasn't been visible
|
||||
flushAppTabUpdates: function GroupItems_flushAppTabUpdates() {
|
||||
let self = this;
|
||||
this._delayedModUpdates.forEach(function(xulTab) {
|
||||
self._updateAppTabIcons(xulTab);
|
||||
});
|
||||
this._delayedModUpdates = [];
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _updateAppTabIcons
|
||||
// Update images of any apptab icons that point to passed in xultab
|
||||
_updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
|
||||
if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
|
||||
return;
|
||||
|
||||
|
@ -1723,7 +1763,7 @@ let GroupItems = {
|
|||
$icon.attr("src", iconUrl);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: addAppTab
|
||||
|
@ -1910,6 +1950,10 @@ let GroupItems = {
|
|||
if (groupItem == this._activeGroupItem)
|
||||
this._activeGroupItem = null;
|
||||
|
||||
this._arrangesPending = this._arrangesPending.filter(function (pending) {
|
||||
return groupItem != pending.groupItem;
|
||||
});
|
||||
|
||||
UI.updateTabButton();
|
||||
},
|
||||
|
||||
|
@ -2234,21 +2278,15 @@ let GroupItems = {
|
|||
|
||||
// switch to the appropriate tab first.
|
||||
if (gBrowser.selectedTab == tab) {
|
||||
let list = gBrowser.visibleTabs;
|
||||
let listLength = list.length;
|
||||
|
||||
if (listLength > 1) {
|
||||
let index = list.indexOf(tab);
|
||||
if (index == 0 || (index + 1) < listLength)
|
||||
gBrowser.selectTabAtIndex(index + 1);
|
||||
else
|
||||
gBrowser.selectTabAtIndex(index - 1);
|
||||
if (gBrowser.visibleTabs.length > 1) {
|
||||
gBrowser._blurTab(tab);
|
||||
shouldUpdateTabBar = true;
|
||||
} else {
|
||||
shouldShowTabView = true;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
shouldUpdateTabBar = true
|
||||
}
|
||||
|
||||
// remove tab item from a groupItem
|
||||
if (tab._tabViewTabItem.parent)
|
||||
|
|
|
@ -166,7 +166,7 @@ function iQClass(selector, context) {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (typeof selector.selector !== "undefined") {
|
||||
if ("selector" in selector) {
|
||||
this.selector = selector.selector;
|
||||
this.context = selector.context;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ iQClass.prototype = {
|
|||
// pass in just key to retrieve it.
|
||||
data: function iQClass_data(key, value) {
|
||||
let data = null;
|
||||
if (typeof value === "undefined") {
|
||||
if (value === undefined) {
|
||||
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
|
||||
data = this[0].iQData;
|
||||
if (data)
|
||||
|
@ -388,7 +388,7 @@ iQClass.prototype = {
|
|||
// what's already there.
|
||||
html: function iQClass_html(value) {
|
||||
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
|
||||
if (typeof value === "undefined")
|
||||
if (value === undefined)
|
||||
return this[0].innerHTML;
|
||||
|
||||
this[0].innerHTML = value;
|
||||
|
@ -401,7 +401,7 @@ iQClass.prototype = {
|
|||
// what's already there.
|
||||
text: function iQClass_text(value) {
|
||||
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
|
||||
if (typeof value === "undefined") {
|
||||
if (value === undefined) {
|
||||
return this[0].textContent;
|
||||
}
|
||||
|
||||
|
@ -413,7 +413,7 @@ iQClass.prototype = {
|
|||
// Given a value, sets the receiver's value to it; otherwise returns what's already there.
|
||||
val: function iQClass_val(value) {
|
||||
Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)');
|
||||
if (typeof value === "undefined") {
|
||||
if (value === undefined) {
|
||||
return this[0].value;
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ iQClass.prototype = {
|
|||
// Sets or gets an attribute on the element(s).
|
||||
attr: function iQClass_attr(key, value) {
|
||||
Utils.assert(typeof key === 'string', 'string key');
|
||||
if (typeof value === "undefined") {
|
||||
if (value === undefined) {
|
||||
Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
|
||||
return this[0].getAttribute(key);
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ iQClass.prototype = {
|
|||
|
||||
if (typeof a === 'string') {
|
||||
let key = a;
|
||||
if (typeof b === "undefined") {
|
||||
if (b === undefined) {
|
||||
Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)');
|
||||
|
||||
return window.getComputedStyle(this[0], null).getPropertyValue(key);
|
||||
|
@ -596,7 +596,7 @@ iQClass.prototype = {
|
|||
// Function: fadeOut
|
||||
// Animates the receiver to full transparency. Calls callback on completion.
|
||||
fadeOut: function iQClass_fadeOut(callback) {
|
||||
Utils.assert(typeof callback == "function" || typeof callback === "undefined",
|
||||
Utils.assert(typeof callback == "function" || callback === undefined,
|
||||
'does not yet support duration');
|
||||
|
||||
this.animate({
|
||||
|
|
|
@ -774,6 +774,7 @@ Item.prototype = {
|
|||
var self = this;
|
||||
var startMouse;
|
||||
var startSize;
|
||||
var startAspect;
|
||||
|
||||
// ___ mousemove
|
||||
var handleMouseMove = function(e) {
|
||||
|
@ -939,12 +940,9 @@ let Items = {
|
|||
// width value of the child items (`childWidth`) and the number of columns
|
||||
// (`columns`) is returned.
|
||||
arrange: function Items_arrange(items, bounds, options) {
|
||||
if (typeof options == 'undefined')
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
var animate = true;
|
||||
if (typeof options.animate != 'undefined')
|
||||
animate = options.animate;
|
||||
var animate = "animate" in options ? options.animate : true;
|
||||
var immediately = !animate;
|
||||
|
||||
var rects = [];
|
||||
|
|
|
@ -224,7 +224,7 @@ TabMatcher.prototype = {
|
|||
// If TabView is around iterate over all tabs, else get the currently
|
||||
// shown tabs...
|
||||
|
||||
tvWindow = win.TabView.getContentWindow();
|
||||
let tvWindow = win.TabView.getContentWindow();
|
||||
if (tvWindow)
|
||||
allTabs = allTabs.concat( tvWindow.TabItems.getItems() );
|
||||
else
|
||||
|
|
|
@ -185,6 +185,14 @@ let Storage = {
|
|||
return this.readData(win, this.UI_DATA_IDENTIFIER);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveVisibilityData
|
||||
// Saves visibility for the given window.
|
||||
saveVisibilityData: function Storage_saveVisibilityData(win, data) {
|
||||
this._sessionStore.setWindowValue(
|
||||
win, win.TabView.VISIBILITY_IDENTIFIER, data);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveData
|
||||
// Generic routine for saving data to a window.
|
||||
|
|
|
@ -62,7 +62,7 @@ function TabItem(tab, options) {
|
|||
var $div = iQ('<div>')
|
||||
.addClass('tab')
|
||||
.html("<div class='thumb'>" +
|
||||
"<img class='cached-thumb' style='display:none'/><canvas/></div>" +
|
||||
"<img class='cached-thumb' style='display:none'/><canvas moz-opaque='true'/></div>" +
|
||||
"<div class='favicon'><img/></div>" +
|
||||
"<span class='tab-title'> </span>"
|
||||
)
|
||||
|
@ -649,13 +649,15 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
duration: 230,
|
||||
easing: 'fast',
|
||||
complete: function() {
|
||||
TabItems.resumePainting();
|
||||
|
||||
$tabEl
|
||||
.css(orig)
|
||||
.removeClass("front");
|
||||
|
||||
onZoomDone();
|
||||
|
||||
setTimeout(function() {
|
||||
TabItems.resumePainting();
|
||||
|
||||
$tabEl
|
||||
.css(orig)
|
||||
.removeClass("front");
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -785,7 +787,7 @@ let TabItems = {
|
|||
cachedDataCounter: 0, // total number of cached data being displayed.
|
||||
tabsProgressListener: null,
|
||||
_tabsWaitingForUpdate: [],
|
||||
_heartbeatOn: false, // see explanation at startHeartbeat() below
|
||||
_heartbeat: null, // see explanation at startHeartbeat() below
|
||||
_heartbeatTiming: 100, // milliseconds between _checkHeartbeat() calls
|
||||
_lastUpdateTime: Date.now(),
|
||||
_eventListeners: [],
|
||||
|
@ -803,7 +805,8 @@ let TabItems = {
|
|||
|
||||
this.minTabHeight = this.minTabWidth * this.tabHeight / this.tabWidth;
|
||||
|
||||
let $canvas = iQ("<canvas>");
|
||||
let $canvas = iQ("<canvas>")
|
||||
.attr('moz-opaque', true);
|
||||
$canvas.appendTo(iQ("body"));
|
||||
$canvas.hide();
|
||||
this.tempCanvas = $canvas[0];
|
||||
|
@ -897,12 +900,9 @@ let TabItems = {
|
|||
Date.now() - this._lastUpdateTime < this._heartbeatTiming
|
||||
);
|
||||
|
||||
let isCurrentTab = (
|
||||
!UI.isTabViewVisible() &&
|
||||
tab == gBrowser.selectedTab
|
||||
);
|
||||
|
||||
if (shouldDefer && !isCurrentTab) {
|
||||
if (shouldDefer) {
|
||||
if (!this.reconnectingPaused() && !tab._tabViewTabItem._reconnected)
|
||||
this._reconnect(tab._tabViewTabItem);
|
||||
if (this._tabsWaitingForUpdate.indexOf(tab) == -1)
|
||||
this._tabsWaitingForUpdate.push(tab);
|
||||
this.startHeartbeat();
|
||||
|
@ -1052,26 +1052,25 @@ let TabItems = {
|
|||
// Start a new heartbeat if there isn't one already started.
|
||||
// The heartbeat is a chain of setTimeout calls that allows us to spread
|
||||
// out update calls over a period of time.
|
||||
// _heartbeatOn is used to make sure that we don't add multiple
|
||||
// _heartbeat is used to make sure that we don't add multiple
|
||||
// setTimeout chains.
|
||||
startHeartbeat: function TabItems_startHeartbeat() {
|
||||
if (!this._heartbeatOn) {
|
||||
this._heartbeatOn = true;
|
||||
if (!this._heartbeat) {
|
||||
let self = this;
|
||||
setTimeout(function() {
|
||||
this._heartbeat = setTimeout(function() {
|
||||
self._checkHeartbeat();
|
||||
}, this._heartbeatTiming);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: _checkHeartbeat
|
||||
// This periodically checks for tabs waiting to be updated, and calls
|
||||
// _update on them.
|
||||
// Should only be called by startHeartbeat and resumePainting.
|
||||
_checkHeartbeat: function TabItems__checkHeartbeat() {
|
||||
this._heartbeatOn = false;
|
||||
|
||||
this._heartbeat = null;
|
||||
|
||||
if (this.isPaintingPaused())
|
||||
return;
|
||||
|
||||
|
@ -1093,8 +1092,12 @@ let TabItems = {
|
|||
// pausePainting needs to be mirrored with a call to <resumePainting>.
|
||||
pausePainting: function TabItems_pausePainting() {
|
||||
this.paintingPaused++;
|
||||
if (this._heartbeat) {
|
||||
clearTimeout(this._heartbeat);
|
||||
this._heartbeat = null;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// ----------
|
||||
// Function: resumePainting
|
||||
// Undoes a call to <pausePainting>. For instance, if you called
|
||||
|
@ -1291,7 +1294,9 @@ TabCanvas.prototype = {
|
|||
ctx.save();
|
||||
ctx.scale(scaler, scaler);
|
||||
try{
|
||||
ctx.drawWindow(fromWin, fromWin.scrollX, fromWin.scrollY, w/scaler, h/scaler, "#fff");
|
||||
ctx.drawWindow(fromWin, fromWin.scrollX, fromWin.scrollY,
|
||||
w/scaler, h/scaler, "#fff",
|
||||
Ci.nsIDOMCanvasRenderingContext2D.DRAWWINDOW_DO_NOT_FLUSH);
|
||||
} catch(e) {
|
||||
Utils.error('paint', e);
|
||||
}
|
||||
|
|
|
@ -345,6 +345,9 @@ let UI = {
|
|||
|
||||
if (firstTime) {
|
||||
gPrefBranch.setBoolPref("experienced_first_run", true);
|
||||
// ensure that the first run pref is flushed to the file, in case a crash
|
||||
// or force quit happens before the pref gets flushed automatically.
|
||||
Services.prefs.savePrefFile(null);
|
||||
|
||||
let url = gPrefBranch.getCharPref("welcome_url");
|
||||
let newTab = gBrowser.loadOneTab(url, {inBackground: true});
|
||||
|
@ -358,6 +361,10 @@ let UI = {
|
|||
welcomeWidth, welcomeWidth * aspect);
|
||||
newTabItem.setBounds(welcomeBounds, true);
|
||||
GroupItems.setActiveGroupItem(groupItem);
|
||||
|
||||
// Remove the newly created welcome-tab from the tab bar
|
||||
if (!this.isTabViewVisible())
|
||||
GroupItems._updateTabBar();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -495,6 +502,11 @@ let UI = {
|
|||
|
||||
self._resize(true);
|
||||
dispatchEvent(event);
|
||||
|
||||
// Flush pending updates
|
||||
GroupItems.flushAppTabUpdates();
|
||||
|
||||
TabItems.resumePainting();
|
||||
});
|
||||
} else {
|
||||
if (currentTab && currentTab._tabViewTabItem)
|
||||
|
@ -502,9 +514,14 @@ let UI = {
|
|||
|
||||
self.setActiveTab(null);
|
||||
dispatchEvent(event);
|
||||
|
||||
// Flush pending updates
|
||||
GroupItems.flushAppTabUpdates();
|
||||
|
||||
TabItems.resumePainting();
|
||||
}
|
||||
|
||||
TabItems.resumePainting();
|
||||
Storage.saveVisibilityData(gWindow, "true");
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -541,6 +558,8 @@ let UI = {
|
|||
let event = document.createEvent("Events");
|
||||
event.initEvent("tabviewhidden", true, false);
|
||||
dispatchEvent(event);
|
||||
|
||||
Storage.saveVisibilityData(gWindow, "false");
|
||||
},
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -1144,7 +1163,7 @@ let UI = {
|
|||
iQ(window).unbind("mousemove", updateSize);
|
||||
item.container.removeClass("dragRegion");
|
||||
dragOutInfo.stop();
|
||||
box = item.getBounds();
|
||||
let box = item.getBounds();
|
||||
if (box.width > minMinSize && box.height > minMinSize &&
|
||||
(box.width > minSize || box.height > minSize)) {
|
||||
var bounds = item.getBounds();
|
||||
|
@ -1153,7 +1172,7 @@ let UI = {
|
|||
// to that groupItem.
|
||||
var tabs = GroupItems.getOrphanedTabs();
|
||||
var insideTabs = [];
|
||||
for each(tab in tabs) {
|
||||
for each(let tab in tabs) {
|
||||
if (bounds.contains(tab.bounds))
|
||||
insideTabs.push(tab);
|
||||
}
|
||||
|
@ -1180,9 +1199,6 @@ let UI = {
|
|||
// Parameters:
|
||||
// force - true to update even when "unnecessary"; default false
|
||||
_resize: function UI__resize(force) {
|
||||
if (typeof force == "undefined")
|
||||
force = false;
|
||||
|
||||
if (!this._pageBounds)
|
||||
return;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Gavin Sharp <gavin@gavinsharp.com>
|
||||
* Sylvain Pasche <sylvain.pasche@gmail.com>
|
||||
* Drew Willcoxon <adw@mozilla.com>
|
||||
* Margaret Leibovic <margaret.leibovic@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -583,6 +584,32 @@ var tests = [
|
|||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
}
|
||||
},
|
||||
// Test notification when chrome is hidden
|
||||
{ // Test #18
|
||||
run: function () {
|
||||
this.oldSelectedTab = gBrowser.selectedTab;
|
||||
gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
let self = this;
|
||||
loadURI("about:addons", function() {
|
||||
self.notifyObj = new basicNotification();
|
||||
self.notification = showNotification(self.notifyObj);
|
||||
});
|
||||
},
|
||||
onShown: function (popup) {
|
||||
checkPopup(popup, this.notifyObj);
|
||||
is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab");
|
||||
dismissNotification(popup);
|
||||
},
|
||||
onHidden: function (popup) {
|
||||
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
|
||||
this.notification.remove();
|
||||
ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
|
||||
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gBrowser.selectedTab = this.oldSelectedTab;
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
function showNotification(notifyObj) {
|
||||
|
@ -604,8 +631,10 @@ function checkPopup(popup, notificationObj) {
|
|||
is(notifications.length, 1, "only one notification displayed");
|
||||
let notification = notifications[0];
|
||||
let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
|
||||
if (notificationObj.id == "geolocation")
|
||||
if (notificationObj.id == "geolocation") {
|
||||
isnot(icon.boxObject.width, 0, "icon for geo displayed");
|
||||
is(popup.anchorNode.className, "notification-anchor-icon", "notification anchored to icon");
|
||||
}
|
||||
is(notification.getAttribute("label"), notificationObj.message, "message matches");
|
||||
is(notification.id, notificationObj.id + "-notification", "id matches");
|
||||
if (notificationObj.mainAction) {
|
||||
|
|
|
@ -137,6 +137,64 @@ var gTestSteps = [
|
|||
}, true);
|
||||
tab.linkedBrowser.loadURI('about:robots');
|
||||
},
|
||||
function() {
|
||||
info("Running step 9 - enter private browsing mode, without keeping session");
|
||||
let ps = Services.prefs;
|
||||
ps.setBoolPref("browser.privatebrowsing.keep_current_session", false);
|
||||
ps.setBoolPref("browser.tabs.warnOnClose", false);
|
||||
|
||||
Services.obs.addObserver(function(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, "private-browsing-transition-complete");
|
||||
|
||||
for (let i = 0; i < gBrowser.tabs.length; i++)
|
||||
waitForRestoredTab(gBrowser.tabs[i]);
|
||||
}, "private-browsing-transition-complete", false);
|
||||
|
||||
gPrivateBrowsing.privateBrowsingEnabled = true;
|
||||
},
|
||||
function() {
|
||||
info("Running step 10 - open tabs in private browsing mode");
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let tab = gBrowser.addTab();
|
||||
loadTab(tab, TEST_URL_BASES[0] + (++gTabCounter));
|
||||
}
|
||||
},
|
||||
function() {
|
||||
info("Running step 11 - close tabs in private browsing mode");
|
||||
gBrowser.removeCurrentTab();
|
||||
ensure_opentabs_match_db(nextStep);
|
||||
},
|
||||
function() {
|
||||
info("Running step 12 - leave private browsing mode");
|
||||
|
||||
Services.obs.addObserver(function(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, "private-browsing-transition-complete");
|
||||
|
||||
let ps = Services.prefs;
|
||||
try {
|
||||
ps.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
} catch (ex) {}
|
||||
try {
|
||||
ps.clearUserPref("browser.tabs.warnOnClose");
|
||||
} catch (ex) {}
|
||||
|
||||
for (let i = 1; i < gBrowser.tabs.length; i++)
|
||||
waitForRestoredTab(gBrowser.tabs[i]);
|
||||
|
||||
}, "private-browsing-transition-complete", false);
|
||||
|
||||
gPrivateBrowsing.privateBrowsingEnabled = false;
|
||||
},
|
||||
function() {
|
||||
info("Running step 13 - close all tabs");
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
info("Removing tab: " + gBrowser.tabs[0].linkedBrowser.currentURI.spec);
|
||||
gBrowser.selectTabAtIndex(0);
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
ensure_opentabs_match_db(nextStep);
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
|
@ -148,7 +206,7 @@ function test() {
|
|||
|
||||
function loadTab(tab, url) {
|
||||
// Because adding visits is async, we will not be notified immediately.
|
||||
let visited = false;
|
||||
let visited = gPrivateBrowsing.privateBrowsingEnabled;
|
||||
let loaded = false;
|
||||
|
||||
function maybeCheckResults() {
|
||||
|
@ -163,22 +221,37 @@ function loadTab(tab, url) {
|
|||
maybeCheckResults();
|
||||
}, true);
|
||||
|
||||
Services.obs.addObserver(
|
||||
function (aSubject, aTopic, aData) {
|
||||
if (url != aSubject.QueryInterface(Ci.nsIURI).spec)
|
||||
return;
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
visited = true;
|
||||
maybeCheckResults();
|
||||
},
|
||||
"uri-visit-saved",
|
||||
false
|
||||
);
|
||||
if (!visited) {
|
||||
Services.obs.addObserver(
|
||||
function (aSubject, aTopic, aData) {
|
||||
if (url != aSubject.QueryInterface(Ci.nsIURI).spec)
|
||||
return;
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
visited = true;
|
||||
maybeCheckResults();
|
||||
},
|
||||
"uri-visit-saved",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
gTabWaitCount++;
|
||||
info("Loading page: " + url);
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
}
|
||||
|
||||
function waitForRestoredTab(tab) {
|
||||
gTabWaitCount++;
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function () {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
if (--gTabWaitCount == 0) {
|
||||
ensure_opentabs_match_db(nextStep);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
||||
function nextStep() {
|
||||
if (gTestSteps.length == 0) {
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
|
|
|
@ -57,7 +57,6 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug589324.js \
|
||||
browser_tabview_bug590606.js \
|
||||
browser_tabview_bug591706.js \
|
||||
browser_tabview_bug594176.js \
|
||||
browser_tabview_bug595191.js \
|
||||
browser_tabview_bug595436.js \
|
||||
browser_tabview_bug595518.js \
|
||||
|
@ -77,13 +76,18 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug606657.js \
|
||||
browser_tabview_bug606905.js \
|
||||
browser_tabview_bug608037.js \
|
||||
browser_tabview_bug608184.js \
|
||||
browser_tabview_bug608158.js \
|
||||
browser_tabview_bug610242.js \
|
||||
browser_tabview_bug616967.js \
|
||||
browser_tabview_bug618828.js \
|
||||
browser_tabview_bug619937.js \
|
||||
browser_tabview_bug622835.js \
|
||||
browser_tabview_bug624265.js \
|
||||
browser_tabview_bug624953.js \
|
||||
browser_tabview_dragdrop.js \
|
||||
browser_tabview_exit_button.js \
|
||||
browser_tabview_expander.js \
|
||||
browser_tabview_group.js \
|
||||
browser_tabview_launch.js \
|
||||
browser_tabview_multiwindow_search.js \
|
||||
|
|
|
@ -109,7 +109,7 @@ function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
|
|||
|
||||
EventUtils.synthesizeMouse(
|
||||
tabItem.container, 1, 1, { type: "mousedown" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
let event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 1, null, dataTransfer);
|
||||
|
|
|
@ -67,7 +67,7 @@ function onTabViewWindowLoaded() {
|
|||
|
||||
gBrowser.tabContainer.addEventListener("TabMove", onTabMove, false);
|
||||
|
||||
groupItem = contentWindow.GroupItems.getActiveGroupItem();
|
||||
let groupItem = contentWindow.GroupItems.getActiveGroupItem();
|
||||
|
||||
// move 3 > 0 (and therefore 0 > 1, 1 > 2, 2 > 3)
|
||||
groupItem._children.splice(0, 0, groupItem._children.splice(3, 1)[0]);
|
||||
|
|
|
@ -82,7 +82,7 @@ function testGroupSwitch(contentWindow, groupItemOne, groupItemTwo) {
|
|||
"The currently selected tab should be the only tab in the groupItemTwo");
|
||||
|
||||
// switch to groupItemOne
|
||||
tabItem = contentWindow.GroupItems.getNextGroupItemTab(false);
|
||||
let tabItem = contentWindow.GroupItems.getNextGroupItemTab(false);
|
||||
if (tabItem)
|
||||
gBrowser.selectedTab = tabItem.tab;
|
||||
is(gBrowser.selectedTab, groupItemOne.getChild(0).tab,
|
||||
|
|
|
@ -91,5 +91,5 @@ function toggleTabViewTest(contentWindow) {
|
|||
}
|
||||
contentWindow.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
// Use keyboard shortcut to toggle back to browser view
|
||||
EventUtils.synthesizeKey("e", { accelKey: true });
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true });
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ function onTabViewWindowLoaded() {
|
|||
// verify that the keyboard combo works (this is the crux of bug 595518)
|
||||
// Prepare the key combo
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
EventUtils.synthesizeKey("e", { accelKey: true }, contentWindow);
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, contentWindow);
|
||||
}
|
||||
|
||||
let onTabViewShown = function() {
|
||||
|
|
|
@ -75,7 +75,7 @@ function onTabViewWindowLoaded() {
|
|||
// the appropriate group would get selected when the key
|
||||
// combination is pressed
|
||||
executeSoon(function() {
|
||||
EventUtils.synthesizeKey("e", {accelKey : true}, contentWindow);
|
||||
EventUtils.synthesizeKey("e", {accelKey : true, shiftKey: true}, contentWindow);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is a test for bug 608184.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let origTab = gBrowser.visibleTabs[0];
|
||||
let newTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = newTab;
|
||||
let relatedTab = gBrowser.addTab("about:blank", { ownerTab: newTab });
|
||||
|
||||
// init the frame, move the owner tab to a new group and close the related
|
||||
// tab.
|
||||
TabView._initFrame(function() {
|
||||
let newTabGroupItemId = newTab._tabViewTabItem.parent.id;
|
||||
|
||||
is(relatedTab.owner, newTab, "The related tab's owner is the right tab");
|
||||
|
||||
// move current tab to a new group
|
||||
TabView.moveTabTo(newTab, null);
|
||||
|
||||
// close the related tab
|
||||
gBrowser.removeTab(relatedTab);
|
||||
|
||||
is(gBrowser.visibleTabs.length, 1, "The number of visible tabs is 1");
|
||||
is(gBrowser.visibleTabs[0], origTab,
|
||||
"The original tab is the only visible tab");
|
||||
isnot(newTab._tabViewTabItem.parent.id, newTabGroupItemId,
|
||||
"The moved tab item has a new group id");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(newTab);
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is bug 594176 test.
|
||||
* The Original Code is a test for bug 616967.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
|
@ -19,7 +19,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
* Tim Taubert <tim.taubert@gmx.de>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -36,30 +36,19 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
let [origTab] = gBrowser.visibleTabs;
|
||||
ok(!origTab.pinned, "The original tab is not pinned");
|
||||
|
||||
let pinnedTab = gBrowser.addTab();
|
||||
gBrowser.pinTab(pinnedTab);
|
||||
ok(pinnedTab.pinned, "The new tab is pinned");
|
||||
waitForExplicitFinish();
|
||||
|
||||
popup(origTab);
|
||||
ok(!document.getElementById("context_tabViewMenu").disabled,
|
||||
"The tab view menu is enabled for normal tab");
|
||||
let branch = Services.prefs.getBranch('browser.panorama.');
|
||||
branch.setBoolPref('experienced_first_run', false);
|
||||
|
||||
newWindowWithTabView(function (win) {
|
||||
is(win.gBrowser.visibleTabs.length, 1, 'There should be one visible tab, only');
|
||||
|
||||
popup(pinnedTab);
|
||||
ok(document.getElementById("context_tabViewMenu").disabled,
|
||||
"The tab view menu is disabled for pinned tab");
|
||||
win.TabView._initFrame(function () {
|
||||
is(win.gBrowser.visibleTabs.length, 1, 'There should be one visible tab, only');
|
||||
|
||||
gBrowser.unpinTab(pinnedTab);
|
||||
popup(pinnedTab);
|
||||
ok(!document.getElementById("context_tabViewMenu").disabled,
|
||||
"The tab view menu is enabled for unpinned tab");
|
||||
|
||||
gBrowser.removeTab(pinnedTab);
|
||||
}
|
||||
|
||||
function popup(tab) {
|
||||
document.popupNode = tab;
|
||||
TabContextMenu.updateContextMenu(document.getElementById("tabContextMenu"));
|
||||
win.close();
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is a test for bug 622835.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tim Taubert <tim.taubert@gmx.de>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
newWindowWithTabView(onTabViewShown);
|
||||
}
|
||||
|
||||
function onTabViewShown(win) {
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
|
||||
let getTransformValue = function (childIndex) {
|
||||
let tabItem = groupItem.getChildren()[childIndex];
|
||||
let style = contentWindow.getComputedStyle(tabItem.container);
|
||||
return style.getPropertyValue('-moz-transform');
|
||||
}
|
||||
|
||||
let finishTest = function () {
|
||||
win.addEventListener('tabviewhidden', function () {
|
||||
win.removeEventListener('tabviewhidden', arguments.callee, false);
|
||||
win.close();
|
||||
finish();
|
||||
}, false);
|
||||
win.TabView.hide();
|
||||
}
|
||||
|
||||
// do not let the group arrange itself
|
||||
contentWindow.GroupItems.pauseArrange();
|
||||
|
||||
// let's create a groupItem small enough to get stacked
|
||||
let groupItem = new contentWindow.GroupItem([], {
|
||||
immediately: true,
|
||||
bounds: {left: 20, top: 20, width: 100, height: 100}
|
||||
});
|
||||
|
||||
contentWindow.GroupItems.setActiveGroupItem(groupItem);
|
||||
|
||||
// we need seven tabs at least to reproduce this
|
||||
for (var i=0; i<7; i++)
|
||||
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
|
||||
|
||||
// finally let group arrange
|
||||
contentWindow.GroupItems.resumeArrange();
|
||||
|
||||
ok(getTransformValue(5) != getTransformValue(4), 'the 6th child must peek out of its position under the 5th');
|
||||
is(getTransformValue(6), getTransformValue(5), 'the 7th child must not peek out of its position under the 6th');
|
||||
|
||||
finishTest();
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tabview bug 624953 test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tim Taubert <tim.taubert@gmx.de>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let finishTest = function (groupItem) {
|
||||
groupItem.addSubscriber(groupItem, 'groupHidden', function () {
|
||||
groupItem.removeSubscriber(groupItem, 'groupHidden');
|
||||
groupItem.closeHidden();
|
||||
hideTabView(finish);
|
||||
});
|
||||
|
||||
groupItem.closeAll();
|
||||
}
|
||||
|
||||
showTabView(function () {
|
||||
let cw = TabView.getContentWindow();
|
||||
|
||||
let bounds = new cw.Rect(20, 20, 150, 200);
|
||||
let groupItem = new cw.GroupItem([], {bounds: bounds, immediately: true});
|
||||
cw.GroupItems.setActiveGroupItem(groupItem);
|
||||
|
||||
for (let i=0; i<4; i++)
|
||||
gBrowser.loadOneTab('about:blank', {inBackground: true});
|
||||
|
||||
ok(!groupItem._isStacked, 'groupItem is not stacked');
|
||||
cw.GroupItems.pauseArrange();
|
||||
|
||||
groupItem.setSize(150, 150);
|
||||
groupItem.setUserSize();
|
||||
ok(!groupItem._isStacked, 'groupItem is still not stacked');
|
||||
|
||||
cw.GroupItems.resumeArrange();
|
||||
ok(groupItem._isStacked, 'groupItem is now stacked');
|
||||
|
||||
finishTest(groupItem);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Panorama expander test.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(2);
|
||||
newWindowWithTabView(onTabViewWindowLoaded);
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded(win) {
|
||||
ok(win.TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = win.document.getElementById("tab-view").contentWindow;
|
||||
let [originalTab] = win.gBrowser.visibleTabs;
|
||||
let currentGroup = contentWindow.GroupItems.getActiveGroupItem();
|
||||
|
||||
// let's create a group small enough to get stacked
|
||||
let group = new contentWindow.GroupItem([], {
|
||||
immediately: true,
|
||||
bounds: {left: 20, top: 300, width: 300, height: 300}
|
||||
});
|
||||
|
||||
let expander = contentWindow.iQ(group.container).find(".stackExpander");
|
||||
ok("length" in expander && expander.length == 1, "The group has an expander.");
|
||||
|
||||
// procreate!
|
||||
contentWindow.GroupItems.setActiveGroupItem(group);
|
||||
for (var i=0; i<7; i++) {
|
||||
win.gBrowser.loadOneTab('about:blank#' + i, {inBackground: true});
|
||||
}
|
||||
let children = group.getChildren();
|
||||
|
||||
// Wait until they all update because, once updated, they will notice that they
|
||||
// don't have favicons and this will change their styling at some unknown time.
|
||||
afterAllTabItemsUpdated(function() {
|
||||
|
||||
ok(!group.shouldStack(group._children.length), "The group should not stack.");
|
||||
is(expander[0].style.display, "none", "The expander is hidden.");
|
||||
|
||||
// now resize the group down.
|
||||
group.setSize(100, 100, true);
|
||||
|
||||
ok(group.shouldStack(group._children.length), "The group should stack.");
|
||||
isnot(expander[0].style.display, "none", "The expander is now visible!");
|
||||
let expanderBounds = expander.bounds();
|
||||
ok(group.getBounds().contains(expanderBounds), "The expander lies in the group.");
|
||||
let stackCenter = children[0].getBounds().center();
|
||||
ok(stackCenter.y < expanderBounds.center().y, "The expander is below the stack.");
|
||||
|
||||
// STAGE 1:
|
||||
// Here, we just expand the group, click elsewhere, and make sure
|
||||
// it collapsed.
|
||||
let stage1expanded = function() {
|
||||
group.removeSubscriber("test stage 1", "expanded", stage1expanded);
|
||||
|
||||
ok(group.expanded, "The group is now expanded.");
|
||||
is(expander[0].style.display, "none", "The expander is hidden!");
|
||||
|
||||
let overlay = contentWindow.document.getElementById("expandedTray");
|
||||
ok(overlay, "The expanded tray exists.");
|
||||
let $overlay = contentWindow.iQ(overlay);
|
||||
|
||||
group.addSubscriber("test stage 1", "collapsed", stage1collapsed);
|
||||
// null type means "click", for some reason...
|
||||
EventUtils.synthesizeMouse(contentWindow.document.body, 10, $overlay.bounds().bottom + 5,
|
||||
{type: null}, contentWindow);
|
||||
};
|
||||
|
||||
let stage1collapsed = function() {
|
||||
group.removeSubscriber("test stage 1", "collapsed", stage1collapsed);
|
||||
ok(!group.expanded, "The group is no longer expanded.");
|
||||
isnot(expander[0].style.display, "none", "The expander is visible!");
|
||||
let expanderBounds = expander.bounds();
|
||||
ok(group.getBounds().contains(expanderBounds), "The expander still lies in the group.");
|
||||
let stackCenter = children[0].getBounds().center();
|
||||
ok(stackCenter.y < expanderBounds.center().y, "The expander is below the stack.");
|
||||
|
||||
// now, try opening it up again.
|
||||
group.addSubscriber("test stage 2", "expanded", stage2expanded);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, expander[0], contentWindow);
|
||||
};
|
||||
|
||||
// STAGE 2:
|
||||
// Now make sure every child of the group shows up within this "tray", and
|
||||
// click on one of them and make sure we go into the tab and the tray collapses.
|
||||
let stage2expanded = function() {
|
||||
group.removeSubscriber("test stage 2", "expanded", stage2expanded);
|
||||
|
||||
ok(group.expanded, "The group is now expanded.");
|
||||
is(expander[0].style.display, "none", "The expander is hidden!");
|
||||
|
||||
let overlay = contentWindow.document.getElementById("expandedTray");
|
||||
ok(overlay, "The expanded tray exists.");
|
||||
let $overlay = contentWindow.iQ(overlay);
|
||||
let overlayBounds = $overlay.bounds();
|
||||
|
||||
children.forEach(function(child, i) {
|
||||
ok(overlayBounds.contains(child.getBounds()), "Child " + i + " is in the overlay");
|
||||
});
|
||||
|
||||
win.addEventListener("tabviewhidden", stage2hidden, false);
|
||||
// again, null type means "click", for some reason...
|
||||
EventUtils.synthesizeMouse(children[0].container, 2, 2, {type: null}, contentWindow);
|
||||
};
|
||||
|
||||
let stage2hidden = function() {
|
||||
win.removeEventListener("tabviewhidden", stage2hidden, false);
|
||||
|
||||
is(win.gBrowser.selectedTab, children[0].tab, "We clicked on the first child.");
|
||||
|
||||
win.addEventListener("tabviewshown", stage2shown, false);
|
||||
win.TabView.toggle();
|
||||
};
|
||||
|
||||
let stage2shown = function() {
|
||||
win.removeEventListener("tabviewshown", stage2shown, false);
|
||||
ok(!group.expanded, "The group is not expanded.");
|
||||
isnot(expander[0].style.display, "none", "The expander is visible!");
|
||||
let expanderBounds = expander.bounds();
|
||||
ok(group.getBounds().contains(expanderBounds), "The expander still lies in the group.");
|
||||
let stackCenter = children[0].getBounds().center();
|
||||
ok(stackCenter.y < expanderBounds.center().y, "The expander is below the stack.");
|
||||
|
||||
// In preparation for Stage 3, find that original tab and make it the active tab.
|
||||
let originalTabItem = originalTab._tabViewTabItem;
|
||||
contentWindow.UI.setActiveTab(originalTabItem);
|
||||
|
||||
// okay, expand this group one last time
|
||||
group.addSubscriber("test stage 3", "expanded", stage3expanded);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, expander[0], contentWindow);
|
||||
}
|
||||
|
||||
// STAGE 3:
|
||||
// Activate another tab not in this group, expand our stacked group, but then
|
||||
// enter Panorama (i.e., zoom into this other group), and make sure we can go to
|
||||
// it and that the tray gets collapsed.
|
||||
let stage3expanded = function() {
|
||||
group.removeSubscriber("test stage 3", "expanded", stage3expanded);
|
||||
|
||||
ok(group.expanded, "The group is now expanded.");
|
||||
is(expander[0].style.display, "none", "The expander is hidden!");
|
||||
let overlay = contentWindow.document.getElementById("expandedTray");
|
||||
ok(overlay, "The expanded tray exists.");
|
||||
|
||||
let activeTab = contentWindow.UI.getActiveTab();
|
||||
ok(activeTab, "There is an active tab.");
|
||||
let originalTabItem = originalTab._tabViewTabItem;
|
||||
|
||||
isnot(activeTab, originalTabItem, "But it's not what it was a moment ago.");
|
||||
let someChildIsActive = group.getChildren().some(function(child)
|
||||
child == activeTab);
|
||||
ok(someChildIsActive, "Now one of the children in the group is active.");
|
||||
|
||||
// now activate Panorama...
|
||||
win.addEventListener("tabviewhidden", stage3hidden, false);
|
||||
win.TabView.toggle();
|
||||
};
|
||||
|
||||
let stage3hidden = function() {
|
||||
win.removeEventListener("tabviewhidden", stage3hidden, false);
|
||||
|
||||
isnot(win.gBrowser.selectedTab, originalTab, "We did not enter the original tab.");
|
||||
|
||||
let someChildIsSelected = group.getChildren().some(function(child)
|
||||
child.tab == win.gBrowser.selectedTab);
|
||||
ok(someChildIsSelected, "Instead we're in one of the stack's children.");
|
||||
|
||||
win.addEventListener("tabviewshown", stage3shown, false);
|
||||
win.TabView.toggle();
|
||||
};
|
||||
|
||||
let stage3shown = function() {
|
||||
win.removeEventListener("tabviewshown", stage3shown, false);
|
||||
|
||||
let overlay = contentWindow.document.getElementById("expandedTray");
|
||||
ok(!group.expanded, "The group is no longer expanded.");
|
||||
isnot(expander[0].style.display, "none", "The expander is visible!");
|
||||
|
||||
win.close();
|
||||
finish();
|
||||
}
|
||||
|
||||
// get the ball rolling
|
||||
group.addSubscriber("test stage 1", "expanded", stage1expanded);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, expander[0], contentWindow);
|
||||
}, win);
|
||||
}
|
|
@ -40,7 +40,7 @@ let tabViewShownCount = 0;
|
|||
// ----------
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
||||
// verify initial state
|
||||
ok(!TabView.isVisible(), "Tab View starts hidden");
|
||||
|
||||
|
@ -54,7 +54,7 @@ function test() {
|
|||
// ----------
|
||||
function onTabViewLoadedAndShown() {
|
||||
window.removeEventListener("tabviewshown", onTabViewLoadedAndShown, false);
|
||||
|
||||
|
||||
// Evidently sometimes isVisible (which is based on the selectedIndex of the
|
||||
// tabview deck) isn't updated immediately when called from button.doCommand,
|
||||
// so we add a little timeout here to get outside of the doCommand call.
|
||||
|
@ -66,7 +66,7 @@ function onTabViewLoadedAndShown() {
|
|||
if (deck.selectedIndex == 1) {
|
||||
ok(TabView.isVisible(), "Tab View is visible. Count: " + tabViewShownCount);
|
||||
tabViewShownCount++;
|
||||
|
||||
|
||||
// kick off the series
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
@ -75,7 +75,7 @@ function onTabViewLoadedAndShown() {
|
|||
setTimeout(waitForSwitch, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setTimeout(waitForSwitch, 1);
|
||||
}
|
||||
|
||||
|
@ -87,17 +87,17 @@ function onTabViewShown() {
|
|||
TabView.toggle();
|
||||
}
|
||||
|
||||
// ----------
|
||||
// ----------
|
||||
function onTabViewHidden() {
|
||||
ok(!TabView.isVisible(), "Tab View is hidden. Count: " + tabViewShownCount);
|
||||
|
||||
if (tabViewShownCount == 1) {
|
||||
document.getElementById("menu_tabview").doCommand();
|
||||
} else if (tabViewShownCount == 2) {
|
||||
EventUtils.synthesizeKey("e", { accelKey: true });
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true });
|
||||
} else if (tabViewShownCount == 3) {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
|
|||
|
||||
EventUtils.synthesizeMouse(
|
||||
tabItem.container, 1, 1, { type: "mousedown" }, contentWindow);
|
||||
event = contentWindow.document.createEvent("DragEvents");
|
||||
let event = contentWindow.document.createEvent("DragEvents");
|
||||
event.initDragEvent(
|
||||
"dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
|
||||
false, false, false, false, 1, null, dataTransfer);
|
||||
|
|
|
@ -105,3 +105,59 @@ function afterAllTabsLoaded(callback, win) {
|
|||
if (!stillToLoad)
|
||||
callback();
|
||||
}
|
||||
|
||||
// ----------
|
||||
function showTabView(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
if (win.TabView.isVisible()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
whenTabViewIsShown(callback, win);
|
||||
win.TabView.show();
|
||||
}
|
||||
|
||||
// ----------
|
||||
function hideTabView(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
if (!win.TabView.isVisible()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
whenTabViewIsHidden(callback, win);
|
||||
win.TabView.hide();
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenTabViewIsHidden(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
if (!win.TabView.isVisible()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
win.addEventListener('tabviewhidden', function () {
|
||||
win.removeEventListener('tabviewhidden', arguments.callee, false);
|
||||
callback();
|
||||
}, false);
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenTabViewIsShown(callback, win) {
|
||||
win = win || window;
|
||||
|
||||
if (win.TabView.isVisible()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
win.addEventListener('tabviewshown', function () {
|
||||
win.removeEventListener('tabviewshown', arguments.callee, false);
|
||||
callback();
|
||||
}, false);
|
||||
}
|
||||
|
|
|
@ -121,10 +121,9 @@ function test()
|
|||
// Select all the bookmarks
|
||||
synthesizeKey("a", {accelKey:true}, aWin);
|
||||
|
||||
// If we can, start shark
|
||||
// If we can, start profiling
|
||||
try {
|
||||
connectShark();
|
||||
startShark();
|
||||
startProfiling();
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
|
@ -133,10 +132,9 @@ function test()
|
|||
synthesizeKey("VK_BACK_SPACE", {}, aWin);
|
||||
let end = Date.now();
|
||||
|
||||
// Stop shark, if we can
|
||||
// Stop profiling, if we can
|
||||
try {
|
||||
stopShark();
|
||||
disconnectionShark();
|
||||
stopProfiling();
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
|
|
|
@ -118,7 +118,8 @@ const CAPABILITIES = [
|
|||
const INTERNAL_KEYS = ["_tabStillLoading", "_hosts", "_formDataSaved"];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
const TAB_EVENTS = ["TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide"];
|
||||
const TAB_EVENTS = ["TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide",
|
||||
"TabPinned", "TabUnpinned"];
|
||||
|
||||
#ifndef XP_WIN
|
||||
#define BROKEN_WM_Z_ORDER
|
||||
|
@ -201,9 +202,6 @@ SessionStoreService.prototype = {
|
|||
// whether we are in private browsing mode
|
||||
_inPrivateBrowsing: false,
|
||||
|
||||
// whether we clearing history on shutdown
|
||||
_clearingOnShutdown: false,
|
||||
|
||||
// whether the last window was closed and should be restored
|
||||
_restoreLastWindow: false,
|
||||
|
||||
|
@ -454,7 +452,13 @@ SessionStoreService.prototype = {
|
|||
case "quit-application":
|
||||
if (aData == "restart") {
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
|
||||
this._clearingOnShutdown = false;
|
||||
// The browser:purge-session-history notification fires after the
|
||||
// quit-application notification so unregister the
|
||||
// browser:purge-session-history notification to prevent clearing
|
||||
// session data on disk on a restart. It is also unnecessary to
|
||||
// perform any other sanitization processing on a restart as the
|
||||
// browser is about to exit anyway.
|
||||
Services.obs.removeObserver(this, "browser:purge-session-history");
|
||||
}
|
||||
else if (this._resume_session_once_on_shutdown != null) {
|
||||
// if the sessionstore.resume_session_once preference was changed by
|
||||
|
@ -469,6 +473,12 @@ SessionStoreService.prototype = {
|
|||
this._uninit();
|
||||
break;
|
||||
case "browser:purge-session-history": // catch sanitization
|
||||
this._clearDisk();
|
||||
// If the browser is shutting down, simply return after clearing the
|
||||
// session data on disk as this notification fires after the
|
||||
// quit-application notification so the browser is about to exit.
|
||||
if (this._loadState == STATE_QUITTING)
|
||||
return;
|
||||
let openWindows = {};
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
Array.forEach(aWindow.gBrowser.tabs, function(aTab) {
|
||||
|
@ -487,7 +497,6 @@ SessionStoreService.prototype = {
|
|||
}
|
||||
// also clear all data about closed windows
|
||||
this._closedWindows = [];
|
||||
this._clearDisk();
|
||||
// give the tabbrowsers a chance to clear their histories first
|
||||
var win = this._getMostRecentBrowserWindow();
|
||||
if (win)
|
||||
|
@ -497,8 +506,6 @@ SessionStoreService.prototype = {
|
|||
// Delete the private browsing backed up state, if any
|
||||
if ("_stateBackup" in this)
|
||||
delete this._stateBackup;
|
||||
if (this._loadState == STATE_QUITTING)
|
||||
this._clearingOnShutdown = true;
|
||||
break;
|
||||
case "browser:purge-domain-data":
|
||||
// does a session history entry contain a url for the given domain?
|
||||
|
@ -677,6 +684,10 @@ SessionStoreService.prototype = {
|
|||
case "TabHide":
|
||||
this.onTabHide(aEvent.originalTarget);
|
||||
break;
|
||||
case "TabPinned":
|
||||
case "TabUnpinned":
|
||||
this.saveStateDelayed(win);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -3368,9 +3379,6 @@ SessionStoreService.prototype = {
|
|||
* @returns bool
|
||||
*/
|
||||
_doResumeSession: function sss_doResumeSession() {
|
||||
if (this._clearingOnShutdown)
|
||||
return false;
|
||||
|
||||
return this._prefBranch.getIntPref("startup.page") == 3 ||
|
||||
this._prefBranch.getBoolPref("sessionstore.resume_session_once");
|
||||
},
|
||||
|
|
|
@ -131,6 +131,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_597315_c1.html \
|
||||
browser_597315_c2.html \
|
||||
browser_600545.js \
|
||||
browser_601955.js \
|
||||
browser_607016.js \
|
||||
browser_615394-SSWindowState_events.js \
|
||||
browser_618151.js \
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
var startup_info = Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(Components.interfaces.nsIAppStartup_MOZILLA_2_0).getStartupInfo();
|
||||
// No .process info on mac
|
||||
is(startup_info.process <= startup_info.main, true, "process created before main is run " + uneval(startup_info));
|
||||
ok(startup_info.process <= startup_info.main, "process created before main is run " + uneval(startup_info));
|
||||
|
||||
// on linux firstPaint can happen after everything is loaded (especially with remote X)
|
||||
if (startup_info.firstPaint)
|
||||
is(startup_info.main <= startup_info.firstPaint, true, "main ran before first paint " + uneval(startup_info));
|
||||
ok(startup_info.main <= startup_info.firstPaint, "main ran before first paint " + uneval(startup_info));
|
||||
|
||||
is(startup_info.main < startup_info.sessionRestored, true, "Session restored after main " + uneval(startup_info));
|
||||
finish();
|
||||
ok(startup_info.main < startup_info.sessionRestored, "Session restored after main " + uneval(startup_info));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is sessionstore test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mehdi Mulani <mmmulani@uwaterloo.ca>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****/
|
||||
|
||||
// This tests that pinning/unpinning a tab, on its own, eventually triggers a
|
||||
// session store.
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
// We speed up the interval between session saves to ensure that the test
|
||||
// runs quickly.
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 2000);
|
||||
|
||||
// Loading a tab causes a save state and this is meant to catch that event.
|
||||
waitForSaveState(testBug601955_1);
|
||||
|
||||
// Assumption: Only one window is open and it has one tab open.
|
||||
gBrowser.addTab("about:mozilla");
|
||||
}
|
||||
|
||||
function testBug601955_1() {
|
||||
// Because pinned tabs are at the front of |gBrowser.tabs|, pinning tabs
|
||||
// re-arranges the |tabs| array.
|
||||
ok(!gBrowser.tabs[0].pinned, "first tab should not be pinned yet");
|
||||
ok(!gBrowser.tabs[1].pinned, "second tab should not be pinned yet");
|
||||
|
||||
waitForSaveState(testBug601955_2);
|
||||
gBrowser.pinTab(gBrowser.tabs[0]);
|
||||
}
|
||||
|
||||
function testBug601955_2() {
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
ok(state.windows[0].tabs[0].pinned, "first tab should be pinned by now");
|
||||
ok(!state.windows[0].tabs[1].pinned, "second tab should still not be pinned");
|
||||
|
||||
waitForSaveState(testBug601955_3);
|
||||
gBrowser.unpinTab(window.gBrowser.tabs[0]);
|
||||
}
|
||||
|
||||
function testBug601955_3() {
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
ok(!state.windows[0].tabs[0].pinned, "first tab should not be pinned");
|
||||
ok(!state.windows[0].tabs[1].pinned, "second tab should not be pinned");
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
function done() {
|
||||
gBrowser.removeTab(window.gBrowser.tabs[0]);
|
||||
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
|
||||
executeSoon(finish);
|
||||
}
|
|
@ -90,6 +90,16 @@ function waitForBrowserState(aState, aSetStateCallback) {
|
|||
SS_SVC.setBrowserState(JSON.stringify(aState));
|
||||
}
|
||||
|
||||
// waitForSaveState waits for a state write but not necessarily for the state to
|
||||
// turn dirty.
|
||||
function waitForSaveState(aSaveStateCallback) {
|
||||
let topic = "sessionstore-state-write";
|
||||
Services.obs.addObserver(function() {
|
||||
Services.obs.removeObserver(arguments.callee, topic, false);
|
||||
executeSoon(aSaveStateCallback);
|
||||
}, topic, false);
|
||||
};
|
||||
|
||||
function r() {
|
||||
return Date.now() + Math.random();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,6 @@ new.password.acceptButton = Update Password
|
|||
new.password.status.incorrect = Password incorrect, please try again.
|
||||
|
||||
new.synckey.title = Update Sync Key
|
||||
new.synckey.introText = Your Sync Key has changed, please enter your new Sync Key
|
||||
new.synckey2.introText = Your Sync Key was changed using another device, please enter your updated Sync Key.
|
||||
new.synckey.acceptButton = Update Sync Key
|
||||
new.synckey.status.incorrect = Sync Key incorrect, please try again.
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
<!ENTITY existingSyncKey.description "You can get a copy of your Sync Key by going to &syncBrand.shortName.label; Options on your other device, and selecting "My Sync Key" under "Manage Account".">
|
||||
<!ENTITY verifying.label "Verifying…">
|
||||
<!ENTITY resetPassword.label "Reset Password">
|
||||
<!ENTITY lostSyncKey.label "I have lost my Sync Key">
|
||||
<!ENTITY resetSyncKey.label "I have lost my other device.">
|
||||
|
||||
<!-- Sync Options -->
|
||||
<!ENTITY setup.optionsPage.title "Sync Options">
|
||||
|
|
|
@ -55,7 +55,7 @@ treechildren::-moz-tree-image(noicon) {
|
|||
}
|
||||
|
||||
treechildren::-moz-tree-image(noicon) {
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
treechildren::-moz-tree-image(container, noicon) {
|
||||
list-style-image: url("chrome://browser/skin/aboutSessionRestore-window-icon.png");
|
||||
|
|
|
@ -196,8 +196,7 @@ menuitem.bookmark-item {
|
|||
|
||||
/* Bookmark items */
|
||||
.bookmark-item:not([container]) {
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px)
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
|
||||
.bookmark-item[container] {
|
||||
|
@ -514,12 +513,22 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
#appmenu_addons,
|
||||
#menu_openAddons {
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
|
||||
}
|
||||
|
||||
#menu_pageInfo,
|
||||
#context-viewinfo,
|
||||
#context-viewframeinfo {
|
||||
list-style-image: url("moz-icon://stock/gtk-info?size=menu");
|
||||
}
|
||||
|
||||
#appmenu_privateBrowsing,
|
||||
#privateBrowsingItem {
|
||||
list-style-image: url("chrome://browser/skin/Privacy-16.png");
|
||||
}
|
||||
|
||||
#placesContext_show\:info {
|
||||
list-style-image: url("moz-icon://stock/gtk-properties?size=menu");
|
||||
}
|
||||
|
@ -878,9 +887,7 @@ toolbar[iconsize="small"] #feed-button {
|
|||
/* Fullscreen window controls */
|
||||
#window-controls {
|
||||
-moz-box-align: start;
|
||||
padding: 0;
|
||||
border-left: 2px solid;
|
||||
-moz-border-left-colors: ThreeDHighlight ThreeDShadow;
|
||||
-moz-margin-start: 10px;
|
||||
}
|
||||
|
||||
#minimize-button {
|
||||
|
@ -1002,12 +1009,11 @@ toolbar[iconsize="small"] #feed-button {
|
|||
}
|
||||
|
||||
#page-proxy-favicon:not([src]) {
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
|
||||
#page-proxy-favicon[pageproxystate="invalid"] {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0px);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#urlbar-throbber {
|
||||
|
@ -1195,6 +1201,10 @@ toolbar[iconsize="small"] #feed-button {
|
|||
outline: 1px dotted -moz-DialogText;
|
||||
}
|
||||
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
@ -1498,8 +1508,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
width: 16px;
|
||||
height: 16px;
|
||||
-moz-margin-end: 3px;
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
|
||||
.tab-throbber {
|
||||
|
@ -1616,8 +1625,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
|
||||
/* All tabs menupopup */
|
||||
.alltabs-item > .menu-iconic-left > .menu-iconic-icon {
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
|
||||
.alltabs-item[selected="true"] {
|
||||
|
|
|
@ -23,7 +23,7 @@ treechildren::-moz-tree-image(title) {
|
|||
margin: 0px 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, livemarkItem) {
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
.searchbar-engine-image {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
list-style-image: url("moz-icon://stock/gtk-file?size=menu");
|
||||
-moz-margin-start: 2px;
|
||||
}
|
||||
|
||||
|
|
Двоичные данные
browser/themes/gnomestripe/browser/tabview/stack-expander.png
Двоичные данные
browser/themes/gnomestripe/browser/tabview/stack-expander.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 1009 B После Ширина: | Высота: | Размер: 1.7 KiB |
|
@ -465,15 +465,15 @@ html[dir=rtl] .title-shield {
|
|||
}
|
||||
|
||||
.stackExpander {
|
||||
opacity: .4;
|
||||
cursor: pointer;
|
||||
background-image: url(chrome://browser/skin/tabview/stack-expander.png);
|
||||
bottom: 8px;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 48, 24, 24);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.stackExpander:hover {
|
||||
opacity: .7 !important;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 24, 24, 0);
|
||||
}
|
||||
|
||||
/* Resizable
|
||||
|
|
|
@ -288,6 +288,22 @@ toolbarbutton.bookmark-item > menupopup {
|
|||
background-origin: border-box;
|
||||
}
|
||||
|
||||
.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme,
|
||||
#restore-button:-moz-lwtheme {
|
||||
border-color: rgba(0, 0, 0, 0.4);
|
||||
background-image: -moz-linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.2));
|
||||
box-shadow: inset 0 1px rgba(255,255,255,0.3), 0 1px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme-darktext,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme-darktext,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme-darktext,
|
||||
#restore-button:-moz-lwtheme-darktext {
|
||||
background-image: -moz-linear-gradient(rgba(255,255,255,0.3), rgba(50,50,50,0.2) 50%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.13));
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
margin: 0;
|
||||
|
@ -376,30 +392,50 @@ toolbar:not([mode="icons"]) .toolbarbutton-1:not([open="true"]) > .toolbarbutton
|
|||
margin: 2px 0 0;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):active:hover,
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"])[open="true"],
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([disabled="true"]) > .toolbarbutton-menubutton-button:active:hover,
|
||||
toolbar[mode="icons"] .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
toolbar[mode="icons"] #restore-button:not([disabled="true"]):active:hover {
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):active:hover:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"])[open="true"]:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([disabled="true"]) > .toolbarbutton-menubutton-button:active:hover:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] #restore-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme) {
|
||||
background: @toolbarbuttonPressedBackgroundColor@;
|
||||
text-shadow: @loweredShadow@;
|
||||
box-shadow: @toolbarbuttonPressedInnerShadow@, @loweredShadow@;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"] {
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):active:hover:-moz-lwtheme,
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"])[open="true"]:-moz-lwtheme,
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([disabled="true"]) > .toolbarbutton-menubutton-button:active:hover:-moz-lwtheme,
|
||||
toolbar[mode="icons"] .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme,
|
||||
toolbar[mode="icons"] #restore-button:not([disabled="true"]):active:hover:-moz-lwtheme {
|
||||
text-shadow: @loweredShadow@;
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not(:-moz-lwtheme) {
|
||||
background: #606060;
|
||||
box-shadow: inset #2A2A2A 0 3px 3.5px, @loweredShadow@;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not([disabled="true"]):active:hover {
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:-moz-lwtheme {
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
box-shadow: inset 0 2px 5px rgba(0,0,0,0.7), 0 1px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not([disabled="true"]):active:hover:not(:-moz-lwtheme) {
|
||||
background: #4E4E4E;
|
||||
box-shadow: inset #1c1c1c 0 3px 3.5px;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):-moz-window-inactive,
|
||||
toolbar[mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-window-inactive,
|
||||
toolbar[mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-window-inactive,
|
||||
toolbar[mode="icons"] #restore-button:-moz-window-inactive {
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not([disabled="true"]):active:hover:-moz-lwtheme {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.8), 0 1px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):-moz-window-inactive:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-window-inactive:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-window-inactive:not(:-moz-lwtheme),
|
||||
toolbar[mode="icons"] #restore-button:-moz-window-inactive:not(:-moz-lwtheme) {
|
||||
border-color: @toolbarbuttonInactiveBorderColor@;
|
||||
background-image: @toolbarbuttonInactiveBackgroundImage@;
|
||||
}
|
||||
|
@ -432,20 +468,18 @@ toolbar[mode="icons"] .toolbarbutton-1 > menupopup {
|
|||
toolbar:not([iconsize="small"])[mode="icons"] #back-button {
|
||||
-moz-margin-end: -5px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
-moz-image-region: rect(0, 20px, 20px, 0);
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button:-moz-locale-dir(rtl) {
|
||||
-moz-transform: scaleX(-1);
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 4px 5px 4px 3px;
|
||||
border-radius: 10000px;
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button:-moz-locale-dir(rtl) {
|
||||
-moz-transform: scaleX(-1);
|
||||
}
|
||||
|
||||
toolbar[mode="icons"] #forward-button {
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
@ -456,6 +490,10 @@ toolbar[mode="icons"]:not([iconsize="small"]) #forward-button {
|
|||
-moz-padding-end: 2px;
|
||||
}
|
||||
|
||||
toolbar[mode="icons"]:not([iconsize="small"]) #forward-button:-moz-lwtheme {
|
||||
mask: url(chrome://browser/content/browser.xul#pinstripe-keyhole-forward-mask);
|
||||
}
|
||||
|
||||
toolbar[iconsize="small"][mode="icons"] #back-button {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
@ -1134,13 +1172,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
padding: 0;
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 8px !important;
|
||||
margin-bottom: 8px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#editBMPanel_newFolderButton {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent !important;
|
||||
border: 0;
|
||||
-moz-border-end-width: 3px;
|
||||
border-style: solid;
|
||||
|
@ -1152,7 +1189,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
min-height: 20px;
|
||||
height: 20px;
|
||||
color: #fff;
|
||||
list-style-image: url("chrome://browser/skin/hud-style-new-folder-plus-sign.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/hud-style-new-folder-plus-sign.png");
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -1162,13 +1199,11 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
#editBMPanel_newFolderButton:-moz-focusring {
|
||||
box-shadow: 0 0 1px -moz-mac-focusring inset,
|
||||
0 0 4px 1px -moz-mac-focusring,
|
||||
0 0 2px 1px -moz-mac-focusring;
|
||||
@hudButtonFocused@
|
||||
}
|
||||
|
||||
#editBMPanel_newFolderButton .button-text {
|
||||
display: none !important;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#editBMPanel_folderMenuList {
|
||||
|
@ -1253,41 +1288,38 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
#editBMPanel_tagsSelector:-moz-focusring {
|
||||
box-shadow: 0 0 1px -moz-mac-focusring inset,
|
||||
0 0 4px 1px -moz-mac-focusring,
|
||||
0 0 2px 1px -moz-mac-focusring;
|
||||
@hudButtonFocused@
|
||||
}
|
||||
|
||||
#editBMPanel_tagsSelector .listcell-check {
|
||||
-moz-appearance: none !important;
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
border: 0;
|
||||
list-style-image: url("chrome://browser/skin/hud-style-check-box-empty.png");
|
||||
background: url("chrome://browser/skin/hud-style-check-box-empty.png") no-repeat 50% 50%;
|
||||
min-height: 14px;
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
#editBMPanel_tagsSelector .listcell-check[checked="true"] {
|
||||
list-style-image: url("chrome://browser/skin/hud-style-check-box-checked.png");
|
||||
background-image: url("chrome://browser/skin/hud-style-check-box-checked.png");
|
||||
}
|
||||
|
||||
#editBMPanel_folderTree treechildren::-moz-tree-row {
|
||||
color: #fff !important;
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
#editBMPanel_folderTree > treechildren::-moz-tree-row {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#editBMPanel_folderTree treechildren::-moz-tree-row(selected) {
|
||||
background-color: #b3b3b3 !important;
|
||||
#editBMPanel_folderTree > treechildren::-moz-tree-row(selected) {
|
||||
background-color: #b3b3b3;
|
||||
}
|
||||
|
||||
#editBMPanel_folderTree treechildren::-moz-tree-cell-text(selected),
|
||||
#editBMPanel_folderTree treechildren::-moz-tree-cell-text(selected, focus) {
|
||||
color: #222222 !important;
|
||||
#editBMPanel_folderTree > treechildren::-moz-tree-cell-text(selected),
|
||||
#editBMPanel_folderTree > treechildren::-moz-tree-cell-text(selected, focus) {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
#editBMPanel_folderTree treechildren::-moz-tree-row(selected, focus) {
|
||||
background-color: #b3b3b3 !important;
|
||||
#editBMPanel_folderTree > treechildren::-moz-tree-row(selected, focus) {
|
||||
background-color: #b3b3b3;
|
||||
}
|
||||
|
||||
#editBMPanel_tagsSelector > listitem[selected="true"] {
|
||||
|
@ -1321,12 +1353,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
|
||||
#editBookmarkPanel .expander-up,
|
||||
#editBookmarkPanel .expander-down:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/hud-style-expander-open.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/hud-style-expander-open.png");
|
||||
}
|
||||
|
||||
#editBookmarkPanel .expander-down,
|
||||
#editBookmarkPanel .expander-up:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/hud-style-expander-closed.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/hud-style-expander-closed.png");
|
||||
}
|
||||
|
||||
/**** name picker ****/
|
||||
|
@ -1350,14 +1382,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
#editBMPanel_tagsField > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder {
|
||||
color: #bbb !important;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#editBMPanel_tagsField[focused="true"],
|
||||
#editBMPanel_namePicker[droppable="false"][focused="true"] > .menulist-editable-box {
|
||||
box-shadow: 0 0 1px -moz-mac-focusring inset,
|
||||
0 0 4px 1px -moz-mac-focusring,
|
||||
0 0 2px 1px -moz-mac-focusring;
|
||||
@hudButtonFocused@
|
||||
background-color: #eee !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
@ -1467,6 +1497,14 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
opacity: .8;
|
||||
}
|
||||
|
||||
/* Prevent overlapping of tabs during the close animation */
|
||||
.tab-label:not([fadein]):not([pinned]) {
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
-moz-transition: opacity 100ms ease-out,
|
||||
margin 30ms ease-out 80ms;
|
||||
}
|
||||
|
||||
.tab-stack {
|
||||
/* ensure stable tab height with and without toolbarbuttons on the tab bar */
|
||||
height: 26px;
|
||||
|
@ -1659,11 +1697,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
|
||||
.tabbrowser-tab[selected="true"] {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[selected="true"]:not([pinned]),
|
||||
#tabbrowser-tabs[pinnedonly="true"] > .tabbrowser-tab[selected="true"] {
|
||||
/* Don't overwrite position:fixed on pinned tabs. */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -1885,7 +1918,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
-moz-image-region: rect(0, 54px, 20px, 36px);
|
||||
}
|
||||
|
||||
#TabsToolbar > #alltabs-button {
|
||||
#TabsToolbar #alltabs-button {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png);
|
||||
-moz-image-region: rect(0, 22px, 20px, 0);
|
||||
}
|
||||
|
@ -2034,6 +2067,10 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
0 0 3px 2px -moz-mac-focusring;
|
||||
}
|
||||
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
|
|
@ -69,19 +69,19 @@
|
|||
}
|
||||
|
||||
.expander-up {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open.png");
|
||||
}
|
||||
|
||||
.expander-down {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed.png");
|
||||
}
|
||||
|
||||
.expander-down:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/places/expander-closed-active.png");
|
||||
}
|
||||
|
||||
.expander-up:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
|
||||
list-style-image: url("chrome://browser/skin/places/expander-open-active.png");
|
||||
}
|
||||
|
||||
#editBookmarkPanelContent {
|
||||
|
|
Двоичные данные
browser/themes/pinstripe/browser/tabview/stack-expander.png
Двоичные данные
browser/themes/pinstripe/browser/tabview/stack-expander.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 1009 B После Ширина: | Высота: | Размер: 1.5 KiB |
|
@ -457,15 +457,15 @@ html[dir=rtl] .title-shield {
|
|||
}
|
||||
|
||||
.stackExpander {
|
||||
opacity: .4;
|
||||
cursor: pointer;
|
||||
background-image: url(chrome://browser/skin/tabview/stack-expander.png);
|
||||
bottom: 8px;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 48, 24, 24);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.stackExpander:hover {
|
||||
opacity: .7 !important;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 24, 24, 0);
|
||||
}
|
||||
|
||||
/* Resizable
|
||||
|
|
|
@ -149,6 +149,14 @@
|
|||
border-top-right-radius: 3.5px;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme),
|
||||
#navigator-toolbox[tabsontop="true"] > #nav-bar:not(:-moz-lwtheme),
|
||||
#navigator-toolbox[tabsontop="true"]:not([customizing]) > #nav-bar[collapsed="true"] + toolbar:not(:-moz-lwtheme),
|
||||
#navigator-toolbox[tabsontop="true"]:not([customizing]) > #nav-bar[collapsed="true"] + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme) {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#navigator-toolbox:not([tabsontop="true"]) > #PersonalToolbar {
|
||||
padding-top: 0 !important;
|
||||
margin-top: 3px;
|
||||
|
@ -208,17 +216,6 @@
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not(:-moz-lwtheme):not([selected="true"]),
|
||||
.tabs-newtab-button:not(:-moz-lwtheme) {
|
||||
background-image: -moz-linear-gradient(hsl(214,15%,80%), hsl(214,15%,65%) 50%);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not(:-moz-lwtheme):not([selected="true"]):hover,
|
||||
.tabs-newtab-button:not(:-moz-lwtheme):hover {
|
||||
background-image: -moz-linear-gradient(hsl(214,15%,90%), hsl(214,15%,75%) 50%);
|
||||
}
|
||||
|
||||
#allTabs-panel,
|
||||
#ctrlTab-panel {
|
||||
background: transparent;
|
||||
|
|
|
@ -552,9 +552,22 @@ menuitem.bookmark-item {
|
|||
|
||||
/* ::::: primary toolbar buttons ::::: */
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
|
||||
.toolbarbutton-1 {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar.png");
|
||||
}
|
||||
|
||||
.toolbarbutton-1:not([type="menu-button"]) {
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
|
||||
#nav-bar .toolbarbutton-1 {
|
||||
-moz-appearance: none;
|
||||
padding: 1px 5px;
|
||||
background: rgba(151,152,153,.05)
|
||||
|
@ -571,19 +584,14 @@ menuitem.bookmark-item {
|
|||
text-shadow: 0 0 2px white;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
|
||||
toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
|
||||
#nav-bar[iconsize="small"][mode="icons"] .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
#nav-bar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.toolbarbutton-1:not([type="menu-button"]) {
|
||||
-moz-box-orient: vertical;
|
||||
list-style-image: url("chrome://browser/skin/Toolbar.png");
|
||||
}
|
||||
|
||||
.toolbarbutton-1[type="menu-button"] {
|
||||
#nav-bar .toolbarbutton-1[type="menu-button"] {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
background: none !important;
|
||||
|
@ -591,43 +599,43 @@ toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
|||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 {
|
||||
#nav-bar .toolbarbutton-1 {
|
||||
margin: 1px 3px;
|
||||
}
|
||||
|
||||
toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
||||
#nav-bar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-border-start-style: none;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr),
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl),
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.toolbarbutton-1[disabled="true"] {
|
||||
#nav-bar .toolbarbutton-1[disabled="true"] {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon {
|
||||
#nav-bar .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):not(:active):hover,
|
||||
.toolbarbutton-1:not([open="true"]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
|
||||
.toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):not([checked="true"]):not([open="true"]):not(:active):hover {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):not(:active):hover,
|
||||
#nav-bar .toolbarbutton-1:not([open="true"]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
|
||||
#nav-bar .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):not([checked="true"]):not([open="true"]):not(:active):hover {
|
||||
background-color: hsla(190,60%,70%,.5);
|
||||
border-color: hsla(190,50%,65%,.8) hsla(190,50%,50%,.8) hsla(190,50%,40%,.8);
|
||||
box-shadow: 0 0 0 1px rgba(255,255,255,.3) inset,
|
||||
|
@ -639,12 +647,12 @@ toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
|||
box-shadow .3s ease-in;
|
||||
}
|
||||
|
||||
.toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):hover:active,
|
||||
.toolbarbutton-1:hover:active > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
|
||||
.toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
.toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):hover:active,
|
||||
.toolbarbutton-1:not([type="menu-button"])[checked="true"],
|
||||
.toolbarbutton-1[open="true"] {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled="true"]):hover:active,
|
||||
#nav-bar .toolbarbutton-1:hover:active > .toolbarbutton-menubutton-dropmarker:not([disabled="true"]),
|
||||
#nav-bar .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
#nav-bar .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):hover:active,
|
||||
#nav-bar .toolbarbutton-1:not([type="menu-button"])[checked="true"],
|
||||
#nav-bar .toolbarbutton-1[open="true"] {
|
||||
background-color: transparent;
|
||||
border-color: rgba(0,0,0,.65) rgba(0,0,0,.55) rgba(0,0,0,.5);
|
||||
box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
|
||||
|
@ -653,7 +661,7 @@ toolbar[iconsize="small"][mode="icons"] .toolbarbutton-1 {
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
.toolbarbutton-1[checked="true"]:not(:active):hover {
|
||||
#nav-bar .toolbarbutton-1[checked="true"]:not(:active):hover {
|
||||
background-color: rgba(90%,90%,90%,.4);
|
||||
-moz-transition: background-color .4s;
|
||||
}
|
||||
|
@ -689,7 +697,6 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
|
||||
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: toolbarbutton;
|
||||
%ifdef WINSTRIPE_AERO
|
||||
margin: -2px 0 -1px;
|
||||
padding-top: 1px;
|
||||
|
@ -700,11 +707,6 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
padding-bottom: 0;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
border: none !important;
|
||||
color: inherit !important;
|
||||
background: transparent !important;
|
||||
text-shadow: inherit !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
%ifdef WINSTRIPE_AERO
|
||||
|
@ -715,21 +717,18 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
}
|
||||
%endif
|
||||
|
||||
:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
/* unified back/forward button */
|
||||
|
||||
#back-button {
|
||||
-moz-image-region: rect(0, 18px, 18px, 0);
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
#forward-button {
|
||||
-moz-image-region: rect(0, 36px, 18px, 18px);
|
||||
border-left: none;
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button {
|
||||
-moz-image-region: rect(18px, 20px, 38px, 0);
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
|
@ -738,18 +737,27 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
-moz-transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(ltr) {
|
||||
#nav-bar #back-button {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
#nav-bar #forward-button {
|
||||
border-left: none;
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
#nav-bar #back-button:-moz-locale-dir(ltr) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl),
|
||||
#forward-button {
|
||||
#nav-bar #back-button:-moz-locale-dir(rtl),
|
||||
#nav-bar #forward-button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button {
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"] #back-button {
|
||||
border-radius: 10000px;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
|
@ -767,10 +775,9 @@ toolbar:not([iconsize="small"])[mode="icons"] #back-button {
|
|||
0 1px 0 rgba(0,0,0,.4),
|
||||
0 1px 1px rgba(0,0,0,.3),
|
||||
1px 2px 1px rgba(0,0,0,.2);
|
||||
-moz-image-region: rect(18px, 20px, 38px, 0);
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button:not([disabled="true"]):not([checked="true"]):not(:active):hover {
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"] #back-button:not([disabled="true"]):not([checked="true"]):not(:active):hover {
|
||||
box-shadow: 0 0 0 1px rgba(255,255,255,.3) inset,
|
||||
0 0 0 2px rgba(255,255,255,.1) inset,
|
||||
0 0 0 1px hsla(190,50%,40%,.3),
|
||||
|
@ -780,25 +787,25 @@ toolbar:not([iconsize="small"])[mode="icons"] #back-button:not([disabled="true"]
|
|||
0 0 5px 1px hsl(190,90%,80%);
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #back-button:not([disabled="true"]):hover:active {
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"] #back-button:not([disabled="true"]):hover:active {
|
||||
box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
|
||||
0 0 2px rgba(0,0,0,.4) inset,
|
||||
0 0 0 1px rgba(0,0,0,.65),
|
||||
0 2px 0 rgba(255,255,255,.4);
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"][currentset*="unified-back-forward-button"],
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"][currentset*="unified-back-forward-button"],
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"]:not([currentset]) {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#navigator-toolbox[tabsontop="true"] > toolbar:not([iconsize="small"])[mode="icons"][currentset*="unified-back-forward-button"],
|
||||
#navigator-toolbox[tabsontop="true"] > #nav-bar:not([iconsize="small"])[mode="icons"][currentset*="unified-back-forward-button"],
|
||||
#navigator-toolbox[tabsontop="true"] > #nav-bar:not([iconsize="small"])[mode="icons"]:not([currentset]) {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #forward-button {
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"] #forward-button {
|
||||
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
|
||||
mask: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-mask);
|
||||
-moz-margin-start: -6px;
|
||||
|
@ -806,7 +813,7 @@ toolbar:not([iconsize="small"])[mode="icons"] #forward-button {
|
|||
padding-right: 3px;
|
||||
}
|
||||
|
||||
toolbar:not([iconsize="small"])[mode="icons"] #forward-button:not([disabled="true"]):not(:active):hover {
|
||||
#nav-bar:not([iconsize="small"])[mode="icons"] #forward-button:not([disabled="true"]):not(:active):hover {
|
||||
/*mask: url(keyhole-forward-mask.svg#mask-hover);*/
|
||||
mask: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-mask-hover);
|
||||
/* Don't animate the box shadow, as the blur and spread radii affect the mask. */
|
||||
|
@ -940,23 +947,29 @@ toolbar:not([iconsize="small"])[mode="icons"] #forward-button:not([disabled="tru
|
|||
|
||||
#zoom-out-button {
|
||||
-moz-image-region: rect(0, 288px, 18px, 270px);
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
#zoom-in-button {
|
||||
-moz-image-region: rect(0, 306px, 18px, 288px);
|
||||
}
|
||||
|
||||
#nav-bar #zoom-out-button {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
#nav-bar #zoom-in-button {
|
||||
-moz-border-start: none;
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
#zoom-out-button:-moz-locale-dir(ltr),
|
||||
#zoom-in-button:-moz-locale-dir(rtl) {
|
||||
#nav-bar #zoom-out-button:-moz-locale-dir(ltr),
|
||||
#nav-bar #zoom-in-button:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
#zoom-out-button:-moz-locale-dir(rtl),
|
||||
#zoom-in-button:-moz-locale-dir(ltr) {
|
||||
#nav-bar #zoom-out-button:-moz-locale-dir(rtl),
|
||||
#nav-bar #zoom-in-button:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
@ -1498,15 +1511,24 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > scrollbox:not(:-moz-lwtheme) {
|
||||
padding-bottom: 1px;
|
||||
margin-bottom: -1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) {
|
||||
margin-bottom: -1px;
|
||||
padding-bottom: 1px;
|
||||
%ifdef WINSTRIPE_AERO
|
||||
@media not all and (-moz-windows-compositor) {
|
||||
%endif
|
||||
#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > scrollbox:not(:-moz-lwtheme) {
|
||||
padding-bottom: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) {
|
||||
margin-bottom: -1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
%ifdef WINSTRIPE_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
/* Tabs */
|
||||
.tabbrowser-tab,
|
||||
|
@ -2001,6 +2023,10 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
|
Двоичные данные
browser/themes/winstripe/browser/tabview/stack-expander.png
Двоичные данные
browser/themes/winstripe/browser/tabview/stack-expander.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 1009 B После Ширина: | Высота: | Размер: 1.9 KiB |
|
@ -484,15 +484,15 @@ html[dir=rtl] .title-shield {
|
|||
}
|
||||
|
||||
.stackExpander {
|
||||
opacity: .4;
|
||||
cursor: pointer;
|
||||
background-image: url(chrome://browser/skin/tabview/stack-expander.png);
|
||||
bottom: 8px;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 48, 24, 24);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.stackExpander:hover {
|
||||
opacity: .7 !important;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/tabview/stack-expander.png), 0, 24, 24, 0);
|
||||
}
|
||||
|
||||
/* Resizable
|
||||
|
|
|
@ -120,6 +120,7 @@ postflight_all:
|
|||
$(DIST_UNI)/$(MOZ_PKG_APPNAME)/$(APPNAME)
|
||||
# A universal .dmg can now be produced by making in either architecture's
|
||||
# INSTALLER_DIR.
|
||||
ifdef ENABLE_TESTS
|
||||
# Now, repeat the process for the test package.
|
||||
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= CHROME_JAR= package-tests
|
||||
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= CHROME_JAR= package-tests
|
||||
|
@ -137,3 +138,4 @@ postflight_all:
|
|||
$(DIST_ARCH_1)/test-package-stage \
|
||||
$(DIST_ARCH_2)/test-package-stage \
|
||||
$(DIST_UNI)/test-package-stage; fi
|
||||
endif
|
||||
|
|
|
@ -477,12 +477,6 @@ INCLUDES = \
|
|||
|
||||
include $(topsrcdir)/config/static-checking-config.mk
|
||||
|
||||
ifdef MOZ_SHARK
|
||||
OS_CFLAGS += -F/System/Library/PrivateFrameworks
|
||||
OS_CXXFLAGS += -F/System/Library/PrivateFrameworks
|
||||
OS_LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
|
||||
endif # ifdef MOZ_SHARK
|
||||
|
||||
CFLAGS = $(OS_CFLAGS)
|
||||
CXXFLAGS = $(OS_CXXFLAGS)
|
||||
LDFLAGS = $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
# /bin/bash
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# We must avoid using the vanilla new/new[] operators (and consequently, the
|
||||
# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why.
|
||||
#
|
||||
# This script:
|
||||
# - Detects if any of the vanilla new/new[] operators are used in a file.
|
||||
# Its exit code is 1 if it found some, and 0 if it didn't.
|
||||
# - Doesn't detect delete/delete[] because it appears they can be present
|
||||
# somehow due to virtual destructors, but this is ok because vanilla
|
||||
# delete/delete[] calls don't make sense without corresponding new/new[]
|
||||
# calls, and any explicit calls will be caught by Valgrind's mismatched
|
||||
# alloc/free checking.
|
||||
# - Doesn't detect the 'nothrow' variants, which are ok but probably still
|
||||
# best avoided.
|
||||
# - Is designed to only run on Linux (though it may also work on Mac); one
|
||||
# platform will be enough to catch any violations.
|
||||
#
|
||||
# If this script fails:
|
||||
# - You need to find the uses of vanilla new/delete and replace them with
|
||||
# js_new()/js_delete().
|
||||
# - Run this script on each of the .o files, that should narrow it down.
|
||||
# - After that, one way to find them is to run 'objdump -r -C' on the
|
||||
# relevant .o files. For example, you might search for 'operator new' and
|
||||
# find a record like this:
|
||||
#
|
||||
# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]:
|
||||
# OFFSET TYPE VALUE
|
||||
# 00000009 R_386_PC32 __i686.get_pc_thunk.bx
|
||||
# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_
|
||||
# 0000001b R_386_PLT32 operator new(unsigned int)
|
||||
# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int)
|
||||
# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool()
|
||||
# 00000052 R_386_PLT32 operator delete(void*)
|
||||
#
|
||||
# This says that vanilla 'new' and 'delete' are both used in
|
||||
# JSC::ExecutablePool::create(unsigned int). This doesn't always work,
|
||||
# though. (Nb: use 'c++filt' to demangle names like
|
||||
# _ZN3JSC14ExecutablePool6createEj.)
|
||||
#
|
||||
# If that doesn't work, use grep.
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
if [ -z $1 ] ; then
|
||||
echo "usage: find_vanilla_new_calls <file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file=$1
|
||||
|
||||
if [ ! -f $file ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpfile1=`mktemp`
|
||||
tmpfile2=`mktemp`
|
||||
nm -C $file > $tmpfile1
|
||||
|
||||
# Need to double-escape '[' and ']' to stop grep from interpreting them
|
||||
# specially.
|
||||
grep 'operator new(unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new(unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2
|
||||
grep 'operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2
|
||||
rm -f $tmpfile1
|
||||
|
||||
if [ -s $tmpfile2 ] ; then
|
||||
echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below"
|
||||
cat $tmpfile2
|
||||
echo
|
||||
rm -f $tmpfile2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "TEST-PASS | find_vanilla_new_calls | ok"
|
||||
echo
|
||||
|
||||
exit 0
|
|
@ -60,7 +60,7 @@ ABS_DIST = $(call core_abspath,$(DIST))
|
|||
|
||||
libs::
|
||||
$(MAKE) -C $(DEPTH)/nsprpub install prefix=$(ABS_DIST)/sdk exec_prefix=$(ABS_DIST)/sdk bindir=$(ABS_DIST)/sdk/dummy includedir=$(ABS_DIST)/include libdir=$(ABS_DIST)/sdk/lib datadir=$(ABS_DIST)/sdk/dummy DESTDIR=
|
||||
$(INSTALL) $(DEPTH)/nsprpub/config/nspr-config $(DIST)/bin
|
||||
$(INSTALL) $(DEPTH)/nsprpub/config/nspr-config $(DIST)/sdk/bin
|
||||
$(RM) -rf $(DIST)/sdk/dummy
|
||||
ifneq (,$(filter OS2 WINNT,$(OS_ARCH))) # {
|
||||
$(RM) -f $(DIST)/sdk/lib/$(DLL_PREFIX)nspr4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plc4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plds4$(DLL_SUFFIX)
|
||||
|
|
|
@ -224,7 +224,7 @@ ifdef CPP_UNIT_TESTS
|
|||
CPPSRCS += $(CPP_UNIT_TESTS)
|
||||
SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
|
||||
INCLUDES += -I$(DIST)/include/testing
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) -ljs_static
|
||||
|
||||
# ...and run them the usual way
|
||||
check::
|
||||
|
|
58
configure.in
58
configure.in
|
@ -4642,8 +4642,8 @@ else
|
|||
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib "
|
||||
fi
|
||||
else
|
||||
NSPR_CFLAGS='`$(LIBXUL_DIST)/bin/nspr-config --prefix='${LIBXUL_DIST}' --includedir='${LIBXUL_DIST}'/include/nspr --cflags`'
|
||||
NSPR_LIBS='`$(LIBXUL_DIST)/bin/nspr-config --prefix='${LIBXUL_DIST}' --libdir='${LIBXUL_DIST}'/lib --libs`'
|
||||
NSPR_CFLAGS='`$(LIBXUL_DIST)/sdk/bin/nspr-config --prefix='${LIBXUL_DIST}' --includedir='${LIBXUL_DIST}'/include/nspr --cflags`'
|
||||
NSPR_LIBS='`$(LIBXUL_DIST)/sdk/bin/nspr-config --prefix='${LIBXUL_DIST}' --libdir='${LIBXUL_DIST}'/lib --libs`'
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -7132,18 +7132,39 @@ if test $MOZ_PLATFORM_MAEMO; then
|
|||
AC_SUBST(MOZ_PLATFORM_MAEMO_CFLAGS)
|
||||
fi
|
||||
|
||||
dnl Setup default CPU arch for arm target
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
MOZ_ARM_ARCH=armv7
|
||||
;;
|
||||
esac
|
||||
dnl ========================================================
|
||||
dnl = Enable building the Thumb2 instruction set
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(thumb2,
|
||||
[ --enable-thumb2 Enable Thumb2 instruction set],
|
||||
[ --enable-thumb2 Enable Thumb2 instruction set (implies ARMv7)],
|
||||
MOZ_THUMB2=1,
|
||||
MOZ_THUMB2=)
|
||||
if test -n "$MOZ_THUMB2"; then
|
||||
MOZ_ARM_ARCH=armv7
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable building for ARM specific CPU features
|
||||
dnl ========================================================
|
||||
MOZ_ARG_WITH_STRING(cpu-arch,
|
||||
[ --with-cpu-arch=arch Use specific arm architecture CPU features, default armv7],
|
||||
MOZ_ARM_ARCH=$withval)
|
||||
|
||||
if test -n "$MOZ_THUMB2"; then
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
if test "$MOZ_ARM_ARCH" != "armv7"; then
|
||||
AC_MSG_ERROR([--enable-thumb2 is not compatible with cpu-arch=$MOZ_ARM_ARCH])
|
||||
fi
|
||||
if test "$GNU_CC"; then
|
||||
AC_DEFINE(MOZ_THUMB2)
|
||||
AC_DEFINE(MOZ_ARM_ARCH)
|
||||
CFLAGS="$CFLAGS -march=armv7-a -mthumb -Wa, -march=armv7-a -Wa, -mthumb"
|
||||
CXXFLAGS="$CXXFLAGS -march=armv7-a -mthumb -Wa, -march=armv7-a -Wa, -mthumb"
|
||||
ASFLAGS="$ASFLAGS -march=armv7-a -mthumb"
|
||||
|
@ -7155,11 +7176,27 @@ if test -n "$MOZ_THUMB2"; then
|
|||
AC_MSG_ERROR([--enable-thumb2 is not supported for non-ARM CPU architectures])
|
||||
;;
|
||||
esac
|
||||
elif test "$MOZ_ARM_ARCH" = "armv7"; then
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
if test "$GNU_CC"; then
|
||||
AC_DEFINE(MOZ_ARM_ARCH)
|
||||
CFLAGS="$CFLAGS -march=armv7-a -marm -Wa, -march=armv7-a -Wa, -marm"
|
||||
CXXFLAGS="$CXXFLAGS -march=armv7-a -marm -Wa, -march=armv7-a -Wa, -marm"
|
||||
ASFLAGS="$ASFLAGS -march=armv7-a -marm"
|
||||
else
|
||||
AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-GNU toolchains])
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([--with-cpu-arch=armv7 is not supported for non-ARM CPU architectures])
|
||||
;;
|
||||
esac
|
||||
else
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
if test "$GNU_CC"; then
|
||||
CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -Wa, -march=armv5te -Wa, -mthumb-interwork"
|
||||
CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -Wa, -march=armv5te -Wa, -mthumb-interwork"
|
||||
CXXFLAGS="$CXXFLAGS -march=armv5te -mthumb-interwork -Wa, -march=armv5te -Wa, -mthumb-interwork"
|
||||
ASFLAGS="$ASFLAGS -march=armv5te -mthumb-interwork"
|
||||
fi
|
||||
|
@ -7168,6 +7205,7 @@ else
|
|||
fi
|
||||
|
||||
AC_SUBST(MOZ_THUMB2)
|
||||
AC_SUBST(MOZ_ARM_ARCH)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = faststripe theme
|
||||
|
@ -7604,7 +7642,7 @@ dnl ========================================================
|
|||
dnl shark
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(shark,
|
||||
[ --enable-shark Enable shark remote profiling (needs CHUD framework). Implies --enable-profiling.],
|
||||
[ --enable-shark Enable shark remote profiling. Implies --enable-profiling.],
|
||||
MOZ_SHARK=1,
|
||||
MOZ_SHARK= )
|
||||
if test -n "$MOZ_SHARK"; then
|
||||
|
@ -7635,6 +7673,13 @@ if test -n "$MOZ_VTUNE"; then
|
|||
AC_DEFINE(MOZ_VTUNE)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl Profiling
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_PROFILING"; then
|
||||
AC_DEFINE(MOZ_PROFILING)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl Zealous JavaScript GC
|
||||
dnl ========================================================
|
||||
|
@ -9478,6 +9523,9 @@ if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
|
|||
if test -n "$MOZ_THUMB2"; then
|
||||
_SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --enable-thumb2"
|
||||
fi
|
||||
if test -n "$MOZ_ARM_ARCH"; then
|
||||
_SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --with-cpu-arch=$MOZ_ARM_ARCH"
|
||||
fi
|
||||
if test -n "$_WRAP_MALLOC"; then
|
||||
_SUBDIR_CONFIG_ARGS="$_SUBDIR_CONFIG_ARGS --enable-wrap-malloc"
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var frame1 = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); frame1.src = "data:text/html,1"; document.body.appendChild(frame1);
|
||||
var frame2 = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); frame2.src = "data:text/html,2"; document.body.appendChild(frame2);
|
||||
var frame1doc = frame1.contentDocument;
|
||||
var frame1root = frame1doc.documentElement;
|
||||
frame1root.appendChild(frame2);
|
||||
setTimeout(function() {
|
||||
try {
|
||||
frame2.contentDocument.q = frame1root.__lookupGetter__("nextSibling");
|
||||
} catch(ex) {}
|
||||
document.documentElement.removeAttribute("class");
|
||||
}, 200);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
||||
|
|
@ -82,3 +82,4 @@ load 595606-2.html
|
|||
load 606729-1.html
|
||||
load 593302-1.html
|
||||
load 593302-2.html
|
||||
load 610571-1.html
|
||||
|
|
|
@ -855,6 +855,33 @@ nsExternalResourceMap::ShowViewers()
|
|||
mMap.EnumerateRead(ExternalResourceShower, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
TransferZoomLevels(nsIDocument* aFromDoc,
|
||||
nsIDocument* aToDoc)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aFromDoc && aToDoc,
|
||||
"transferring zoom levels from/to null doc");
|
||||
|
||||
nsIPresShell* fromShell = aFromDoc->GetShell();
|
||||
if (!fromShell)
|
||||
return;
|
||||
|
||||
nsPresContext* fromCtxt = fromShell->GetPresContext();
|
||||
if (!fromCtxt)
|
||||
return;
|
||||
|
||||
nsIPresShell* toShell = aToDoc->GetShell();
|
||||
if (!toShell)
|
||||
return;
|
||||
|
||||
nsPresContext* toCtxt = toShell->GetPresContext();
|
||||
if (!toCtxt)
|
||||
return;
|
||||
|
||||
toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
|
||||
toCtxt->SetTextZoom(fromCtxt->TextZoom());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
|
||||
nsIDocumentViewer* aViewer,
|
||||
|
@ -912,6 +939,9 @@ nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
|
|||
newResource->mDocument = doc;
|
||||
newResource->mViewer = aViewer;
|
||||
newResource->mLoadGroup = aLoadGroup;
|
||||
if (doc) {
|
||||
TransferZoomLevels(aDisplayDocument, doc);
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
|
||||
|
@ -2220,12 +2250,12 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
|
|||
|
||||
// Now reset our inline style and attribute sheets.
|
||||
nsresult rv = NS_OK;
|
||||
nsStyleSet::sheetType attrSheetType = GetAttrSheetType();
|
||||
if (mAttrStyleSheet) {
|
||||
// Remove this sheet from all style sets
|
||||
nsCOMPtr<nsIPresShell> shell = GetShell();
|
||||
if (shell) {
|
||||
shell->StyleSet()->RemoveStyleSheet(attrSheetType, mAttrStyleSheet);
|
||||
shell->StyleSet()->RemoveStyleSheet(nsStyleSet::ePresHintSheet,
|
||||
mAttrStyleSheet);
|
||||
}
|
||||
mAttrStyleSheet->Reset(aURI);
|
||||
} else {
|
||||
|
@ -2265,20 +2295,12 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsStyleSet::sheetType
|
||||
nsDocument::GetAttrSheetType()
|
||||
{
|
||||
return nsStyleSet::ePresHintSheet;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
|
||||
{
|
||||
NS_PRECONDITION(aStyleSet, "Must have a style set");
|
||||
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0,
|
||||
"Style set already has a preshint sheet?");
|
||||
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eHTMLPresHintSheet) == 0,
|
||||
"Style set already has a HTML preshint sheet?");
|
||||
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
|
||||
"Style set already has document sheets?");
|
||||
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0,
|
||||
|
@ -2286,7 +2308,7 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
|
|||
NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?");
|
||||
NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?");
|
||||
|
||||
aStyleSet->AppendStyleSheet(GetAttrSheetType(), mAttrStyleSheet);
|
||||
aStyleSet->AppendStyleSheet(nsStyleSet::ePresHintSheet, mAttrStyleSheet);
|
||||
|
||||
aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet,
|
||||
mStyleAttrStyleSheet);
|
||||
|
|
|
@ -1035,7 +1035,6 @@ protected:
|
|||
nsIPresShell** aInstancePtrResult);
|
||||
|
||||
nsresult ResetStylesheetsToURI(nsIURI* aURI);
|
||||
virtual nsStyleSet::sheetType GetAttrSheetType();
|
||||
void FillStyleSet(nsStyleSet* aStyleSet);
|
||||
|
||||
// Return whether all the presshells for this document are safe to flush
|
||||
|
|
|
@ -1386,8 +1386,9 @@ nsFrameLoader::MaybeCreateDocShell()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (doc->GetDisplayDocument()) {
|
||||
// Don't allow subframe loads in external reference documents
|
||||
if (doc->GetDisplayDocument() || !doc->IsActive()) {
|
||||
// Don't allow subframe loads in external reference documents, nor
|
||||
// in non-active documents.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
|
@ -2059,7 +2060,7 @@ nsFrameLoader::GetRootContentView(nsIContentView** aContentView)
|
|||
NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!");
|
||||
nsRefPtr<nsIContentView>(view).forget(aContentView);
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
#else
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
|
|
|
@ -886,6 +886,7 @@ GK_ATOM(setter, "setter")
|
|||
GK_ATOM(shape, "shape")
|
||||
GK_ATOM(show, "show")
|
||||
GK_ATOM(showcaret, "showcaret")
|
||||
GK_ATOM(showresizer, "showresizer")
|
||||
GK_ATOM(simple, "simple")
|
||||
GK_ATOM(single, "single")
|
||||
GK_ATOM(size, "size")
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nsIJSContextStack.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
bool SendSyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
|
@ -292,6 +293,8 @@ nsInProcessTabChildGlobal::InitTabChildGlobal()
|
|||
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_ANONFUNFIX | JSOPTION_PRIVATE_IS_NSISUPPORTS);
|
||||
JS_SetVersion(cx, JSVERSION_LATEST);
|
||||
|
||||
xpc_LocalizeContext(cx);
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
|
||||
|
|
|
@ -882,10 +882,7 @@ nsObjectLoadingContent::EnsureInstantiation(nsIPluginInstance** aInstance)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = doc->GetShell();
|
||||
if (shell) {
|
||||
shell->RecreateFramesFor(thisContent);
|
||||
}
|
||||
doc->FlushPendingNotifications(Flush_Frames);
|
||||
|
||||
mInstantiating = PR_FALSE;
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче