зеркало из https://github.com/mozilla/gecko-dev.git
Merge tracemonkey to mozilla-central. (a=blockers)
This commit is contained in:
Коммит
04ffe6d2a0
|
@ -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);
|
||||
}
|
||||
|
@ -1855,13 +1763,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 +1819,101 @@ 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();
|
||||
|
||||
nsAccessible* directContainer =
|
||||
GetAccService()->GetContainerAccessible(aInsertedContent->ElementAt(0),
|
||||
mWeakShell);
|
||||
|
||||
// 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.
|
||||
for (PRUint32 idx = 0; idx < aInsertedContent->Length(); idx++)
|
||||
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 +1931,7 @@ nsDocAccessible::UpdateTreeInternal(nsAccessible* aContainer,
|
|||
|
||||
if (!accessible) {
|
||||
updateFlags |= UpdateTreeInternal(aContainer, node->GetFirstChild(),
|
||||
nsnull, aIsInsert, aFireAllEvents,
|
||||
aFromUserInput);
|
||||
nsnull, aIsInsert);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1963,29 +1957,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 +1986,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 +2036,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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,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) {
|
||||
|
@ -2776,6 +2799,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 +2816,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 +4793,7 @@ function setToolbarVisibility(toolbar, isVisible) {
|
|||
|
||||
PlacesToolbarHelper.init();
|
||||
BookmarksMenuButton.updatePosition();
|
||||
gBrowser.updateWindowResizers();
|
||||
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
updateAppButtonDisplay();
|
||||
|
@ -8227,8 +8254,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 +8356,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
|
||||
});
|
||||
|
||||
|
|
|
@ -1014,6 +1014,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"/>
|
||||
|
|
|
@ -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();
|
||||
|
@ -2431,6 +2449,7 @@
|
|||
this.appendChild(this._autoScrollPopup);
|
||||
this.mCurrentBrowser.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
this.mCurrentBrowser.droppedLinkHandler = handleDroppedLink;
|
||||
this.updateWindowResizers();
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
|
@ -2796,30 +2815,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;
|
||||
|
@ -813,7 +813,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
item.removeTrenches();
|
||||
|
||||
if (typeof options == 'undefined')
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
var self = this;
|
||||
|
@ -897,7 +897,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 +1036,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 +1052,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 +1092,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 +1115,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 +1159,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
|
||||
|
@ -1231,6 +1179,72 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
|
||||
self._isStacked = true;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _randRotate
|
||||
|
@ -1284,7 +1298,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 +1330,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 +1378,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 +1392,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");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1627,6 +1646,7 @@ let GroupItems = {
|
|||
_arrangePaused: false,
|
||||
_arrangesPending: [],
|
||||
_removingHiddenGroups: false,
|
||||
_delayedModUpdates: [],
|
||||
minGroupHeight: 110,
|
||||
minGroupWidth: 125,
|
||||
|
||||
|
@ -1640,9 +1660,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);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1709,6 +1738,30 @@ let GroupItems = {
|
|||
// 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 +1776,7 @@ let GroupItems = {
|
|||
$icon.attr("src", iconUrl);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: addAppTab
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -939,12 +939,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 = [];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -358,6 +358,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 +499,11 @@ let UI = {
|
|||
|
||||
self._resize(true);
|
||||
dispatchEvent(event);
|
||||
|
||||
// Flush pending updates
|
||||
GroupItems.flushAppTabUpdates();
|
||||
|
||||
TabItems.resumePainting();
|
||||
});
|
||||
} else {
|
||||
if (currentTab && currentTab._tabViewTabItem)
|
||||
|
@ -502,9 +511,12 @@ let UI = {
|
|||
|
||||
self.setActiveTab(null);
|
||||
dispatchEvent(event);
|
||||
}
|
||||
|
||||
TabItems.resumePainting();
|
||||
// Flush pending updates
|
||||
GroupItems.flushAppTabUpdates();
|
||||
|
||||
TabItems.resumePainting();
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -1180,9 +1192,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;
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
@ -79,11 +78,13 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug608037.js \
|
||||
browser_tabview_bug608158.js \
|
||||
browser_tabview_bug610242.js \
|
||||
browser_tabview_bug616967.js \
|
||||
browser_tabview_bug618828.js \
|
||||
browser_tabview_bug619937.js \
|
||||
browser_tabview_bug624265.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 \
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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,225 @@
|
|||
/* ***** 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;
|
||||
|
||||
// TODO: bug 625654
|
||||
todo_isnot(activeTab, originalTabItem, "But it's not what it was a moment ago.");
|
||||
let someChildIsActive = group.getChildren().some(function(child)
|
||||
child == activeTab);
|
||||
todo(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);
|
||||
|
||||
// TODO: bug 625654
|
||||
todo_isnot(win.gBrowser.selectedTab, originalTab, "We did not enter the original tab.");
|
||||
|
||||
let someChildIsSelected = group.getChildren().some(function(child)
|
||||
child.tab == win.gBrowser.selectedTab);
|
||||
todo(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);
|
||||
|
||||
// TODO: bug 625654
|
||||
let overlay = contentWindow.document.getElementById("expandedTray");
|
||||
todo(!group.expanded, "The group is no longer expanded.");
|
||||
todo(!overlay, "The expanded tray should be gone after looking at another tab.");
|
||||
todo_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -1498,8 +1504,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 +1621,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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Двоичные данные
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
|
||||
|
|
|
@ -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)
|
||||
|
|
49
configure.in
49
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
|
||||
|
@ -9485,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -456,6 +456,8 @@ _TEST_FILES2 = \
|
|||
test_bug622117.html \
|
||||
test_bug622246.html \
|
||||
test_bug484396.html \
|
||||
test_bug466080.html \
|
||||
bug466080.sjs \
|
||||
$(NULL)
|
||||
|
||||
# This test fails on the Mac for some reason
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var body = "loaded";
|
||||
var origin = "localhost";
|
||||
try {
|
||||
var origin = request.getHeader("Origin");
|
||||
} catch(e) {}
|
||||
|
||||
response.setHeader("Access-Control-Allow-Origin",
|
||||
origin,
|
||||
false);
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true", false);
|
||||
response.setHeader("Connection", "Keep-alive", false);
|
||||
|
||||
response.bodyOutputStream.write(body, body.length);
|
||||
}
|
|
@ -57,6 +57,8 @@ _CHROME_FILES = \
|
|||
title_window.xul \
|
||||
test_bug549682.xul \
|
||||
file_bug549682.xul \
|
||||
test_bug616841.xul \
|
||||
file_bug616841.xul \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=616841
|
||||
-->
|
||||
<window title="Mozilla Bug 616841"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="start()">
|
||||
<label value="Mozilla Bug 616841"/>
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
const FRAME_SCRIPT =
|
||||
"data:,addMessageListener(\n"+
|
||||
" 'cmp',\n"+
|
||||
" function (m) {\n"+
|
||||
" sendAsyncMessage('cmp', { i: m.json.i,\n"+
|
||||
" cmp: m.json.a.localeCompare(m.json.b) });\n"+
|
||||
" });\n"+
|
||||
"sendAsyncMessage('contentReady');";
|
||||
|
||||
var toCompare = [ [ "C", "D" ],
|
||||
[ "D", "C" ],
|
||||
[ "\u010C", "D" ],
|
||||
[ "D", "\u010C" ] ];
|
||||
var nCmps = 0;
|
||||
|
||||
function recvContentReady(m) {
|
||||
for (var i = 0; i < toCompare.length; ++i) {
|
||||
var pair = toCompare[i];
|
||||
messageManager.sendAsyncMessage("cmp",
|
||||
{ i: i, a: pair[0], b: pair[1] });
|
||||
}
|
||||
}
|
||||
|
||||
function recvCmp(m) {
|
||||
var i = m.json.i, cmp = m.json.cmp;
|
||||
var pair = toCompare[i];
|
||||
opener.wrappedJSObject.is(pair[0].localeCompare(pair[1]), cmp, "localeCompare returned same result in frame script");
|
||||
|
||||
if (toCompare.length == ++nCmps) {
|
||||
messageManager.removeMessageListener("cmp", recvCmp);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
messageManager.addMessageListener("contentReady", recvContentReady);
|
||||
messageManager.addMessageListener("cmp", recvCmp);
|
||||
messageManager.loadFrameScript(FRAME_SCRIPT, true);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
opener.setTimeout("done()", 0);
|
||||
window.close();
|
||||
}
|
||||
|
||||
]]></script>
|
||||
|
||||
<browser id="browser" type="content" src="about:blank"/>
|
||||
</window>
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=616841
|
||||
-->
|
||||
<window title="Mozilla Bug 616841"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=616841"
|
||||
target="_blank">Mozilla Bug 616841</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function done() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
window.open("file_bug616841.xul", "", "chrome");
|
||||
});
|
||||
]]></script>
|
||||
</window>
|
|
@ -53,7 +53,11 @@ function init_test() {
|
|||
}
|
||||
|
||||
function start_test(plugin) {
|
||||
is(plugin.description, "Plug-in for testing purposes.", "Test plugin had an incorrect description");
|
||||
is(plugin.description, "Plug-in for testing purposes.\u2122 " +
|
||||
"(\u0939\u093f\u0928\u094d\u0926\u0940 " +
|
||||
"\u4e2d\u6587 " +
|
||||
"\u0627\u0644\u0639\u0631\u0628\u064a\u0629)",
|
||||
"Test plugin had an incorrect description");
|
||||
is(plugin.version, "1.0.0.0", "Test plugin had an incorrect version");
|
||||
ok(!plugin.disabled, "Test plugin should not be disabled");
|
||||
ok(!plugin.blocklisted, "Test plugin should not be blocklisted");
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test bug 466080</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="onWindowLoad()">
|
||||
<iframe id="frame1"
|
||||
src="https://requireclientcert.example.com/tests/content/base/test/bug466080.sjs"
|
||||
onload="document.iframeWasLoaded = true">
|
||||
|
||||
This iframe should load the resource via the src-attribute from
|
||||
a secure server which requires a client-cert. Doing this is
|
||||
supposed to work, but further below in the test we try to load
|
||||
the resource from the same url using a XHR, which should not work.
|
||||
|
||||
TODO : What if we change 'src' from JS? Would/should it load?
|
||||
|
||||
</iframe>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
document.iframeWasLoaded = false;
|
||||
|
||||
var alltests = [
|
||||
|
||||
// load resource from a relative url - this should work
|
||||
{ url:"bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR from relative URL"},
|
||||
|
||||
// TODO - load the resource from a relative url via https..?
|
||||
|
||||
// load a non-existing resource - should get "404 Not Found"
|
||||
{ url:"bug466080-does-not.exist",
|
||||
status_check:"==404",
|
||||
error:"XHR loading non-existing resource"},
|
||||
|
||||
// load resource from cross-site non-secure server
|
||||
{ url:"http://test1.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR from cross-site plaintext server"},
|
||||
|
||||
// load resource from cross-site secure server - should work since no credentials are needed
|
||||
{ url:"https://test1.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR from cross-site secure server"},
|
||||
|
||||
// load resource from cross-site secure server - should work since the server just requests certs
|
||||
{ url:"https://requestclientcert.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR from cross-site secure server requesting certificate"},
|
||||
|
||||
// load resource from cross-site secure server - should NOT work since the server requires cert
|
||||
// note that this is the url which is used in the iframe.src above
|
||||
{ url:"https://requireclientcert.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"!=200",
|
||||
error:"XHR from cross-site secure server requiring certificate"},
|
||||
|
||||
// repeat previous, - should NOT work
|
||||
{ url:"https://requireclientcert.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR w/ credentials from cross-site secure server requiring certificate",
|
||||
withCredentials:"true"},
|
||||
|
||||
// repeat previous, but with credentials - should work
|
||||
{ url:"https://requireclientcert.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"==200",
|
||||
error:"XHR w/ credentials from cross-site secure server requiring certificate",
|
||||
withCredentials:"true"},
|
||||
|
||||
// repeat previous, withCredentials but using a weird method to force preflight
|
||||
// should NOT work since our preflight is anonymous and will fail with our simple server
|
||||
{ url:"https://requireclientcert.example.com/tests/content/base/test/bug466080.sjs",
|
||||
status_check:"!=200",
|
||||
error:"XHR PREFLIGHT from cross-site secure server requiring certificate",
|
||||
withCredentials:"true",
|
||||
method:"XMETHOD"},
|
||||
|
||||
];
|
||||
|
||||
function onWindowLoad() {
|
||||
// First, check that resource was loaded into the iframe
|
||||
// This check in fact depends on bug #444165... :)
|
||||
ok(document.iframeWasLoaded, "Loading resource via src-attribute");
|
||||
|
||||
|
||||
for each (test in alltests) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
var method = "GET";
|
||||
if (test.method != null) { method = test.method; }
|
||||
xhr.open(method, test.url, false);
|
||||
|
||||
xhr.withCredentials = test.withCredentials;
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
xhr.setRequestHeader("Connection", "Keep-Alive", false);
|
||||
netscape.security.PrivilegeManager.disablePrivilege("UniversalXPConnect");
|
||||
|
||||
try {
|
||||
xhr.send();
|
||||
} catch(e) {
|
||||
}
|
||||
var success = eval(xhr.status + test.status_check);
|
||||
ok(success, test.error);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -6,4 +6,5 @@ conformance/gl-uniform-bool.html
|
|||
conformance/gl-vertexattribpointer.html
|
||||
conformance/glsl-2types-of-textures-on-same-unit.html
|
||||
conformance/is-object.html
|
||||
conformance/tex-image-and-sub-image-2d-with-array-buffer-view.html
|
||||
conformance/uninitialized-test.html
|
||||
|
|
|
@ -31,27 +31,88 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
|||
var keyPress = 0;
|
||||
var keyUp = 0;
|
||||
|
||||
function suppressEventHandling(aSuppress) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
ok(true, "suppressEventHandling: aSuppress=" + aSuppress);
|
||||
utils.suppressEventHandling(aSuppress);
|
||||
}
|
||||
|
||||
function dispatchKeyEvent(type) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
ok(true, "Dipatching key event: type=" + type);
|
||||
utils.sendKeyEvent(type,
|
||||
Components.interfaces.nsIDOMKeyEvent.DOM_VK_A,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
function dispatchMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
win.document.getElementsByTagName("input")[0].focus();
|
||||
win.addEventListener("keydown", function(e) { ++keyDown; }, true);
|
||||
win.addEventListener("keypress", function(e) { ++keyPress; }, true);
|
||||
win.addEventListener("keyup", function(e) { ++keyUp; }, true);
|
||||
win.addEventListener("mousedown", function(e) { ++mouseDown; }, true);
|
||||
win.addEventListener("mouseup", function(e) { ++mouseUp; }, true);
|
||||
win.addEventListener("click", function(e) { ++mouseClick; }, true);
|
||||
ok(true, "Dipatching mouse event: aType=" + aType + ", aX=" + aX + ", aY" +
|
||||
aY + ", aButton=" + aButton + ", aClickCount=" + aClickCount +
|
||||
", aModifiers=" + aModifiers);
|
||||
utils.sendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers);
|
||||
}
|
||||
|
||||
function dumpEvent(aEvent) {
|
||||
var detail = "target=" + aEvent.target + ", originalTarget=" +
|
||||
aEvent.originalTarget + ", getPreventDefault()=" +
|
||||
aEvent.getPreventDefault() + ", isTrusted=" + aEvent.isTrusted;
|
||||
switch (aEvent.type) {
|
||||
case "keydown":
|
||||
case "keypress":
|
||||
case "keyup":
|
||||
detail += ", charCode=0x" + aEvent.charCode.toString(16) +
|
||||
", keyCode=0x" + aEvent.keyCode.toString(16) +
|
||||
", altKey=" + (aEvent.altKey ? "PRESSED" : "no") +
|
||||
", ctrlKey=" + (aEvent.ctrlKey ? "PRESSED" : "no") +
|
||||
", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
|
||||
", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no");
|
||||
break;
|
||||
case "mousedown":
|
||||
case "mouseup":
|
||||
case "click":
|
||||
detail += ", screenX=" + aEvent.screenX + ", screenY=" + aEvent.screenY +
|
||||
", clientX=" + aEvent.clientX + ", clientY=" + aEvent.clientY +
|
||||
", altKey=" + (aEvent.altKey ? "PRESSED" : "no") +
|
||||
", ctrlKey=" + (aEvent.ctrlKey ? "PRESSED" : "no") +
|
||||
", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
|
||||
", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no") +
|
||||
", button=" + aEvent.button +
|
||||
", relatedTarget=" + aEvent.relatedTarget;
|
||||
break;
|
||||
}
|
||||
ok(true, aEvent.type + " event is handled: " + detail);
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var fm = Components.classes["@mozilla.org/focus-manager;1"].
|
||||
getService(Components.interfaces.nsIFocusManager);
|
||||
ok(true, "focused element is \"" + fm.focusedElement +
|
||||
"\" and focused window is \"" + fm.focusedWindow +
|
||||
"\" (the testing window is \"" + win + "\"");
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
win.document.getElementsByTagName("input")[0].focus();
|
||||
win.addEventListener("keydown",
|
||||
function(e) { dumpEvent(e); ++keyDown; }, true);
|
||||
win.addEventListener("keypress",
|
||||
function(e) { dumpEvent(e); ++keyPress; }, true);
|
||||
win.addEventListener("keyup",
|
||||
function(e) { dumpEvent(e); ++keyUp; }, true);
|
||||
win.addEventListener("mousedown",
|
||||
function(e) { dumpEvent(e); ++mouseDown; }, true);
|
||||
win.addEventListener("mouseup",
|
||||
function(e) { dumpEvent(e); ++mouseUp; }, true);
|
||||
win.addEventListener("click",
|
||||
function(e) { dumpEvent(e); ++mouseClick; }, true);
|
||||
|
||||
ok(true, "doTest #1...");
|
||||
dispatchKeyEvent("keydown");
|
||||
dispatchKeyEvent("keypress");
|
||||
dispatchKeyEvent("keyup");
|
||||
|
@ -59,14 +120,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
|||
is(keyPress, 1, "Wrong number events (2)");
|
||||
is(keyUp, 1, "Wrong number events (3)");
|
||||
|
||||
utils.suppressEventHandling(true);
|
||||
ok(true, "doTest #2...");
|
||||
suppressEventHandling(true);
|
||||
dispatchKeyEvent("keydown");
|
||||
dispatchKeyEvent("keypress");
|
||||
dispatchKeyEvent("keyup");
|
||||
is(keyDown, 1, "Wrong number events (4)");
|
||||
is(keyPress, 1, "Wrong number events (5)");
|
||||
is(keyUp, 1, "Wrong number events (6)");
|
||||
utils.suppressEventHandling(false);
|
||||
suppressEventHandling(false);
|
||||
is(keyDown, 1, "Wrong number events (7)");
|
||||
is(keyPress, 1, "Wrong number events (8)");
|
||||
is(keyUp, 1, "Wrong number events (9)");
|
||||
|
@ -75,38 +137,35 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
|||
}
|
||||
|
||||
function continueTest1() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
ok(true, "continueTest1...");
|
||||
dispatchKeyEvent("keydown");
|
||||
utils.suppressEventHandling(true);
|
||||
suppressEventHandling(true);
|
||||
dispatchKeyEvent("keypress");
|
||||
dispatchKeyEvent("keyup");
|
||||
is(keyDown, 2, "Wrong number events (10)");
|
||||
is(keyPress, 1, "Wrong number events (11)");
|
||||
is(keyUp, 1, "Wrong number events (12)");
|
||||
utils.suppressEventHandling(false);
|
||||
suppressEventHandling(false);
|
||||
setTimeout(continueTest2, 0);
|
||||
}
|
||||
|
||||
function continueTest2() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
ok(true, "continueTest2 #1...");
|
||||
is(keyDown, 2, "Wrong number events (13)");
|
||||
is(keyPress, 2, "Wrong number events (14)");
|
||||
is(keyUp, 2, "Wrong number events (15)");
|
||||
|
||||
utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
is(mouseDown, 1, "Wrong number events (16)");
|
||||
is(mouseUp, 1, "Wrong number events (17)");
|
||||
is(mouseClick, 1, "Wrong number events (18)");
|
||||
|
||||
utils.suppressEventHandling(true);
|
||||
utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
utils.suppressEventHandling(false);
|
||||
ok(true, "continueTest2 #2...");
|
||||
suppressEventHandling(true);
|
||||
dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
suppressEventHandling(false);
|
||||
is(mouseDown, 1, "Wrong number events (19)");
|
||||
is(mouseUp, 1, "Wrong number events (20)");
|
||||
is(mouseClick, 1, "Wrong number events (21)");
|
||||
|
@ -115,17 +174,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
|||
}
|
||||
|
||||
function continueTest3() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
utils.suppressEventHandling(true);
|
||||
utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
utils.suppressEventHandling(false);
|
||||
ok(true, "continueTest3...");
|
||||
dispatchMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
suppressEventHandling(true);
|
||||
dispatchMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
suppressEventHandling(false);
|
||||
setTimeout(continueTest4, 1000);
|
||||
}
|
||||
|
||||
function continueTest4() {
|
||||
ok(true, "continueTest4...");
|
||||
is(mouseDown, 2, "Wrong number events (19)");
|
||||
is(mouseUp, 2, "Wrong number events (20)");
|
||||
is(mouseClick, 2, "Wrong number events (21)");
|
||||
|
|
|
@ -578,7 +578,7 @@ protected:
|
|||
LoadAlgorithmState mLoadWaitStatus;
|
||||
|
||||
// Current audio volume
|
||||
float mVolume;
|
||||
double mVolume;
|
||||
|
||||
// Current number of audio channels.
|
||||
PRUint32 mChannels;
|
||||
|
@ -608,7 +608,7 @@ protected:
|
|||
|
||||
// Media 'currentTime' value when the last timeupdate event occurred.
|
||||
// Read/Write from the main thread only.
|
||||
float mLastCurrentTime;
|
||||
double mLastCurrentTime;
|
||||
|
||||
nsRefPtr<gfxASurface> mPrintSurface;
|
||||
|
||||
|
|
|
@ -1072,14 +1072,14 @@ NS_IMETHODIMP nsHTMLMediaElement::GetSeeking(PRBool *aSeeking)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute float currentTime; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetCurrentTime(float *aCurrentTime)
|
||||
/* attribute double currentTime; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetCurrentTime(double *aCurrentTime)
|
||||
{
|
||||
*aCurrentTime = mDecoder ? mDecoder->GetCurrentTime() : 0.0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
|
||||
NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime)
|
||||
{
|
||||
StopSuspendingAfterFirstFrame();
|
||||
|
||||
|
@ -1100,8 +1100,8 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
|
|||
}
|
||||
|
||||
// Clamp the time to [0, duration] as required by the spec
|
||||
float clampedTime = NS_MAX(0.0f, aCurrentTime);
|
||||
float duration = mDecoder->GetDuration();
|
||||
double clampedTime = NS_MAX(0.0, aCurrentTime);
|
||||
double duration = mDecoder->GetDuration();
|
||||
if (duration >= 0) {
|
||||
clampedTime = NS_MIN(clampedTime, duration);
|
||||
}
|
||||
|
@ -1118,10 +1118,10 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
|
|||
return rv;
|
||||
}
|
||||
|
||||
/* readonly attribute float duration; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetDuration(float *aDuration)
|
||||
/* readonly attribute double duration; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetDuration(double *aDuration)
|
||||
{
|
||||
*aDuration = mDecoder ? mDecoder->GetDuration() : std::numeric_limits<float>::quiet_NaN();
|
||||
*aDuration = mDecoder ? mDecoder->GetDuration() : std::numeric_limits<double>::quiet_NaN();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1158,15 +1158,15 @@ NS_IMETHODIMP nsHTMLMediaElement::Pause()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute float volume; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetVolume(float *aVolume)
|
||||
/* attribute double volume; */
|
||||
NS_IMETHODIMP nsHTMLMediaElement::GetVolume(double *aVolume)
|
||||
{
|
||||
*aVolume = mVolume;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLMediaElement::SetVolume(float aVolume)
|
||||
NS_IMETHODIMP nsHTMLMediaElement::SetVolume(double aVolume)
|
||||
{
|
||||
if (aVolume < 0.0f || aVolume > 1.0f)
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
|
@ -1815,7 +1815,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
float duration = aOriginal->GetDuration();
|
||||
double duration = aOriginal->GetDuration();
|
||||
if (duration >= 0) {
|
||||
decoder->SetDuration(PRInt64(NS_round(duration * 1000)));
|
||||
decoder->SetSeekable(aOriginal->GetSeekable());
|
||||
|
@ -2592,7 +2592,7 @@ void nsHTMLMediaElement::FireTimeUpdate(PRBool aPeriodic)
|
|||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
float time = 0;
|
||||
double time = 0;
|
||||
GetCurrentTime(&time);
|
||||
|
||||
// Fire a timupdate event if this is not a periodic update (i.e. it's a
|
||||
|
|
|
@ -639,7 +639,7 @@ protected:
|
|||
|
||||
protected:
|
||||
|
||||
nsTextControlFrame* mFrame; // weak reference
|
||||
nsWeakFrame mFrame;
|
||||
|
||||
nsITextControlElement* const mTxtCtrlElement;
|
||||
|
||||
|
@ -667,8 +667,7 @@ protected:
|
|||
*/
|
||||
|
||||
nsTextInputListener::nsTextInputListener(nsITextControlElement* aTxtCtrlElement)
|
||||
: mFrame(nsnull)
|
||||
, mTxtCtrlElement(aTxtCtrlElement)
|
||||
: mTxtCtrlElement(aTxtCtrlElement)
|
||||
, mSelectionWasCollapsed(PR_TRUE)
|
||||
, mHadUndoItems(PR_FALSE)
|
||||
, mHadRedoItems(PR_FALSE)
|
||||
|
@ -698,7 +697,7 @@ NS_IMETHODIMP
|
|||
nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel, PRInt16 aReason)
|
||||
{
|
||||
PRBool collapsed;
|
||||
if (!mFrame || !aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
|
||||
if (!mFrame.IsAlive() || !aDoc || !aSel || NS_FAILED(aSel->GetIsCollapsed(&collapsed)))
|
||||
return NS_OK;
|
||||
|
||||
// Fire the select event
|
||||
|
@ -743,7 +742,7 @@ nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection*
|
|||
|
||||
mSelectionWasCollapsed = collapsed;
|
||||
|
||||
if (!mFrame || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
|
||||
if (!mFrame.IsAlive() || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
|
||||
return NS_OK;
|
||||
|
||||
return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
|
||||
|
@ -794,6 +793,7 @@ DoCommandCallback(const char *aCommand, void *aData)
|
|||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyDown(nsIDOMEvent *aDOMEvent)
|
||||
{
|
||||
NS_ENSURE_STATE(mFrame.IsAlive());
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
|
||||
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
@ -812,6 +812,7 @@ nsTextInputListener::KeyDown(nsIDOMEvent *aDOMEvent)
|
|||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyPress(nsIDOMEvent *aDOMEvent)
|
||||
{
|
||||
NS_ENSURE_STATE(mFrame.IsAlive());
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
|
||||
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
@ -830,6 +831,7 @@ nsTextInputListener::KeyPress(nsIDOMEvent *aDOMEvent)
|
|||
NS_IMETHODIMP
|
||||
nsTextInputListener::KeyUp(nsIDOMEvent *aDOMEvent)
|
||||
{
|
||||
NS_ENSURE_STATE(mFrame.IsAlive());
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aDOMEvent));
|
||||
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
@ -851,11 +853,15 @@ nsTextInputListener::KeyUp(nsIDOMEvent *aDOMEvent)
|
|||
NS_IMETHODIMP
|
||||
nsTextInputListener::EditAction()
|
||||
{
|
||||
NS_ENSURE_STATE(mFrame.IsAlive());
|
||||
nsITextControlFrame* frameBase = do_QueryFrame(mFrame.GetFrame());
|
||||
nsTextControlFrame* frame = static_cast<nsTextControlFrame*> (frameBase);
|
||||
NS_ASSERTION(frame, "Where is our frame?");
|
||||
//
|
||||
// Update the undo / redo menus
|
||||
//
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
mFrame->GetEditor(getter_AddRefs(editor));
|
||||
frame->GetEditor(getter_AddRefs(editor));
|
||||
|
||||
nsCOMPtr<nsITransactionManager> manager;
|
||||
editor->GetTransactionManager(getter_AddRefs(manager));
|
||||
|
@ -875,9 +881,13 @@ nsTextInputListener::EditAction()
|
|||
mHadRedoItems = numRedoItems != 0;
|
||||
}
|
||||
|
||||
if (!mFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure we know we were changed (do NOT set this to false if there are
|
||||
// no undo items; JS could change the value and we'd still need to save it)
|
||||
mFrame->SetValueChanged(PR_TRUE);
|
||||
frame->SetValueChanged(PR_TRUE);
|
||||
|
||||
if (!mSettingValue) {
|
||||
mTxtCtrlElement->OnValueChanged(PR_TRUE);
|
||||
|
@ -888,7 +898,10 @@ nsTextInputListener::EditAction()
|
|||
NS_ASSERTION(editor20, "Something is very wrong!");
|
||||
PRBool trusted = PR_FALSE;
|
||||
editor20->GetLastKeypressEventTrusted(&trusted);
|
||||
mFrame->FireOnInput(trusted);
|
||||
frame->FireOnInput(trusted);
|
||||
|
||||
// mFrame may be dead after this, but we don't need to check for it, because
|
||||
// we are not uisng it in this function any more.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -899,7 +912,7 @@ nsTextInputListener::EditAction()
|
|||
nsresult
|
||||
nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
|
||||
{
|
||||
NS_ENSURE_STATE(mFrame);
|
||||
NS_ENSURE_STATE(mFrame.IsAlive());
|
||||
|
||||
nsIContent* content = mFrame->GetContent();
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
|
||||
|
|
|
@ -58,7 +58,7 @@ nsTimeRanges::GetLength(PRUint32* aLength) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimeRanges::Start(PRUint32 aIndex, float* aTime) {
|
||||
nsTimeRanges::Start(PRUint32 aIndex, double* aTime) {
|
||||
if (aIndex >= mRanges.Length())
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
*aTime = mRanges[aIndex].mStart;
|
||||
|
@ -66,7 +66,7 @@ nsTimeRanges::Start(PRUint32 aIndex, float* aTime) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTimeRanges::End(PRUint32 aIndex, float* aTime) {
|
||||
nsTimeRanges::End(PRUint32 aIndex, double* aTime) {
|
||||
if (aIndex >= mRanges.Length())
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
*aTime = mRanges[aIndex].mEnd;
|
||||
|
@ -74,6 +74,6 @@ nsTimeRanges::End(PRUint32 aIndex, float* aTime) {
|
|||
}
|
||||
|
||||
void
|
||||
nsTimeRanges::Add(float aStart, float aEnd) {
|
||||
nsTimeRanges::Add(double aStart, double aEnd) {
|
||||
mRanges.AppendElement(TimeRange(aStart,aEnd));
|
||||
}
|
||||
|
|
|
@ -47,16 +47,16 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMTIMERANGES
|
||||
|
||||
void Add(float aStart, float aEnd);
|
||||
void Add(double aStart, double aEnd);
|
||||
|
||||
private:
|
||||
|
||||
struct TimeRange {
|
||||
TimeRange(float aStart, float aEnd)
|
||||
TimeRange(double aStart, double aEnd)
|
||||
: mStart(aStart),
|
||||
mEnd(aEnd) {}
|
||||
float mStart;
|
||||
float mEnd;
|
||||
double mStart;
|
||||
double mEnd;
|
||||
};
|
||||
|
||||
nsAutoTArray<TimeRange,4> mRanges;
|
||||
|
|
|
@ -378,16 +378,6 @@ nsHTMLDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
SetContentTypeInternal(nsDependentCString("text/html"));
|
||||
}
|
||||
|
||||
nsStyleSet::sheetType
|
||||
nsHTMLDocument::GetAttrSheetType()
|
||||
{
|
||||
if (IsHTML()) {
|
||||
return nsStyleSet::eHTMLPresHintSheet;
|
||||
}
|
||||
|
||||
return nsDocument::GetAttrSheetType();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLDocument::CreateShell(nsPresContext* aContext,
|
||||
nsIViewManager* aViewManager,
|
||||
|
@ -3318,7 +3308,7 @@ nsHTMLDocument::EditingStateChanged()
|
|||
|
||||
// If we're entering the design mode, put the selection at the beginning of
|
||||
// the document for compatibility reasons.
|
||||
if (designMode) {
|
||||
if (designMode && oldState == eOff) {
|
||||
rv = editor->BeginningOfDocument();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
|
|
@ -85,7 +85,6 @@ public:
|
|||
virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
|
||||
virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
|
||||
nsIPrincipal* aPrincipal);
|
||||
virtual nsStyleSet::sheetType GetAttrSheetType();
|
||||
|
||||
virtual nsresult CreateShell(nsPresContext* aContext,
|
||||
nsIViewManager* aViewManager,
|
||||
|
|
|
@ -62,6 +62,12 @@ extern "C" {
|
|||
#define SA_PER_STREAM_VOLUME 1
|
||||
#endif
|
||||
|
||||
// Android's audio backend is not available in content processes, so audio must
|
||||
// be remoted to the parent chrome process.
|
||||
#if defined(ANDROID) && defined(MOZ_IPC)
|
||||
#define REMOTE_AUDIO 1
|
||||
#endif
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -83,7 +89,7 @@ class nsAudioStreamLocal : public nsAudioStream
|
|||
void Shutdown();
|
||||
nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
|
||||
PRUint32 Available();
|
||||
void SetVolume(float aVolume);
|
||||
void SetVolume(double aVolume);
|
||||
void Drain();
|
||||
void Pause();
|
||||
void Resume();
|
||||
|
@ -128,7 +134,7 @@ class nsAudioStreamRemote : public nsAudioStream
|
|||
void Shutdown();
|
||||
nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
|
||||
PRUint32 Available();
|
||||
void SetVolume(float aVolume);
|
||||
void SetVolume(double aVolume);
|
||||
void Drain();
|
||||
void Pause();
|
||||
void Resume();
|
||||
|
@ -203,10 +209,10 @@ class AudioWriteEvent : public nsRunnable
|
|||
class AudioSetVolumeEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
AudioSetVolumeEvent(AudioChild* aChild, float volume)
|
||||
AudioSetVolumeEvent(AudioChild* aChild, double aVolume)
|
||||
{
|
||||
mAudioChild = aChild;
|
||||
mVolume = volume;
|
||||
mVolume = aVolume;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
|
@ -219,7 +225,7 @@ class AudioSetVolumeEvent : public nsRunnable
|
|||
}
|
||||
|
||||
nsRefPtr<AudioChild> mAudioChild;
|
||||
float mVolume;
|
||||
double mVolume;
|
||||
};
|
||||
|
||||
class AudioDrainEvent : public nsRunnable
|
||||
|
@ -312,7 +318,7 @@ nsAudioStream::GetThread()
|
|||
|
||||
nsAudioStream* nsAudioStream::AllocateStream()
|
||||
{
|
||||
#ifdef MOZ_IPC
|
||||
#if defined(REMOTE_AUDIO)
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
return new nsAudioStreamRemote();
|
||||
}
|
||||
|
@ -491,7 +497,7 @@ PRUint32 nsAudioStreamLocal::Available()
|
|||
return s / sizeof(short);
|
||||
}
|
||||
|
||||
void nsAudioStreamLocal::SetVolume(float aVolume)
|
||||
void nsAudioStreamLocal::SetVolume(double aVolume)
|
||||
{
|
||||
NS_ASSERTION(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
|
||||
#if defined(SA_PER_STREAM_VOLUME)
|
||||
|
@ -673,7 +679,7 @@ PRInt32 nsAudioStreamRemote::GetMinWriteSamples()
|
|||
}
|
||||
|
||||
void
|
||||
nsAudioStreamRemote::SetVolume(float aVolume)
|
||||
nsAudioStreamRemote::SetVolume(double aVolume)
|
||||
{
|
||||
if (!mAudioChild)
|
||||
return;
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
|
||||
// Set the current volume of the audio playback. This is a value from
|
||||
// 0 (meaning muted) to 1 (meaning full volume).
|
||||
virtual void SetVolume(float aVolume) = 0;
|
||||
virtual void SetVolume(double aVolume) = 0;
|
||||
|
||||
// Block until buffered audio data has been consumed.
|
||||
virtual void Drain() = 0;
|
||||
|
|
|
@ -70,22 +70,22 @@ void nsBuiltinDecoder::Pause()
|
|||
ChangeState(PLAY_STATE_PAUSED);
|
||||
}
|
||||
|
||||
void nsBuiltinDecoder::SetVolume(float volume)
|
||||
void nsBuiltinDecoder::SetVolume(double aVolume)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
mInitialVolume = volume;
|
||||
mInitialVolume = aVolume;
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->SetVolume(volume);
|
||||
mDecoderStateMachine->SetVolume(aVolume);
|
||||
}
|
||||
}
|
||||
|
||||
float nsBuiltinDecoder::GetDuration()
|
||||
double nsBuiltinDecoder::GetDuration()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (mDuration >= 0) {
|
||||
return static_cast<float>(mDuration) / 1000.0;
|
||||
return static_cast<double>(mDuration) / 1000.0;
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
nsBuiltinDecoder::nsBuiltinDecoder() :
|
||||
|
@ -256,7 +256,7 @@ nsresult nsBuiltinDecoder::Play()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBuiltinDecoder::Seek(float aTime)
|
||||
nsresult nsBuiltinDecoder::Seek(double aTime)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
MonitorAutoEnter mon(mMonitor);
|
||||
|
@ -289,7 +289,7 @@ nsresult nsBuiltinDecoder::PlaybackRateChanged()
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
float nsBuiltinDecoder::GetCurrentTime()
|
||||
double nsBuiltinDecoder::GetCurrentTime()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
return mCurrentTime;
|
||||
|
@ -599,6 +599,7 @@ void nsBuiltinDecoder::NotifyBytesConsumed(PRInt64 aBytes)
|
|||
"Should be on play state machine or decode thread.");
|
||||
if (!mIgnoreProgressData) {
|
||||
mDecoderPosition += aBytes;
|
||||
mPlaybackStatistics.AddBytes(aBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -757,7 +758,7 @@ void nsBuiltinDecoder::PlaybackPositionChanged()
|
|||
if (mShuttingDown)
|
||||
return;
|
||||
|
||||
float lastTime = mCurrentTime;
|
||||
double lastTime = mCurrentTime;
|
||||
|
||||
// Control the scope of the monitor so it is not
|
||||
// held while the timeupdate and the invalidate is run.
|
||||
|
|
|
@ -117,7 +117,7 @@ Buffer
|
|||
Complete
|
||||
This is not user initiated. It occurs when the
|
||||
stream is completely decoded.
|
||||
Seek(float)
|
||||
Seek(double)
|
||||
Seek to the time position given in the resource.
|
||||
|
||||
A state transition diagram:
|
||||
|
@ -245,7 +245,7 @@ public:
|
|||
|
||||
// Set the audio volume. The decoder monitor must be obtained before
|
||||
// calling this.
|
||||
virtual void SetVolume(float aVolume) = 0;
|
||||
virtual void SetVolume(double aVolume) = 0;
|
||||
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
|
@ -271,12 +271,12 @@ public:
|
|||
virtual void Decode() = 0;
|
||||
|
||||
// Seeks to aTime in seconds
|
||||
virtual void Seek(float aTime) = 0;
|
||||
virtual void Seek(double aTime) = 0;
|
||||
|
||||
// Returns the current playback position in seconds.
|
||||
// Called from the main thread to get the current frame time. The decoder
|
||||
// monitor must be obtained before calling this.
|
||||
virtual float GetCurrentTime() = 0;
|
||||
virtual double GetCurrentTime() = 0;
|
||||
|
||||
// Clear the flag indicating that a playback position change event
|
||||
// is currently queued. This is called from the main thread and must
|
||||
|
@ -303,6 +303,8 @@ public:
|
|||
// with the decode monitor held. Called on the state machine thread and
|
||||
// the main thread.
|
||||
virtual void StartBuffering() = 0;
|
||||
|
||||
virtual void NotifyDataExhausted() = 0;
|
||||
};
|
||||
|
||||
class nsBuiltinDecoder : public nsMediaDecoder
|
||||
|
@ -336,7 +338,7 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
// object disposes of this decoder object.
|
||||
virtual void Shutdown();
|
||||
|
||||
virtual float GetCurrentTime();
|
||||
virtual double GetCurrentTime();
|
||||
|
||||
virtual nsresult Load(nsMediaStream* aStream,
|
||||
nsIStreamListener** aListener,
|
||||
|
@ -349,13 +351,13 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
virtual nsresult Play();
|
||||
|
||||
// Seek to the time position in (seconds) from the start of the video.
|
||||
virtual nsresult Seek(float time);
|
||||
virtual nsresult Seek(double aTime);
|
||||
|
||||
virtual nsresult PlaybackRateChanged();
|
||||
|
||||
virtual void Pause();
|
||||
virtual void SetVolume(float volume);
|
||||
virtual float GetDuration();
|
||||
virtual void SetVolume(double aVolume);
|
||||
virtual double GetDuration();
|
||||
|
||||
virtual nsMediaStream* GetCurrentStream();
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
||||
|
@ -367,6 +369,10 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
// from the resource.
|
||||
void NotifyBytesConsumed(PRInt64 aBytes);
|
||||
|
||||
void NotifyDataExhausted() {
|
||||
mDecoderStateMachine->NotifyDataExhausted();
|
||||
}
|
||||
|
||||
// Called when the video file has completed downloading.
|
||||
// Call on the main thread only.
|
||||
void ResourceLoaded();
|
||||
|
@ -575,18 +581,18 @@ public:
|
|||
// seconds. This is updated approximately at the framerate of the
|
||||
// video (if it is a video) or the callback period of the audio.
|
||||
// It is read and written from the main thread only.
|
||||
float mCurrentTime;
|
||||
double mCurrentTime;
|
||||
|
||||
// Volume that playback should start at. 0.0 = muted. 1.0 = full
|
||||
// volume. Readable/Writeable from the main thread.
|
||||
float mInitialVolume;
|
||||
double mInitialVolume;
|
||||
|
||||
// Position to seek to when the seek notification is received by the
|
||||
// decode thread. Written by the main thread and read via the
|
||||
// decode thread. Synchronised using mMonitor. If the
|
||||
// value is negative then no seek has been requested. When a seek is
|
||||
// started this is reset to negative.
|
||||
float mRequestedSeekTime;
|
||||
double mRequestedSeekTime;
|
||||
|
||||
// Duration of the media resource. Set to -1 if unknown.
|
||||
// Set when the metadata is loaded. Accessed on the main thread
|
||||
|
|
|
@ -341,7 +341,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
|
|||
nsAutoPtr<VideoData> video(mVideoQueue.PeekFront());
|
||||
// If the frame end time is less than the seek target, we won't want
|
||||
// to display this frame after the seek, so discard it.
|
||||
if (video && video->mEndTime < aTarget) {
|
||||
if (video && video->mEndTime <= aTarget) {
|
||||
if (startTime == -1) {
|
||||
startTime = video->mTime;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче