Merge tracemonkey to mozilla-central. (a=blockers)

This commit is contained in:
Chris Leary 2011-01-18 11:19:21 -08:00
Родитель d3f301da5d 091a495e25
Коммит 04ffe6d2a0
332 изменённых файлов: 9436 добавлений и 4270 удалений

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

@ -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'>&nbsp;</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 &#x0022;My Sync Key&#x0022; under &#x0022;Manage Account&#x0022;.">
<!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;
}

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

До

Ширина:  |  Высота:  |  Размер: 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 {

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

До

Ширина:  |  Высота:  |  Размер: 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,

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

До

Ширина:  |  Высота:  |  Размер: 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)

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

@ -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;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше