Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2016-08-09 15:48:42 +02:00
commit b3ea5e55df
561 changed files with 6401 additions and 4470 deletions

View File

@ -122,6 +122,7 @@ devtools/server/actors/**
devtools/server/performance/**
devtools/server/tests/**
devtools/shared/*.js
!devtools/shared/async-storage.js
!devtools/shared/async-utils.js
!devtools/shared/css-lexer.js
!devtools/shared/defer.js

View File

@ -89,6 +89,16 @@ void
DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
nsIDocument* aDOMDocument)
{
// We need to remove listeners in both cases, when document is being shutdown
// or when accessibility service is being shut down as well.
RemoveListeners(aDOMDocument);
// Document will already be removed when accessibility service is shutting
// down so we do not need to remove it twice.
if (nsAccessibilityService::IsShutdown()) {
return;
}
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
if (xpcDoc) {
xpcDoc->Shutdown();
@ -96,7 +106,6 @@ DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
}
mDocAccessibleCache.Remove(aDOMDocument);
RemoveListeners(aDOMDocument);
}
void
@ -530,9 +539,6 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
void
DocManager::ClearDocCache()
{
// This unusual do-one-element-per-iterator approach is required because each
// DocAccessible is removed elsewhere upon its Shutdown() method being
// called, which invalidates the existing iterator.
while (mDocAccessibleCache.Count() > 0) {
auto iter = mDocAccessibleCache.Iter();
MOZ_ASSERT(!iter.Done());
@ -542,7 +548,23 @@ DocManager::ClearDocCache()
if (docAcc) {
docAcc->Shutdown();
}
iter.Remove();
}
// Ensure that all xpcom accessible documents are shut down as well.
while (mXPCDocumentCache.Count() > 0) {
auto iter = mXPCDocumentCache.Iter();
MOZ_ASSERT(!iter.Done());
xpcAccessibleDocument* xpcDoc = iter.UserData();
NS_ASSERTION(xpcDoc, "No xpc doc for the object in xpc doc cache!");
if (xpcDoc) {
xpcDoc->Shutdown();
}
iter.Remove();
}
}
void

View File

@ -219,24 +219,6 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
mDocument->AddScrollListener();
// 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.
for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) {
mDocument->ProcessContentInserted(iter.Key(), iter.UserData());
if (!mDocument) {
return;
}
}
mContentInsertions.Clear();
// Process rendered text change notifications.
for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
@ -311,17 +293,27 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
}
#endif
// Make sure the text node is in accessible document still.
Accessible* container = mDocument->AccessibleOrTrueContainer(containerNode);
MOZ_ASSERT(container,
"Text node having rendered text hasn't accessible document!");
if (container) {
mDocument->ProcessContentInserted(container, textNode);
nsTArray<nsCOMPtr<nsIContent>>* list =
mContentInsertions.LookupOrAdd(container);
list->AppendElement(textNode);
}
}
}
mTextHash.Clear();
// Process content inserted notifications to update the tree.
for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) {
mDocument->ProcessContentInserted(iter.Key(), iter.UserData());
if (!mDocument) {
return;
}
}
mContentInsertions.Clear();
// Bind hanging child documents.
uint32_t hangingDocCnt = mHangingChildDocuments.Length();
nsTArray<RefPtr<DocAccessible>> newChildDocs;

View File

@ -20,7 +20,6 @@
#include "HTMLTableAccessibleWrap.h"
#include "HyperTextAccessibleWrap.h"
#include "RootAccessible.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsArrayUtils.h"
#include "nsAttrName.h"
@ -265,6 +264,7 @@ nsAccessibilityService *nsAccessibilityService::gAccessibilityService = nullptr;
ApplicationAccessible* nsAccessibilityService::gApplicationAccessible = nullptr;
xpcAccessibleApplication* nsAccessibilityService::gXPCApplicationAccessible = nullptr;
bool nsAccessibilityService::gIsShutdown = true;
bool nsAccessibilityService::gIsPlatformCaller = false;
nsAccessibilityService::nsAccessibilityService() :
DocManager(), FocusManager(), mMarkupMaps(ArrayLength(sMarkupMapList))
@ -340,8 +340,6 @@ nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges)
NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService,
DocManager,
nsIAccessibilityService,
nsIAccessibleRetrieval,
nsIObserver,
nsIListenerChangeListener,
nsISelectionListener) // from SelectionManager
@ -359,7 +357,6 @@ nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
return NS_OK;
}
// nsIAccessibilityService
void
nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
{
@ -371,7 +368,6 @@ nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode)
}
}
// nsIAccessibilityService
void
nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent,
Accessible* aTarget)
@ -379,9 +375,6 @@ nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent,
nsEventShell::FireEvent(aEvent, aTarget);
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessibilityService
Accessible*
nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
bool aCanCreate)
@ -737,58 +730,26 @@ nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
document->RecreateAccessible(aContent);
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessibleRetrieval
NS_IMETHODIMP
nsAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication)
{
NS_ENSURE_ARG_POINTER(aAccessibleApplication);
NS_IF_ADDREF(*aAccessibleApplication = XPCApplicationAcc());
return NS_OK;
}
NS_IMETHODIMP
nsAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nullptr;
if (!aNode)
return NS_OK;
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
if (!node)
return NS_ERROR_INVALID_ARG;
DocAccessible* document = GetDocAccessible(node->OwnerDoc());
if (document)
NS_IF_ADDREF(*aAccessible = ToXPC(document->GetAccessible(node)));
return NS_OK;
}
NS_IMETHODIMP
void
nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
{
#define ROLE(geckoRole, stringRole, atkRole, \
macRole, msaaRole, ia2Role, nameRule) \
case roles::geckoRole: \
CopyUTF8toUTF16(stringRole, aString); \
return NS_OK;
return;
switch (aRole) {
#include "RoleMap.h"
default:
aString.AssignLiteral("unknown");
return NS_OK;
return;
}
#undef ROLE
}
NS_IMETHODIMP
void
nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
nsISupports **aStringStates)
{
@ -797,113 +758,159 @@ nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
uint64_t state = nsAccUtils::To64State(aState, aExtraState);
// states
if (state & states::UNAVAILABLE)
if (state & states::UNAVAILABLE) {
stringStates->Add(NS_LITERAL_STRING("unavailable"));
if (state & states::SELECTED)
}
if (state & states::SELECTED) {
stringStates->Add(NS_LITERAL_STRING("selected"));
if (state & states::FOCUSED)
}
if (state & states::FOCUSED) {
stringStates->Add(NS_LITERAL_STRING("focused"));
if (state & states::PRESSED)
}
if (state & states::PRESSED) {
stringStates->Add(NS_LITERAL_STRING("pressed"));
if (state & states::CHECKED)
}
if (state & states::CHECKED) {
stringStates->Add(NS_LITERAL_STRING("checked"));
if (state & states::MIXED)
}
if (state & states::MIXED) {
stringStates->Add(NS_LITERAL_STRING("mixed"));
if (state & states::READONLY)
}
if (state & states::READONLY) {
stringStates->Add(NS_LITERAL_STRING("readonly"));
if (state & states::HOTTRACKED)
}
if (state & states::HOTTRACKED) {
stringStates->Add(NS_LITERAL_STRING("hottracked"));
if (state & states::DEFAULT)
}
if (state & states::DEFAULT) {
stringStates->Add(NS_LITERAL_STRING("default"));
if (state & states::EXPANDED)
}
if (state & states::EXPANDED) {
stringStates->Add(NS_LITERAL_STRING("expanded"));
if (state & states::COLLAPSED)
}
if (state & states::COLLAPSED) {
stringStates->Add(NS_LITERAL_STRING("collapsed"));
if (state & states::BUSY)
}
if (state & states::BUSY) {
stringStates->Add(NS_LITERAL_STRING("busy"));
if (state & states::FLOATING)
}
if (state & states::FLOATING) {
stringStates->Add(NS_LITERAL_STRING("floating"));
if (state & states::ANIMATED)
}
if (state & states::ANIMATED) {
stringStates->Add(NS_LITERAL_STRING("animated"));
if (state & states::INVISIBLE)
}
if (state & states::INVISIBLE) {
stringStates->Add(NS_LITERAL_STRING("invisible"));
if (state & states::OFFSCREEN)
}
if (state & states::OFFSCREEN) {
stringStates->Add(NS_LITERAL_STRING("offscreen"));
if (state & states::SIZEABLE)
}
if (state & states::SIZEABLE) {
stringStates->Add(NS_LITERAL_STRING("sizeable"));
if (state & states::MOVEABLE)
}
if (state & states::MOVEABLE) {
stringStates->Add(NS_LITERAL_STRING("moveable"));
if (state & states::SELFVOICING)
}
if (state & states::SELFVOICING) {
stringStates->Add(NS_LITERAL_STRING("selfvoicing"));
if (state & states::FOCUSABLE)
}
if (state & states::FOCUSABLE) {
stringStates->Add(NS_LITERAL_STRING("focusable"));
if (state & states::SELECTABLE)
}
if (state & states::SELECTABLE) {
stringStates->Add(NS_LITERAL_STRING("selectable"));
if (state & states::LINKED)
}
if (state & states::LINKED) {
stringStates->Add(NS_LITERAL_STRING("linked"));
if (state & states::TRAVERSED)
}
if (state & states::TRAVERSED) {
stringStates->Add(NS_LITERAL_STRING("traversed"));
if (state & states::MULTISELECTABLE)
}
if (state & states::MULTISELECTABLE) {
stringStates->Add(NS_LITERAL_STRING("multiselectable"));
if (state & states::EXTSELECTABLE)
}
if (state & states::EXTSELECTABLE) {
stringStates->Add(NS_LITERAL_STRING("extselectable"));
if (state & states::PROTECTED)
}
if (state & states::PROTECTED) {
stringStates->Add(NS_LITERAL_STRING("protected"));
if (state & states::HASPOPUP)
}
if (state & states::HASPOPUP) {
stringStates->Add(NS_LITERAL_STRING("haspopup"));
if (state & states::REQUIRED)
}
if (state & states::REQUIRED) {
stringStates->Add(NS_LITERAL_STRING("required"));
if (state & states::ALERT)
}
if (state & states::ALERT) {
stringStates->Add(NS_LITERAL_STRING("alert"));
if (state & states::INVALID)
}
if (state & states::INVALID) {
stringStates->Add(NS_LITERAL_STRING("invalid"));
if (state & states::CHECKABLE)
}
if (state & states::CHECKABLE) {
stringStates->Add(NS_LITERAL_STRING("checkable"));
}
// extraStates
if (state & states::SUPPORTS_AUTOCOMPLETION)
if (state & states::SUPPORTS_AUTOCOMPLETION) {
stringStates->Add(NS_LITERAL_STRING("autocompletion"));
if (state & states::DEFUNCT)
}
if (state & states::DEFUNCT) {
stringStates->Add(NS_LITERAL_STRING("defunct"));
if (state & states::SELECTABLE_TEXT)
}
if (state & states::SELECTABLE_TEXT) {
stringStates->Add(NS_LITERAL_STRING("selectable text"));
if (state & states::EDITABLE)
}
if (state & states::EDITABLE) {
stringStates->Add(NS_LITERAL_STRING("editable"));
if (state & states::ACTIVE)
}
if (state & states::ACTIVE) {
stringStates->Add(NS_LITERAL_STRING("active"));
if (state & states::MODAL)
}
if (state & states::MODAL) {
stringStates->Add(NS_LITERAL_STRING("modal"));
if (state & states::MULTI_LINE)
}
if (state & states::MULTI_LINE) {
stringStates->Add(NS_LITERAL_STRING("multi line"));
if (state & states::HORIZONTAL)
}
if (state & states::HORIZONTAL) {
stringStates->Add(NS_LITERAL_STRING("horizontal"));
if (state & states::OPAQUE1)
}
if (state & states::OPAQUE1) {
stringStates->Add(NS_LITERAL_STRING("opaque"));
if (state & states::SINGLE_LINE)
}
if (state & states::SINGLE_LINE) {
stringStates->Add(NS_LITERAL_STRING("single line"));
if (state & states::TRANSIENT)
}
if (state & states::TRANSIENT) {
stringStates->Add(NS_LITERAL_STRING("transient"));
if (state & states::VERTICAL)
}
if (state & states::VERTICAL) {
stringStates->Add(NS_LITERAL_STRING("vertical"));
if (state & states::STALE)
}
if (state & states::STALE) {
stringStates->Add(NS_LITERAL_STRING("stale"));
if (state & states::ENABLED)
}
if (state & states::ENABLED) {
stringStates->Add(NS_LITERAL_STRING("enabled"));
if (state & states::SENSITIVE)
}
if (state & states::SENSITIVE) {
stringStates->Add(NS_LITERAL_STRING("sensitive"));
if (state & states::EXPANDABLE)
}
if (state & states::EXPANDABLE) {
stringStates->Add(NS_LITERAL_STRING("expandable"));
}
//unknown states
if (!stringStates->Length())
if (!stringStates->Length()) {
stringStates->Add(NS_LITERAL_STRING("unknown"));
}
stringStates.forget(aStringStates);
return NS_OK;
}
// nsIAccessibleRetrieval::getStringEventType()
NS_IMETHODIMP
void
nsAccessibilityService::GetStringEventType(uint32_t aEventType,
nsAString& aString)
{
@ -912,105 +919,34 @@ nsAccessibilityService::GetStringEventType(uint32_t aEventType,
if (aEventType >= ArrayLength(kEventTypeNames)) {
aString.AssignLiteral("unknown");
return NS_OK;
return;
}
CopyUTF8toUTF16(kEventTypeNames[aEventType], aString);
return NS_OK;
}
// nsIAccessibleRetrieval::getStringRelationType()
NS_IMETHODIMP
void
nsAccessibilityService::GetStringRelationType(uint32_t aRelationType,
nsAString& aString)
{
NS_ENSURE_ARG(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
NS_ENSURE_TRUE_VOID(aRelationType <= static_cast<uint32_t>(RelationType::LAST));
#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
case RelationType::geckoType: \
aString.AssignLiteral(geckoTypeName); \
return NS_OK;
return;
RelationType relationType = static_cast<RelationType>(aRelationType);
switch (relationType) {
#include "RelationTypeMap.h"
default:
aString.AssignLiteral("unknown");
return NS_OK;
return;
}
#undef RELATIONTYPE
}
NS_IMETHODIMP
nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
nsIAccessible** aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nullptr;
if (!aNode)
return NS_OK;
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
if (!node)
return NS_ERROR_INVALID_ARG;
// Search for an accessible in each of our per document accessible object
// caches. If we don't find it, and the given node is itself a document, check
// our cache of document accessibles (document cache). Note usually shutdown
// document accessibles are not stored in the document cache, however an
// "unofficially" shutdown document (i.e. not from DocManager) can still
// exist in the document cache.
Accessible* accessible = FindAccessibleInCache(node);
if (!accessible) {
nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
if (document)
accessible = GetExistingDocAccessible(document);
}
NS_IF_ADDREF(*aAccessible = ToXPC(accessible));
return NS_OK;
}
NS_IMETHODIMP
nsAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot,
nsIAccessiblePivot** aPivot)
{
NS_ENSURE_ARG_POINTER(aPivot);
NS_ENSURE_ARG(aRoot);
*aPivot = nullptr;
Accessible* accessibleRoot = aRoot->ToInternalAccessible();
NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG);
nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot);
NS_ADDREF(*aPivot = pivot);
return NS_OK;
}
NS_IMETHODIMP
nsAccessibilityService::SetLogging(const nsACString& aModules)
{
#ifdef A11Y_LOG
logging::Enable(PromiseFlatCString(aModules));
#endif
return NS_OK;
}
NS_IMETHODIMP
nsAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged)
{
NS_ENSURE_ARG_POINTER(aIsLogged);
*aIsLogged = false;
#ifdef A11Y_LOG
*aIsLogged = logging::IsEnabled(aModule);
#endif
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService public
@ -1327,6 +1263,7 @@ nsAccessibilityService::Init()
#endif
gAccessibilityService = this;
NS_ADDREF(gAccessibilityService); // will release in Shutdown()
if (XRE_IsParentProcess())
gApplicationAccessible = new ApplicationAccessibleWrap();
@ -1359,6 +1296,15 @@ nsAccessibilityService::Init()
void
nsAccessibilityService::Shutdown()
{
// Application is going to be closed, shutdown accessibility and mark
// accessibility service as shutdown to prevent calls of its methods.
// Don't null accessibility service static member at this point to be safe
// if someone will try to operate with it.
MOZ_ASSERT(!gIsShutdown, "Accessibility was shutdown already");
gIsShutdown = true;
// Remove observers.
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
@ -1384,15 +1330,6 @@ nsAccessibilityService::Shutdown()
sPluginTimers = nullptr;
#endif
// Application is going to be closed, shutdown accessibility and mark
// accessibility service as shutdown to prevent calls of its methods.
// Don't null accessibility service static member at this point to be safe
// if someone will try to operate with it.
NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
gIsShutdown = true;
if (XRE_IsParentProcess())
PlatformShutdown();
@ -1402,6 +1339,10 @@ nsAccessibilityService::Shutdown()
NS_IF_RELEASE(gXPCApplicationAccessible);
gXPCApplicationAccessible = nullptr;
NS_RELEASE(gAccessibilityService);
gAccessibilityService = nullptr;
gIsPlatformCaller = false;
}
already_AddRefed<Accessible>
@ -1756,9 +1697,6 @@ nsAccessibilityService::MarkupAttributes(const nsIContent* aContent,
}
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessibilityService (DON'T put methods here)
Accessible*
nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
{
@ -1802,38 +1740,6 @@ nsAccessibilityService::HasAccessible(nsIDOMNode* aDOMNode)
return document->HasAccessible(node);
}
////////////////////////////////////////////////////////////////////////////////
// NS_GetAccessibilityService
////////////////////////////////////////////////////////////////////////////////
/**
* Return accessibility service; creating one if necessary.
*/
nsresult
NS_GetAccessibilityService(nsIAccessibilityService** aResult)
{
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = nullptr;
if (nsAccessibilityService::gAccessibilityService) {
NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
return NS_OK;
}
RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
if (!service->Init()) {
service->Shutdown();
return NS_ERROR_FAILURE;
}
statistics::A11yInitialized();
NS_ADDREF(*aResult = service);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService private (DON'T put methods here)
@ -1869,6 +1775,38 @@ nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
}
#endif
nsAccessibilityService*
GetOrCreateAccService(bool aIsPlatformCaller)
{
if (aIsPlatformCaller) {
nsAccessibilityService::gIsPlatformCaller = aIsPlatformCaller;
}
if (!nsAccessibilityService::gAccessibilityService) {
RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
if (!service->Init()) {
service->Shutdown();
return nullptr;
}
}
MOZ_ASSERT(nsAccessibilityService::gAccessibilityService,
"Accessible service is not initialized.");
return nsAccessibilityService::gAccessibilityService;
}
bool
CanShutdownAccService()
{
nsAccessibilityService* accService = nsAccessibilityService::gAccessibilityService;
if (!accService) {
return false;
}
return !xpcAccessibilityService::IsInUse() &&
!accService->IsPlatformCaller() && !accService->IsShutdown() &&
!nsCoreUtils::AccEventObserversExist();
}
////////////////////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////////////////////

View File

@ -6,8 +6,6 @@
#ifndef __nsAccessibilityService_h__
#define __nsAccessibilityService_h__
#include "nsIAccessibilityService.h"
#include "mozilla/a11y/DocManager.h"
#include "mozilla/a11y/FocusManager.h"
#include "mozilla/a11y/Role.h"
@ -15,7 +13,9 @@
#include "mozilla/Preferences.h"
#include "nsIObserver.h"
#include "nsIAccessibleEvent.h"
#include "nsIEventListenerService.h"
#include "xpcAccessibilityService.h"
class nsImageFrame;
class nsIArray;
@ -68,7 +68,6 @@ struct MarkupMapInfo {
class nsAccessibilityService final : public mozilla::a11y::DocManager,
public mozilla::a11y::FocusManager,
public mozilla::a11y::SelectionManager,
public nsIAccessibilityService,
public nsIListenerChangeListener,
public nsIObserver
{
@ -80,16 +79,14 @@ public:
NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
protected:
virtual ~nsAccessibilityService();
~nsAccessibilityService();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIACCESSIBLERETRIEVAL
NS_DECL_NSIOBSERVER
// nsIAccessibilityService
virtual Accessible* GetRootDocumentAccessible(nsIPresShell* aPresShell,
bool aCanCreate) override;
Accessible* GetRootDocumentAccessible(nsIPresShell* aPresShell,
bool aCanCreate);
already_AddRefed<Accessible>
CreatePluginAccessible(nsPluginFrame* aFrame, nsIContent* aContent,
Accessible* aContext);
@ -98,10 +95,31 @@ public:
* Adds/remove ATK root accessible for gtk+ native window to/from children
* of the application accessible.
*/
virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible) override;
virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible) override;
Accessible* AddNativeRootAccessible(void* aAtkAccessible);
void RemoveNativeRootAccessible(Accessible* aRootAccessible);
virtual bool HasAccessible(nsIDOMNode* aDOMNode) override;
bool HasAccessible(nsIDOMNode* aDOMNode);
/**
* Get a string equivalent for an accessilbe role value.
*/
void GetStringRole(uint32_t aRole, nsAString& aString);
/**
* Get a string equivalent for an accessible state/extra state.
*/
void GetStringStates(uint32_t aState, uint32_t aExtraState,
nsISupports **aStringStates);
/**
* Get a string equivalent for an accessible event value.
*/
void GetStringEventType(uint32_t aEventType, nsAString& aString);
/**
* Get a string equivalent for an accessible relation type.
*/
void GetStringRelationType(uint32_t aRelationType, nsAString& aString);
// nsAccesibilityService
/**
@ -123,7 +141,7 @@ public:
*/
void ContentRemoved(nsIPresShell* aPresShell, nsIContent* aChild);
virtual void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
/**
* Update XUL:tree accessible tree when treeview is changed.
@ -139,9 +157,9 @@ public:
/**
* Update list bullet accessible.
*/
virtual void UpdateListBullet(nsIPresShell* aPresShell,
nsIContent* aHTMLListItemContent,
bool aHasBullet);
void UpdateListBullet(nsIPresShell* aPresShell,
nsIContent* aHTMLListItemContent,
bool aHasBullet);
/**
* Update the image map.
@ -163,14 +181,14 @@ public:
/**
* Notify that presshell is activated.
*/
virtual void PresShellActivated(nsIPresShell* aPresShell);
void PresShellActivated(nsIPresShell* aPresShell);
/**
* Recreate an accessible for the given content node in the presshell.
*/
void RecreateAccessible(nsIPresShell* aPresShell, nsIContent* aContent);
virtual void FireAccessibleEvent(uint32_t aEvent, Accessible* aTarget) override;
void FireAccessibleEvent(uint32_t aEvent, Accessible* aTarget);
// nsAccessibiltiyService
@ -179,6 +197,11 @@ public:
*/
static bool IsShutdown() { return gIsShutdown; }
/**
* Return true if accessibility service has been initialized by platform.
*/
static bool IsPlatformCaller() { return gIsPlatformCaller; };
/**
* Creates an accessible for the given DOM node.
*
@ -205,7 +228,7 @@ public:
private:
// nsAccessibilityService creation is controlled by friend
// NS_GetAccessibilityService, keep constructors private.
// GetOrCreateAccService, keep constructors private.
nsAccessibilityService();
nsAccessibilityService(const nsAccessibilityService&);
nsAccessibilityService& operator =(const nsAccessibilityService&);
@ -258,15 +281,21 @@ private:
*/
static bool gIsShutdown;
/**
* Indicates whether accessibility service was initialized by platform.
*/
static bool gIsPlatformCaller;
nsDataHashtable<nsPtrHashKey<const nsIAtom>, const mozilla::a11y::MarkupMapInfo*> mMarkupMaps;
friend nsAccessibilityService* GetAccService();
friend nsAccessibilityService* GetOrCreateAccService(bool);
friend bool CanShutdownAccService();
friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();
friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc();
friend mozilla::a11y::xpcAccessibleApplication* mozilla::a11y::XPCApplicationAcc();
friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
friend class xpcAccessibilityService;
};
/**
@ -278,6 +307,16 @@ GetAccService()
return nsAccessibilityService::gAccessibilityService;
}
/**
* Return accessibility service instance; creating one if necessary.
*/
nsAccessibilityService* GetOrCreateAccService(bool aIsPlatformCaller = true);
/**
* Return a flag indicating if accessibility service can be shutdown.
*/
bool CanShutdownAccService();
/**
* Return true if we're in a content process and not B2G.
*/
@ -294,7 +333,7 @@ IPCAccessibilityActive()
/**
* Map nsIAccessibleEvents constants to strings. Used by
* nsIAccessibleRetrieval::getStringEventType() method.
* nsAccessibilityService::GetStringEventType() method.
*/
static const char kEventTypeNames[][40] = {
"unknown", //
@ -387,5 +426,4 @@ static const char kEventTypeNames[][40] = {
"text value change", // EVENT_TEXT_VALUE_CHANGE
};
#endif /* __nsIAccessibilityService_h__ */
#endif

View File

@ -8,6 +8,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows' and CONFIG['COMPILE_ENVIRONMENT']:
DIRS += ['msaa', 'ia2']
XPIDL_SOURCES += [
'nsIAccessibilityService.idl',
'nsIAccessible.idl',
'nsIAccessibleApplication.idl',
'nsIAccessibleCaretMoveEvent.idl',
@ -21,7 +22,6 @@ XPIDL_SOURCES += [
'nsIAccessibleObjectAttributeChangedEvent.idl',
'nsIAccessiblePivot.idl',
'nsIAccessibleRelation.idl',
'nsIAccessibleRetrieval.idl',
'nsIAccessibleRole.idl',
'nsIAccessibleSelectable.idl',
'nsIAccessibleStateChangeEvent.idl',
@ -38,8 +38,3 @@ XPIDL_SOURCES += [
]
XPIDL_MODULE = 'accessibility'
EXPORTS += [
'nsIAccessibilityService.h',
]

View File

@ -1,79 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsIAccessibilityService_h_
#define _nsIAccessibilityService_h_
#include "nsIAccessibleRetrieval.h"
#include "nsIAccessibleEvent.h"
namespace mozilla {
namespace a11y {
class Accessible;
} // namespace a11y
} // namespace mozilla
class nsIPresShell;
// 0e7e6879-854b-4260-bc6e-525b5fb5cf34
#define NS_IACCESSIBILITYSERVICE_IID \
{ 0x0e7e6879, 0x854b, 0x4260, \
{ 0xbc, 0x6e, 0x52, 0x5b, 0x5f, 0xb5, 0xcf, 0x34 } }
class nsIAccessibilityService : public nsIAccessibleRetrieval
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IACCESSIBILITYSERVICE_IID)
/**
* Return root document accessible that is or contains a document accessible
* for the given presshell.
*
* @param aPresShell [in] the presshell
* @param aCanCreate [in] points whether the root document accessible
* should be returned from the cache or can be created
*/
virtual mozilla::a11y::Accessible*
GetRootDocumentAccessible(nsIPresShell* aPresShell, bool aCanCreate) = 0;
/**
* Adds/remove ATK root accessible for gtk+ native window to/from children
* of the application accessible.
*/
virtual mozilla::a11y::Accessible*
AddNativeRootAccessible(void* aAtkAccessible) = 0;
virtual void
RemoveNativeRootAccessible(mozilla::a11y::Accessible* aRootAccessible) = 0;
/**
* Fire accessible event of the given type for the given target.
*
* @param aEvent [in] accessible event type
* @param aTarget [in] target of accessible event
*/
virtual void FireAccessibleEvent(uint32_t aEvent,
mozilla::a11y::Accessible* aTarget) = 0;
/**
* Return true if the given DOM node has accessible object.
*/
virtual bool HasAccessible(nsIDOMNode* aDOMNode) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAccessibilityService,
NS_IACCESSIBILITYSERVICE_IID)
// for component registration
// {DE401C37-9A7F-4278-A6F8-3DE2833989EF}
#define NS_ACCESSIBILITY_SERVICE_CID \
{ 0xde401c37, 0x9a7f, 0x4278, { 0xa6, 0xf8, 0x3d, 0xe2, 0x83, 0x39, 0x89, 0xef } }
extern nsresult
NS_GetAccessibilityService(nsIAccessibilityService** aResult);
#endif

View File

@ -16,8 +16,8 @@ interface nsIAccessiblePivot;
* nsIAccessible for a given DOM node. More documentation at:
* http://www.mozilla.org/projects/ui/accessibility
*/
[scriptable, builtinclass, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)]
interface nsIAccessibleRetrieval : nsISupports
[scriptable, builtinclass, uuid(9a6f80fe-25cc-405c-9f8f-25869bc9f94e)]
interface nsIAccessibilityService : nsISupports
{
/**
* Return application accessible.
@ -99,12 +99,10 @@ interface nsIAccessibleRetrieval : nsISupports
boolean isLogged(in AString aModule);
};
%{ C++
// for component registration
// {663CA4A8-D219-4000-925D-D8F66406B626}
#define NS_ACCESSIBLE_RETRIEVAL_CID \
{ 0x663ca4a8, 0xd219, 0x4000, { 0x92, 0x5d, 0xd8, 0xf6, 0x64, 0x6, 0xb6, 0x26 } }
%}
/**
* @deprecated, use nsIAccessibilityService instead.
*/
[scriptable, builtinclass, uuid(d85e0cbe-47ce-490c-8488-f821dd2be0c2)]
interface nsIAccessibleRetrieval : nsIAccessibilityService
{
};

View File

@ -6,6 +6,7 @@
UNIFIED_SOURCES += [
'nsAccessibleRelation.cpp',
'xpcAccessibilityService.cpp',
'xpcAccessible.cpp',
'xpcAccessibleApplication.cpp',
'xpcAccessibleDocument.cpp',
@ -26,6 +27,7 @@ SOURCES += [
EXPORTS += [
'!xpcAccEvents.h',
'xpcAccessibilityService.h',
]
LOCAL_INCLUDES += [

View File

@ -0,0 +1,249 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "xpcAccessibilityService.h"
#include "nsAccessiblePivot.h"
#include "nsAccessibilityService.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
using namespace mozilla;
using namespace mozilla::a11y;
using namespace mozilla::dom;
xpcAccessibilityService *xpcAccessibilityService::gXPCAccessibilityService = nullptr;
////////////////////////////////////////////////////////////////////////////////
// nsISupports
void
xpcAccessibilityService::ShutdownCallback(nsITimer* aTimer, void* aClosure)
{
if (CanShutdownAccService()) {
GetAccService()->Shutdown();
}
xpcAccessibilityService* xpcAccService =
reinterpret_cast<xpcAccessibilityService*>(aClosure);
if (xpcAccService->mShutdownTimer) {
xpcAccService->mShutdownTimer->Cancel();
xpcAccService->mShutdownTimer = nullptr;
}
}
NS_IMETHODIMP_(MozExternalRefCountType)
xpcAccessibilityService::AddRef(void)
{
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(xpcAccessibilityService)
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
if (!mRefCnt.isThreadSafe)
NS_ASSERT_OWNINGTHREAD(xpcAccessibilityService);
nsrefcnt count = ++mRefCnt;
NS_LOG_ADDREF(this, count, "xpcAccessibilityService", sizeof(*this));
if (mRefCnt > 1) {
GetOrCreateAccService(false);
}
return count;
}
NS_IMETHODIMP_(MozExternalRefCountType)
xpcAccessibilityService::Release(void)
{
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
if (!mRefCnt.isThreadSafe) {
NS_ASSERT_OWNINGTHREAD(xpcAccessibilityService);
}
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "xpcAccessibilityService");
if (count == 0) {
if (!mRefCnt.isThreadSafe) {
NS_ASSERT_OWNINGTHREAD(xpcAccessibilityService);
}
mRefCnt = 1; /* stabilize */
delete (this);
return 0;
}
// When ref count goes down to 1 (held internally as a static reference),
// it means that there are no more external references to the
// xpcAccessibilityService and we can attempt to shut down acceessiblity
// service.
if (count == 1 && !mShutdownTimer) {
mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (mShutdownTimer) {
mShutdownTimer->InitWithFuncCallback(ShutdownCallback, this, 100,
nsITimer::TYPE_ONE_SHOT);
}
}
return count;
}
NS_IMPL_QUERY_INTERFACE(xpcAccessibilityService, nsIAccessibilityService,
nsIAccessibleRetrieval)
NS_IMETHODIMP
xpcAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication)
{
NS_ENSURE_ARG_POINTER(aAccessibleApplication);
NS_IF_ADDREF(*aAccessibleApplication = XPCApplicationAcc());
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nullptr;
if (!aNode) {
return NS_OK;
}
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
if (!node) {
return NS_ERROR_INVALID_ARG;
}
DocAccessible* document = GetAccService()->GetDocAccessible(node->OwnerDoc());
if (document) {
NS_IF_ADDREF(*aAccessible = ToXPC(document->GetAccessible(node)));
}
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
{
GetAccService()->GetStringRole(aRole, aString);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
nsISupports **aStringStates)
{
GetAccService()->GetStringStates(aState, aExtraState, aStringStates);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetStringEventType(uint32_t aEventType,
nsAString& aString)
{
GetAccService()->GetStringEventType(aEventType, aString);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetStringRelationType(uint32_t aRelationType,
nsAString& aString)
{
GetAccService()->GetStringRelationType(aRelationType, aString);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
nsIAccessible** aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nullptr;
if (!aNode) {
return NS_OK;
}
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
if (!node) {
return NS_ERROR_INVALID_ARG;
}
// Search for an accessible in each of our per document accessible object
// caches. If we don't find it, and the given node is itself a document, check
// our cache of document accessibles (document cache). Note usually shutdown
// document accessibles are not stored in the document cache, however an
// "unofficially" shutdown document (i.e. not from DocManager) can still
// exist in the document cache.
Accessible* accessible = GetAccService()->FindAccessibleInCache(node);
if (!accessible) {
nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
if (document) {
accessible = mozilla::a11y::GetExistingDocAccessible(document);
}
}
NS_IF_ADDREF(*aAccessible = ToXPC(accessible));
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot,
nsIAccessiblePivot** aPivot)
{
NS_ENSURE_ARG_POINTER(aPivot);
NS_ENSURE_ARG(aRoot);
*aPivot = nullptr;
Accessible* accessibleRoot = aRoot->ToInternalAccessible();
NS_ENSURE_TRUE(accessibleRoot, NS_ERROR_INVALID_ARG);
nsAccessiblePivot* pivot = new nsAccessiblePivot(accessibleRoot);
NS_ADDREF(*aPivot = pivot);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::SetLogging(const nsACString& aModules)
{
#ifdef A11Y_LOG
logging::Enable(PromiseFlatCString(aModules));
#endif
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged)
{
NS_ENSURE_ARG_POINTER(aIsLogged);
*aIsLogged = false;
#ifdef A11Y_LOG
*aIsLogged = logging::IsEnabled(aModule);
#endif
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// NS_GetAccessibilityService
////////////////////////////////////////////////////////////////////////////////
nsresult
NS_GetAccessibilityService(nsIAccessibilityService** aResult)
{
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = nullptr;
GetOrCreateAccService(false);
xpcAccessibilityService* service = new xpcAccessibilityService();
NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
xpcAccessibilityService::gXPCAccessibilityService = service;
NS_ADDREF(*aResult = service);
return NS_OK;
}

View File

@ -0,0 +1,66 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_xpcAccessibilityService_h_
#define mozilla_a11y_xpcAccessibilityService_h_
#include "nsIAccessibilityService.h"
class xpcAccessibilityService : public nsIAccessibleRetrieval
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIACCESSIBILITYSERVICE
NS_DECL_NSIACCESSIBLERETRIEVAL
/**
* Return true if xpc accessibility service is in use.
*/
static bool IsInUse() {
// When ref count goes down to 1 (held internally as a static reference),
// it means that there are no more external references and thus it is not in
// use.
return gXPCAccessibilityService ? gXPCAccessibilityService->mRefCnt > 1 : false;
}
protected:
virtual ~xpcAccessibilityService() {
if (mShutdownTimer) {
mShutdownTimer->Cancel();
mShutdownTimer = nullptr;
}
gXPCAccessibilityService = nullptr;
}
private:
// xpcAccessibilityService creation is controlled by friend
// NS_GetAccessibilityService, keep constructor private.
xpcAccessibilityService() { };
nsCOMPtr<nsITimer> mShutdownTimer;
/**
* Reference for xpc accessibility service instance.
*/
static xpcAccessibilityService* gXPCAccessibilityService;
/**
* Used to shutdown nsAccessibilityService if xpcom accessible service is not
* in use any more.
*/
static void ShutdownCallback(nsITimer* aTimer, void* aClosure);
friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
};
// for component registration
// {3b265b69-f813-48ff-880d-d88d101af404}
#define NS_ACCESSIBILITY_SERVICE_CID \
{ 0x3b265b69, 0xf813, 0x48ff, { 0x88, 0x0d, 0xd8, 0x8d, 0x10, 0x1a, 0xf4, 0x04 } }
extern nsresult
NS_GetAccessibilityService(nsIAccessibilityService** aResult);
#endif

View File

@ -26,6 +26,7 @@ support-files =
[browser_newtab_disable.js]
[browser_newtab_drag_drop.js]
[browser_newtab_drag_drop_ext.js]
subsuite = clipboard # temporary until determine why more intermittent on VM
[browser_newtab_drop_preview.js]
[browser_newtab_enhanced.js]
[browser_newtab_focus.js]

View File

@ -24,3 +24,4 @@ tags = openwindow
[browser_broadcastchannel.js]
[browser_blobUrl.js]
[browser_middleClick.js]
[browser_imageCache.js]

View File

@ -15,7 +15,6 @@ let css = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
const USER_CONTEXTS = [
"default",
"personal",
"work",
];
const TEST_HOST = "example.com";
const TEST_URL = "http://" + TEST_HOST + "/browser/browser/components/contextualidentity/test/browser/";
@ -133,7 +132,7 @@ function* test_cookie_cleared() {
let tabs = [];
for (let userContextId of Object.keys(USER_CONTEXTS)) {
// Load the page in 3 different contexts and set a cookie
// Load the page in 2 different contexts and set a cookie
// which should only be visible in that context.
let value = USER_CONTEXTS[userContextId];
@ -212,8 +211,10 @@ function* test_image_cache_cleared() {
yield BrowserTestUtils.removeTab(tabs[userContextId].tab);
}
let expectedHits = USER_CONTEXTS.length;
// Check that image cache works with the userContextId.
todo_is(gHits, 3, "The image should be loaded three times. This test should be enabled after the bug 1270680 landed");
is(gHits, expectedHits, "The image should be loaded" + expectedHits + "times.");
// Reset the cache count.
gHits = 0;
@ -229,14 +230,14 @@ function* test_image_cache_cleared() {
yield BrowserTestUtils.removeTab(tabs[userContextId].tab);
}
// Check that image cache was cleared and the server gets another three hits.
todo_is(gHits, 3, "The image should be loaded three times. This test should be enabled after the bug 1270680 landed");
// Check that image cache was cleared and the server gets another two hits.
is(gHits, expectedHits, "The image should be loaded" + expectedHits + "times.");
}
// Offline Storage
function* test_storage_cleared() {
for (let userContextId of Object.keys(USER_CONTEXTS)) {
// Load the page in 3 different contexts and set the local storage
// Load the page in 2 different contexts and set the local storage
// which should only be visible in that context.
let value = USER_CONTEXTS[userContextId];

View File

@ -0,0 +1,59 @@
let Cu = Components.utils;
let {HttpServer} = Cu.import("resource://testing-common/httpd.js", {});
const NUM_USER_CONTEXTS = 3;
let gHits = 0;
let server = new HttpServer();
server.registerPathHandler('/image.png', imageHandler);
server.registerPathHandler('/file.html', fileHandler);
server.start(-1);
let BASE_URI = 'http://localhost:' + server.identity.primaryPort;
let IMAGE_URI = BASE_URI + '/image.png';
let FILE_URI = BASE_URI + '/file.html';
function imageHandler(metadata, response) {
gHits++;
response.setHeader("Cache-Control", "max-age=10000", false);
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "image/png", false);
var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
response.bodyOutputStream.write(body, body.length);
}
function fileHandler(metadata, response) {
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html", false);
let body = `<html><body><image src=${IMAGE_URI}></body></html>`;
response.bodyOutputStream.write(body, body.length);
}
add_task(function* setup() {
// make sure userContext is enabled.
yield SpecialPowers.pushPrefEnv({"set": [["privacy.userContext.enabled", true]]});
});
// opens `uri' in a new tab with the provided userContextId and focuses it.
// returns the newly opened tab
function* openTabInUserContext(uri, userContextId) {
// open the tab in the correct userContextId
let tab = gBrowser.addTab(uri, {userContextId});
// select tab and make sure its browser is focused
gBrowser.selectedTab = tab;
tab.ownerDocument.defaultView.focus();
let browser = gBrowser.getBrowserForTab(tab);
yield BrowserTestUtils.browserLoaded(browser);
return tab;
}
add_task(function* test() {
for (let userContextId = 0; userContextId < NUM_USER_CONTEXTS; userContextId++) {
let tab = yield* openTabInUserContext(FILE_URI, userContextId);
gBrowser.removeTab(tab);
}
is(gHits, NUM_USER_CONTEXTS, "should get an image request for each user contexts");
});

View File

@ -216,14 +216,18 @@ class BasePopup {
// Resizes the browser to match the preferred size of the content (debounced).
resizeBrowser() {
if (this.resizeTimeout == null) {
this._resizeBrowser();
this.resizeTimeout = this.window.setTimeout(this._resizeBrowser.bind(this), RESIZE_TIMEOUT);
this.resizeTimeout = this.window.setTimeout(() => {
try {
this._resizeBrowser();
} finally {
this.resizeTimeout = null;
}
}, RESIZE_TIMEOUT);
this._resizeBrowser(false);
}
}
_resizeBrowser() {
this.resizeTimeout = null;
_resizeBrowser(clearTimeout = true) {
if (!this.browser) {
return;
}

View File

@ -42,6 +42,7 @@
{
"namespace": "browserAction",
"description": "Use browser actions to put icons in the main browser toolbar, to the right of the address bar. In addition to its icon, a browser action can also have a tooltip, a badge, and a popup.",
"permissions": ["manifest:browser_action"],
"types": [
{
"id": "ColorArray",

View File

@ -42,6 +42,7 @@
{
"namespace": "pageAction",
"description": "Use the <code>browser.pageAction</code> API to put icons inside the address bar. Page actions represent actions that can be taken on the current page, but that aren't applicable to all pages.",
"permissions": ["manifest:page_action"],
"types": [
{
"id": "ImageDataType",

View File

@ -3,20 +3,6 @@
// found in the LICENSE file.
[
{
"namespace": "manifest",
"types": [
{
"$extend": "Permission",
"choices": [{
"type": "string",
"enum": [
"windows"
]
}]
}
]
},
{
"namespace": "windows",
"description": "Use the <code>browser.windows</code> API to interact with browser windows. You can use this API to create, modify, and rearrange windows in the browser.",

View File

@ -21,11 +21,6 @@ add_task(function* tabsSendMessageReply() {
if (msg == "content-script-ready") {
let tabId = sender.tab.id;
browser.tabs.sendMessage(tabId, "respond-never", response => {
browser.test.fail(`Got unexpected response callback: ${response}`);
browser.test.notifyFail("sendMessage");
});
Promise.all([
promiseResponse,
@ -34,12 +29,15 @@ add_task(function* tabsSendMessageReply() {
new Promise(resolve => browser.tabs.sendMessage(tabId, "respond-soon", resolve)),
browser.tabs.sendMessage(tabId, "respond-promise"),
browser.tabs.sendMessage(tabId, "respond-never"),
new Promise(resolve => {
browser.runtime.sendMessage("respond-never", response => { resolve(response); });
}),
browser.tabs.sendMessage(tabId, "respond-error").catch(error => Promise.resolve({error})),
browser.tabs.sendMessage(tabId, "throw-error").catch(error => Promise.resolve({error})),
browser.tabs.sendMessage(firstTab, "no-listener").catch(error => Promise.resolve({error})),
]).then(([response, respondNow, respondNow2, respondSoon, respondPromise, respondNever, respondError, throwError, noListener]) => {
]).then(([response, respondNow, respondNow2, respondSoon, respondPromise, respondNever, respondNever2, respondError, throwError, noListener]) => {
browser.test.assertEq("expected-response", response, "Content script got the expected response");
browser.test.assertEq("respond-now", respondNow, "Got the expected immediate response");
@ -47,6 +45,7 @@ add_task(function* tabsSendMessageReply() {
browser.test.assertEq("respond-soon", respondSoon, "Got the expected delayed response");
browser.test.assertEq("respond-promise", respondPromise, "Got the expected promise response");
browser.test.assertEq(undefined, respondNever, "Got the expected no-response resolution");
browser.test.assertEq(undefined, respondNever2, "Got the expected no-response resolution");
browser.test.assertEq("respond-error", respondError.error.message, "Got the expected error response");
browser.test.assertEq("throw-error", throwError.error.message, "Got the expected thrown error response");

View File

@ -0,0 +1,57 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
/* globals chrome */
function* testPermission(options) {
function background(options) {
browser.test.sendMessage("typeof-namespace", {
browser: typeof browser[options.namespace],
chrome: typeof chrome[options.namespace],
});
}
let extensionDetails = {
background: `(${background})(${JSON.stringify(options)})`,
};
let extension = ExtensionTestUtils.loadExtension(extensionDetails);
yield extension.startup();
let types = yield extension.awaitMessage("typeof-namespace");
equal(types.browser, "undefined", `Type of browser.${options.namespace} without manifest entry`);
equal(types.chrome, "undefined", `Type of chrome.${options.namespace} without manifest entry`);
yield extension.unload();
extensionDetails.manifest = options.manifest;
extension = ExtensionTestUtils.loadExtension(extensionDetails);
yield extension.startup();
types = yield extension.awaitMessage("typeof-namespace");
equal(types.browser, "object", `Type of browser.${options.namespace} with manifest entry`);
equal(types.chrome, "object", `Type of chrome.${options.namespace} with manifest entry`);
yield extension.unload();
}
add_task(function* test_browserAction() {
yield testPermission({
namespace: "browserAction",
manifest: {
browser_action: {},
},
});
});
add_task(function* test_pageAction() {
yield testPermission({
namespace: "pageAction",
manifest: {
page_action: {},
},
});
});

View File

@ -6,3 +6,4 @@ firefox-appdir = browser
[test_ext_bookmarks.js]
[test_ext_history.js]
[test_ext_manifest_commands.js]
[test_ext_manifest_permissions.js]

View File

@ -1703,12 +1703,12 @@ toolbarbutton.chevron > .toolbarbutton-icon {
#ctrlTab-panel {
-moz-appearance: none;
background: rgba(27%,27%,27%,.7);
background: hsla(0,0%,33%,.85);
color: white;
border-style: none;
padding: 20px 10px 10px;
font-weight: bold;
text-shadow: 0 0 1px rgb(27%,27%,27%), 0 0 2px rgb(27%,27%,27%);
text-shadow: 0 0 1px hsl(0,0%,12%), 0 0 2px hsl(0,0%,12%);
}
.ctrlTab-favicon[src] {

View File

@ -1,46 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16">
<style>
use:not(:target) {
display: none;
}
use {
fill: menutext;
}
use[id$="-active"] {
fill: -moz-menuhovertext;
}
use[id$="-disabled"] {
fill: graytext;
}
</style>
<defs>
<path id="back-shape" fill-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159 l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705 c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974 L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171 c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
<path id="forward-shape" fill-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159 L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14 c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974 l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082 c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
<path id="reload-shape" fill-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947 c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104 C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
<polygon id="stop-shape" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669 5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967 L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39 l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56 l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072 c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564 l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562 l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075 C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566 l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</defs>
<use id="back" xlink:href="#back-shape"/>
<use id="back-active" xlink:href="#back-shape"/>
<use id="back-disabled" xlink:href="#back-shape"/>
<use id="forward" xlink:href="#forward-shape"/>
<use id="forward-active" xlink:href="#forward-shape"/>
<use id="forward-disabled" xlink:href="#forward-shape"/>
<use id="reload" xlink:href="#reload-shape"/>
<use id="reload-active" xlink:href="#reload-shape"/>
<use id="reload-disabled" xlink:href="#reload-shape"/>
<use id="stop" xlink:href="#stop-shape"/>
<use id="stop-active" xlink:href="#stop-shape"/>
<use id="stop-disabled" xlink:href="#stop-shape"/>
<use id="bookmark" xlink:href="#bookmark-shape"/>
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -5,7 +5,7 @@
%include ../../shared/customizableui/panelUI.inc.css
.panel-subviews {
background-color: -moz-dialog;
background-color: var(--panel-arrowcontent-background);
}
#BMB_bookmarksPopup > menuitem[type="checkbox"] {

View File

@ -15,7 +15,6 @@ browser.jar:
* skin/classic/browser/devedition.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/Info.png
skin/classic/browser/menuPanel.png
skin/classic/browser/menuPanel@2x.png

View File

@ -3116,11 +3116,11 @@ menulist.translate-infobar-element > .menulist-dropmarker {
#ctrlTab-panel {
-moz-appearance: none;
-moz-window-shadow: none;
background: rgba(27%,27%,27%,.7);
background: hsla(0,0%,33%,.85);
color: white;
border-style: none;
padding: 20px 10px 10px;
text-shadow: 0 0 1px rgb(27%,27%,27%), 0 0 2px rgb(27%,27%,27%);
text-shadow: 0 0 1px hsl(0,0%,12%), 0 0 2px hsl(0,0%,12%);
}
.ctrlTab-favicon[src] {

View File

@ -1,46 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16">
<style>
use:not(:target) {
display: none;
}
use {
fill: menutext;
}
use[id$="-active"] {
fill: -moz-mac-menutextselect;
}
use[id$="-disabled"] {
fill: -moz-mac-menutextdisable;
}
</style>
<defs>
<path id="back-shape" fill-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159 l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705 c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974 L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171 c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
<path id="forward-shape" fill-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159 L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14 c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974 l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082 c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
<path id="reload-shape" fill-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947 c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104 C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
<polygon id="stop-shape" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669 5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967 L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39 l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56 l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072 c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564 l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562 l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075 C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566 l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</defs>
<use id="back" xlink:href="#back-shape"/>
<use id="back-active" xlink:href="#back-shape"/>
<use id="back-disabled" xlink:href="#back-shape"/>
<use id="forward" xlink:href="#forward-shape"/>
<use id="forward-active" xlink:href="#forward-shape"/>
<use id="forward-disabled" xlink:href="#forward-shape"/>
<use id="reload" xlink:href="#reload-shape"/>
<use id="reload-active" xlink:href="#reload-shape"/>
<use id="reload-disabled" xlink:href="#reload-shape"/>
<use id="stop" xlink:href="#stop-shape"/>
<use id="stop-active" xlink:href="#stop-shape"/>
<use id="stop-disabled" xlink:href="#stop-shape"/>
<use id="bookmark" xlink:href="#bookmark-shape"/>
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -15,7 +15,6 @@ browser.jar:
* skin/classic/browser/devedition.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/Info.png
skin/classic/browser/keyhole-circle.png
skin/classic/browser/keyhole-circle@2x.png

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<style>
path:not(:target),
polygon:not(:target) {
display: none;
}
</style>
<path id="back" fill-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159 l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705 c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974 L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171 c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
<path id="forward" fill-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159 L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14 c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974 l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082 c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
<path id="reload" fill-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947 c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104 C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
<polygon id="stop" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669 5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
<path id="bookmark" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967 L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39 l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56 l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072 c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564 l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
<path id="bookmarked" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562 l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075 C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566 l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -8,90 +8,44 @@
-moz-appearance: none;
}
#context-navigation > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
width: 16px;
height: 16px;
margin: 7px;
filter: url(chrome://browser/skin/filters.svg#fill);
fill: currentColor;
}
#context-back {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back");
}
#context-back[_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back-active");
}
#context-back[disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#back-disabled");
}
#context-forward {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward");
}
#context-forward[_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward-active");
}
#context-forward[disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#forward-disabled");
}
#context-reload {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload");
}
#context-reload[_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload-active");
}
#context-reload[disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#reload-disabled");
}
#context-stop {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop");
}
#context-stop[_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop-active");
}
#context-stop[disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#stop-disabled");
}
#context-bookmarkpage {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark");
}
#context-bookmarkpage[_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-active");
}
#context-bookmarkpage[disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmark-disabled");
}
#context-bookmarkpage[starred=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked");
}
#context-bookmarkpage[starred=true][_moz-menuactive=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked-active");
}
#context-bookmarkpage[starred=true][disabled=true] {
list-style-image: url("chrome://browser/skin/content-contextmenu.svg#bookmarked-disabled");
}
#context-back:-moz-locale-dir(rtl),
#context-forward:-moz-locale-dir(rtl),
#context-reload:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
#context-navigation > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
width: 16px;
height: 16px;
margin: 7px;
}
#context-media-eme-learnmore {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}

View File

@ -52,7 +52,7 @@
.downloadsPanelFooterButton {
-moz-appearance: none;
background-color: transparent;
color: black;
color: inherit;
margin: 0;
padding: 0;
min-height: 40px;

View File

@ -15,6 +15,7 @@
skin/classic/browser/aboutSocialError.css (../shared/aboutSocialError.css)
skin/classic/browser/aboutTabCrashed.css (../shared/aboutTabCrashed.css)
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
skin/classic/browser/content-contextmenu.svg (../shared/content-contextmenu.svg)
skin/classic/browser/addons/addon-install-blocked.svg (../shared/addons/addon-install-blocked.svg)
skin/classic/browser/addons/addon-install-confirm.svg (../shared/addons/addon-install-confirm.svg)
skin/classic/browser/addons/addon-install-downloading.svg (../shared/addons/addon-install-downloading.svg)

View File

@ -332,13 +332,6 @@
color: white;
}
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7),{
#toolbar-menubar:not(:-moz-lwtheme) {
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
}
}
/* Show borders on vista through win8, but not on win10 and later: */
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7),
@ -376,29 +369,6 @@
#appcontent:not(:-moz-lwtheme) {
background-color: -moz-dialog;
}
#main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
background-color: rgba(255,255,255,.5);
color: black;
}
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
#main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
border-radius: 4px;
}
/* Artificially draw window borders that are covered by lwtheme, see bug 591930.
* We use a different border for win8, and this is not necessary on win10+ */
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme {
border-top: 2px solid;
-moz-border-top-colors: @glassActiveBorderColor@ rgba(255,255,255,.6);
}
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme:-moz-window-inactive {
-moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
}
}
}
@media (-moz-windows-glass) {
@ -412,6 +382,27 @@
background-color: #556;
}
#toolbar-menubar:not(:-moz-lwtheme) {
text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
}
#main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
background-color: rgba(255,255,255,.5);
color: black;
border-radius: 4px;
}
/* Artificially draw window borders that are covered by lwtheme, see bug 591930.
* We use a different border for win8, and this is not necessary on win10+ */
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme {
border-top: 2px solid;
-moz-border-top-colors: @glassActiveBorderColor@ rgba(255,255,255,.6);
}
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel:-moz-lwtheme:-moz-window-inactive {
-moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
}
/* Glass Fog */
#TabsToolbar:not(:-moz-lwtheme) {

View File

@ -2353,12 +2353,12 @@ notification[value="translation"] {
#ctrlTab-panel {
-moz-appearance: none;
background: rgba(27%,27%,27%,.7);
background: hsla(0,0%,33%,.85);
color: white;
border-style: none;
padding: 20px 10px 10px;
font-weight: bold;
text-shadow: 0 0 1px rgb(27%,27%,27%), 0 0 2px rgb(27%,27%,27%);
text-shadow: 0 0 1px hsl(0,0%,12%), 0 0 2px hsl(0,0%,12%);
}
.ctrlTab-favicon[src] {

View File

@ -5,7 +5,7 @@
%include ../../shared/customizableui/panelUI.inc.css
.panel-subviews {
background-color: -moz-field;
background-color: var(--panel-arrowcontent-background);
}
#PanelUI-contents #zoom-out-btn {

View File

@ -17,7 +17,6 @@ browser.jar:
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/caption-buttons.svg
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/Info.png
skin/classic/browser/Info-XP.png
skin/classic/browser/keyhole-forward-mask.svg

View File

@ -49,34 +49,11 @@ AC_DEFUN([MOZ_CROSS_COMPILER],
[
echo "cross compiling from $host to $target"
_SAVE_CC="$CC"
_SAVE_CFLAGS="$CFLAGS"
_SAVE_LDFLAGS="$LDFLAGS"
if test -z "$HOST_AR_FLAGS"; then
HOST_AR_FLAGS="$AR_FLAGS"
fi
AC_CHECK_PROGS(HOST_RANLIB, $HOST_RANLIB ranlib, ranlib, :)
AC_CHECK_PROGS(HOST_AR, $HOST_AR ar, ar, :)
CC="$HOST_CC"
CFLAGS="$HOST_CFLAGS"
LDFLAGS="$HOST_LDFLAGS"
AC_MSG_CHECKING([whether the host c compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works])
AC_TRY_COMPILE([], [return(0);],
[ac_cv_prog_hostcc_works=1 AC_MSG_RESULT([yes])],
AC_MSG_ERROR([installation or configuration problem: host compiler $HOST_CC cannot create executables.]) )
CC="$HOST_CXX"
CFLAGS="$HOST_CXXFLAGS"
AC_MSG_CHECKING([whether the host c++ compiler ($HOST_CXX $HOST_CXXFLAGS $HOST_LDFLAGS) works])
AC_TRY_COMPILE([], [return(0);],
[ac_cv_prog_hostcxx_works=1 AC_MSG_RESULT([yes])],
AC_MSG_ERROR([installation or configuration problem: host compiler $HOST_CXX cannot create executables.]) )
CC=$_SAVE_CC
CFLAGS=$_SAVE_CFLAGS
LDFLAGS=$_SAVE_LDFLAGS
dnl AC_CHECK_PROGS manually goes through $PATH, and as such fails to handle
dnl absolute or relative paths. Relative paths wouldn't work anyways, but

View File

@ -60,7 +60,7 @@ def checking(what, callback=None):
log.info('no')
else:
log.info(display_ret)
if error:
if error is not None:
die(error)
return ret
return wrapped

View File

@ -18,47 +18,14 @@
# - `check_msg` is the message to be printed to accompany compiling the test
# program.
@template
@imports('textwrap')
def try_compile(includes=None, body='', language='C++', flags=None, check_msg=None):
includes = includes or []
source_lines = ['#include <%s>' % f for f in includes]
source = '\n'.join(source_lines) + '\n'
source += textwrap.dedent('''\
int
main(void)
{
%s
;
return 0;
}
''' % body)
compiler = {
'C': c_compiler,
'C++': cxx_compiler,
}[language]
if check_msg:
def checking_fn(fn):
return checking(check_msg, callback=lambda r: r is not None)(fn)
else:
def checking_fn(fn):
return fn
return compiler.try_compile(includes, body, flags, check_msg)
def get_flags():
if flags:
return flags[:]
@depends(cxx_compiler, c_compiler, extra_toolchain_flags)
@checking_fn
def check(cxx_info, c_info, extra_flags):
flags = get_flags() or []
flags += extra_flags
flags.append('-c')
info = {
'C': c_info,
'C++': cxx_info,
}[language]
return try_invoke_compiler(info.wrapper + [info.compiler] + info.flags,
language, source, flags,
onerror=lambda: None)
return check
# Checks for the presence of the given header on the target system by compiling
# a test program including that header. The return value of the template is a

View File

@ -0,0 +1,65 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@template
@imports('textwrap')
@imports(_from='mozbuild.configure', _import='DependsFunction')
def compiler_class(compiler):
class Compiler(DependsFunction):
# Generates a test program and attempts to compile it. In case of
# failure, the resulting check will return None. If the test program
# succeeds, it will return the output of the test program.
# - `includes` are the includes (as file names) that will appear at the
# top of the generated test program.
# - `body` is the code that will appear in the main function of the
# generated test program. `return 0;` is appended to the function
# body automatically.
# - `flags` are the flags to be passed to the compiler, in addition to
# `-c`.
# - `check_msg` is the message to be printed to accompany compiling the
# test program.
def try_compile(self, includes=None, body='', flags=None,
check_msg=None, onerror=lambda: None):
includes = includes or []
source_lines = ['#include <%s>' % f for f in includes]
source = '\n'.join(source_lines) + '\n'
source += textwrap.dedent('''\
int
main(void)
{
%s
;
return 0;
}
''' % body)
if check_msg:
def checking_fn(fn):
return checking(check_msg,
callback=lambda r: r is not None)(fn)
else:
def checking_fn(fn):
return fn
def get_flags():
if flags:
return flags[:]
@depends(self, extra_toolchain_flags)
@checking_fn
def func(compiler, extra_flags):
flags = get_flags() or []
flags += extra_flags
flags.append('-c')
return try_invoke_compiler(
compiler.wrapper + [compiler.compiler] + compiler.flags,
compiler.language, source, flags, onerror=onerror)
return func
compiler.__class__ = Compiler
return compiler

View File

@ -171,6 +171,8 @@ add_old_configure_assignment('TOOLCHAIN_PREFIX', toolchain_prefix)
# Compilers
# ==============================================================
include('compilers-util.configure')
def try_preprocess(compiler, language, source):
return try_invoke_compiler(compiler, language, source, ['-E'])
@ -533,7 +535,7 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
'C++': lambda: default_cxx_compilers(c_compiler),
}[language]()
what='the %s %s compiler' % (host_or_target_str, language),
what='the %s %s compiler' % (host_or_target_str, language)
option(env=var, nargs=1, help='Path to %s' % what)
@ -697,6 +699,7 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
flags=flags,
type=info.type,
version=info.version,
language=language,
)
@depends(valid_compiler)
@ -735,6 +738,15 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
add_old_configure_assignment(
'%s_VERSION' % var, delayed_getattr(valid_compiler, 'version'))
valid_compiler = compiler_class(valid_compiler)
def compiler_error():
raise FatalCheckError('Failed compiling a simple %s source with %s'
% (language, what))
valid_compiler.try_compile(check_msg='%s works' % what,
onerror=compiler_error)
return valid_compiler

View File

@ -15,6 +15,7 @@
"dump": true,
"exports": true,
"isWorker": true,
"indexedDB": true,
"loader": true,
"module": true,
"reportError": true,

View File

@ -11,7 +11,6 @@ const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const Services = require("Services");
const promise = require("promise");
const FocusManager = Services.focus;
const ELLIPSIS = Services.prefs.getComplexValue(
"intl.ellipsis",
@ -356,8 +355,6 @@ HTMLBreadcrumbs.prototype = {
this.shortcuts.on("Right", this.handleShortcut);
this.shortcuts.on("Left", this.handleShortcut);
this.shortcuts.on("Tab", this.handleShortcut);
this.shortcuts.on("Shift+Tab", this.handleShortcut);
// We will save a list of already displayed nodes in this array.
this.nodeHierarchy = [];
@ -365,6 +362,9 @@ HTMLBreadcrumbs.prototype = {
// Last selected node in nodeHierarchy.
this.currentIndex = -1;
// Used to build a unique breadcrumb button Id.
this.breadcrumbsWidgetItemId = 0;
this.update = this.update.bind(this);
this.updateSelectors = this.updateSelectors.bind(this);
this.selection.on("new-node-front", this.update);
@ -487,20 +487,18 @@ HTMLBreadcrumbs.prototype = {
},
/**
* Focus event handler. When breadcrumbs container gets focus, if there is an
* already selected breadcrumb, move focus to it.
* Focus event handler. When breadcrumbs container gets focus,
* aria-activedescendant needs to be updated to currently selected
* breadcrumb. Ensures that the focus stays on the container at all times.
* @param {DOMEvent} event.
*/
handleFocus: function (event) {
let control = this.container.querySelector(
".breadcrumbs-widget-item[checked]");
if (!this.suspendFocus && control && control !== event.target) {
// If we already have a selected breadcrumb and focus target is not it,
// move focus to selected breadcrumb
event.preventDefault();
control.focus();
}
this.suspendFocus = false;
event.stopPropagation();
this.outer.setAttribute("aria-activedescendant",
this.nodeHierarchy[this.currentIndex].button.id);
this.outer.focus();
},
/**
@ -508,10 +506,6 @@ HTMLBreadcrumbs.prototype = {
* @param {DOMEvent} event.
*/
handleClick: function (event) {
// When clicking a button temporarily suspend the behaviour that refocuses
// the currently selected button, to prevent flicking back to that button
// See Bug 1272011
this.suspendFocus = true;
let target = event.originalTarget;
if (target.tagName == "button") {
target.onBreadcrumbsClick();
@ -554,28 +548,17 @@ HTMLBreadcrumbs.prototype = {
event.stopPropagation();
this.keyPromise = (this.keyPromise || promise.resolve(null)).then(() => {
let currentnode;
if (name === "Left" && this.currentIndex != 0) {
let node = this.nodeHierarchy[this.currentIndex - 1].node;
return this.selection.setNodeFront(node, "breadcrumbs");
currentnode = this.nodeHierarchy[this.currentIndex - 1];
} else if (name === "Right" && this.currentIndex < this.nodeHierarchy.length - 1) {
let node = this.nodeHierarchy[this.currentIndex + 1].node;
return this.selection.setNodeFront(node, "breadcrumbs");
} else if (name === "Tab") {
// To move focus to next element following the breadcrumbs, relative
// element needs to be the last element in breadcrumbs' subtree.
let last = this.container.lastChild;
while (last && last.lastChild) {
last = last.lastChild;
}
FocusManager.moveFocus(this.chromeWin, last, FocusManager.MOVEFOCUS_FORWARD, 0);
} else if (name === "Shift+Tab") {
// Tabbing when breadcrumbs or its contents are focused should move focus to
// previous focusable element relative to breadcrumbs themselves.
let elt = this.container;
FocusManager.moveFocus(this.chromeWin, elt, FocusManager.MOVEFOCUS_BACKWARD, 0);
currentnode = this.nodeHierarchy[this.currentIndex + 1];
} else {
return null;
}
return null;
this.outer.setAttribute("aria-activedescendant", currentnode.button.id);
return this.selection.setNodeFront(currentnode.node, "breadcrumbs");
});
},
@ -671,7 +654,9 @@ HTMLBreadcrumbs.prototype = {
let button = this.chromeDoc.createElementNS(NS_XHTML, "button");
button.appendChild(this.prettyPrintNodeAsXHTML(node));
button.className = "breadcrumbs-widget-item";
button.id = "breadcrumbs-widget-item-" + this.breadcrumbsWidgetItemId++;
button.setAttribute("tabindex", "-1");
button.setAttribute("title", this.prettyPrintNodeAsText(node));
button.onclick = () => {

View File

@ -54,7 +54,8 @@
<vbox flex="1" id="markup-box">
</vbox>
<html:div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
<html:div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"/>
<html:div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
role="group" aria-label="&inspectorBreadcrumbsGroup;" tabindex="0" />
</html:div>
</vbox>
<splitter class="devtools-side-splitter"/>

View File

@ -62,6 +62,9 @@ add_task(function* () {
let newNodeFront = yield getNodeFront(newSelection, inspector);
is(newNodeFront, inspector.selection.nodeFront,
"The current selection is correct");
is(container.getAttribute("aria-activedescendant"),
container.querySelector("button[checked]").id,
"aria-activedescendant is set correctly");
currentSelection = newSelection;
}

View File

@ -61,7 +61,9 @@ add_task(function* () {
yield onHighlight;
// Ensure a breadcrumb is focused.
is(doc.activeElement, button, "Focus is on selected breadcrumb");
is(doc.activeElement, container, "Focus is on selected breadcrumb");
is(container.getAttribute("aria-activedescendant"), button.id,
"aria-activedescendant is set correctly");
for (let { desc, focused, key, options } of TEST_DATA) {
info(desc);
@ -71,9 +73,11 @@ add_task(function* () {
yield breadcrumbs.keyPromise;
if (focused) {
is(doc.activeElement, button, "Focus is on selected breadcrumb");
is(doc.activeElement, container, "Focus is on selected breadcrumb");
} else {
ok(!containsFocus(doc, container), "Focus is outside of breadcrumbs");
}
is(container.getAttribute("aria-activedescendant"), button.id,
"aria-activedescendant is set correctly");
}
});

View File

@ -19,4 +19,9 @@
<!-- LOCALIZATION NOTE (inspectorEyeDropper.label): A string displayed as the tooltip of
a button in the inspector which toggles the Eyedropper tool -->
<!ENTITY inspectorEyeDropper.label "Grab a color from the page">
<!ENTITY inspectorEyeDropper.label "Grab a color from the page">
<!-- LOCALIZATION NOTE (inspectorBreadcrumbsGroup): A string visible only to a
screen reader and is used to label (using aria-label attribute) a container
for inspector breadcrumbs -->
<!ENTITY inspectorBreadcrumbsGroup "Breadcrumbs">

View File

@ -179,16 +179,6 @@ inspectorPasteOuterHTML.accesskey=O
inspectorPasteInnerHTML.label=Inner HTML
inspectorPasteInnerHTML.accesskey=I
# LOCALIZATION NOTE (inspectorHTMLPasteExtraSubmenu.label): This is the label
# shown in the inspector contextual-menu for the sub-menu of the other Paste
# items, which allow to paste HTML:
# - before the current node
# - after the current node
# - as the first child of the current node
# - as the last child of the current node
inspectorHTMLPasteExtraSubmenu.label=Paste…
inspectorHTMLPasteExtraSubmenu.accesskey=t
# LOCALIZATION NOTE (inspectorHTMLPasteBefore.label): This is the label shown
# in the inspector contextual-menu for the item that lets users paste
# the HTML before the current node
@ -240,11 +230,6 @@ inspectorAttributesSubmenu.accesskey=A
inspectorAddAttribute.label=Add Attribute
inspectorAddAttribute.accesskey=A
# LOCALIZATION NOTE (inspectorSearchHTML.label2): This is the label shown as
# the placeholder in inspector search box
inspectorSearchHTML.label2=Search with CSS Selectors
inspectorSearchHTML.key=F
# LOCALIZATION NOTE (inspectorSearchHTML.label3): This is the label that is
# shown as the placeholder for the markup view search in the inspector.
inspectorSearchHTML.label3=Search HTML

View File

@ -249,15 +249,6 @@
color: hsl(210,30%,85%);
}
.breadcrumbs-widget-item:-moz-focusring {
outline: none;
}
.breadcrumbs-widget-item[checked]:-moz-focusring > .button-box {
outline: var(--theme-focus-outline);
outline-offset: -1px;
}
.breadcrumbs-widget-item > .button-box {
border: none;
padding-top: 0;

View File

@ -8,6 +8,7 @@ DIRS += [
'components',
'reducers',
'selectors',
'test',
'utils',
]

View File

@ -29,6 +29,9 @@ let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
let React = browserRequire("devtools/client/shared/vendor/react");
var TestUtils = React.addons.TestUtils;
const { stubConsoleMessages } = require("devtools/client/webconsole/new-console-output/test/stubs");
// @TODO Remove this.
let testCommands = new Map();
testCommands.set("console.log()", {
command: "console.log('foobar', 'test')",

View File

@ -0,0 +1,8 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'stubs.js',
)

View File

@ -58,20 +58,6 @@ add_task(function* () {
"Non-repeated messages aren't clobbered");
});
/**
* Test getRepeatId().
*/
add_task(function* () {
const message1 = prepareMessage(packet);
let message2 = prepareMessage(packet);
equal(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns same repeat id for objects with the same values");
message2 = message2.set("parameters", ["new args"]);
notEqual(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different values");
});
/**
* Test adding a console.clear message to the store.
*/
@ -122,7 +108,7 @@ add_task(function* () {
let newPacket = Object.assign({}, packet);
for (let i = 1; i <= userSetLimit + 1; i++) {
newPacket.message.parameters = [i];
newPacket.message.arguments = [i];
dispatch(actions.messageAdd(newPacket));
}

View File

@ -0,0 +1,99 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {
MESSAGE_SOURCE,
MESSAGE_TYPE,
MESSAGE_LEVEL,
// Legacy
CATEGORY_WEBDEV,
SEVERITY_LOG,
} = require("devtools/client/webconsole/new-console-output/constants");
const { ConsoleMessage } = require("devtools/client/webconsole/new-console-output/types");
exports.stubConsoleMessages = new Map([
[
"console.log('foobar', 'test')",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.LOG,
messageText: null,
parameters: ["foobar", "test"],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
[
"console.warn('danger, will robinson!')",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.WARN,
messageText: null,
parameters: ["danger, will robinson!"],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
[
"console.log(undefined)",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.LOG,
messageText: null,
parameters: [
{ type: "undefined" }
],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
[
"console.log(NaN)",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.LOG,
messageText: null,
parameters: [
{ type: "NaN" }
],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
[
"console.log(null)",
new ConsoleMessage({
allowRepeating: true,
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
level: MESSAGE_LEVEL.LOG,
messageText: null,
parameters: [
{ type: "null" }
],
repeat: 1,
repeatId: null,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
})
],
]);

View File

@ -13,47 +13,43 @@
<script type="text/javascript;version=1.8">
window.onload = Task.async(function* () {
const {
prepareMessage,
getRepeatId
} = require("devtools/client/webconsole/new-console-output/utils/messages");
const { getRepeatId } = require("devtools/client/webconsole/new-console-output/utils/messages");
yield testDuplicateValues();
yield testDifferentValues();
yield testDifferentSeverities();
yield testFalsyValues();
yield testConsoleVsJSTerm();
SimpleTest.finish();
function testDuplicateValues() {
const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
const {message: message2} = yield getPacket("console.log('same')", "consoleAPICall");
const message1 = stubConsoleMessages.get("console.log('foobar', 'test')");
const message2 = message1.set("repeat", 3);
is(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns same repeat id for objects with the same values");
}
function testDifferentValues() {
const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
const {message: message2} = yield getPacket("console.log('diff')", "consoleAPICall");
const message1 = stubConsoleMessages.get("console.log('foobar', 'test')");
const message2 = message1.set("parameters", ["funny", "monkey"]);
isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different values");
}
function testDifferentSeverities() {
const {message: message1} = yield getPacket("console.log('test')", "consoleAPICall");
const {message: message2} = yield getPacket("console.warn('test')", "consoleAPICall");
const message1 = stubConsoleMessages.get("console.log('foobar', 'test')");
const message2 = message1.set("level", "error");
isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for different severities");
}
function testFalsyValues() {
const {message: messageNaN} = yield getPacket("console.log(NaN)", "consoleAPICall");
const {message: messageUnd} = yield getPacket("console.log(undefined)", "consoleAPICall");
const {message: messageNul} = yield getPacket("console.log(null)", "consoleAPICall");
const messageNaN = stubConsoleMessages.get("console.log(NaN)");
const messageUnd = stubConsoleMessages.get("console.log(undefined)");
const messageNul = stubConsoleMessages.get("console.log(null)");
const repeatIds = new Set([
getRepeatId(messageNaN),
@ -62,25 +58,6 @@ window.onload = Task.async(function* () {
);
is(repeatIds.size, 3,
"getRepeatId() handles falsy values distinctly");
const {message: messageNaN2} = yield getPacket("console.log(NaN)", "consoleAPICall");
const {message: messageUnd2} = yield getPacket("console.log(undefined)", "consoleAPICall");
const {message: messageNul2} = yield getPacket("console.log(null)", "consoleAPICall");
is(getRepeatId(messageNaN), getRepeatId(messageNaN2),
"getRepeatId() handles NaN values");
is(getRepeatId(messageUnd), getRepeatId(messageUnd2),
"getRepeatId() handles undefined values");
is(getRepeatId(messageNul), getRepeatId(messageNul2),
"getRepeatId() handles null values");
}
function testConsoleVsJSTerm() {
const {message: message1} = yield getPacket("console.log(undefined)", "consoleAPICall");
const {result: message2} = yield getPacket("undefined");
isnot(getRepeatId(message1), getRepeatId(message2),
"getRepeatId() returns different repeat ids for console vs JSTerm");
}
});
</script>

View File

@ -8,6 +8,7 @@
const Immutable = require("devtools/client/shared/vendor/immutable");
exports.ConsoleCommand = Immutable.Record({
id: null,
allowRepeating: false,
messageText: null,
source: null,
@ -17,6 +18,7 @@ exports.ConsoleCommand = Immutable.Record({
});
exports.ConsoleMessage = Immutable.Record({
id: null,
allowRepeating: true,
source: null,
type: null,
@ -27,5 +29,4 @@ exports.ConsoleMessage = Immutable.Record({
repeatId: null,
category: "output",
severity: "log",
id: null,
});

View File

@ -30,11 +30,14 @@ function getNextMessageId() {
function prepareMessage(packet) {
// This packet is already in the expected packet structure. Simply return.
if (packet.source) {
return packet;
if (!packet.source) {
packet = transformPacket(packet);
}
return transformPacket(packet);
if (packet.allowRepeating) {
packet = packet.set("repeatId", getRepeatId(packet));
}
return packet.set("id", getNextMessageId());
}
/**
@ -77,10 +80,8 @@ function transformPacket(packet) {
level,
parameters,
messageText,
repeatId: getRepeatId(message),
category: CATEGORY_WEBDEV,
severity: level,
id: getNextMessageId(),
});
}
@ -97,10 +98,8 @@ function transformPacket(packet) {
source: MESSAGE_SOURCE.JAVASCRIPT,
type: MESSAGE_TYPE.LOG,
messageText: pageError.errorMessage,
repeatId: getRepeatId(pageError),
category: CATEGORY_JS,
severity: level,
id: getNextMessageId(),
});
}
@ -113,10 +112,8 @@ function transformPacket(packet) {
type: MESSAGE_TYPE.RESULT,
level: MESSAGE_LEVEL.LOG,
parameters: result,
repeatId: getRepeatId(result),
category: CATEGORY_OUTPUT,
severity: SEVERITY_LOG,
id: getNextMessageId(),
});
}
}
@ -124,10 +121,9 @@ function transformPacket(packet) {
// Helpers
function getRepeatId(message) {
let clonedMessage = JSON.parse(JSON.stringify(message));
delete clonedMessage.id;
delete clonedMessage.timeStamp;
return JSON.stringify(clonedMessage);
message = message.toJS();
delete message.repeat;
return JSON.stringify(message);
}
function convertCachedPacket(packet) {

View File

@ -8,7 +8,6 @@ const promise = require("promise");
const EventEmitter = require("devtools/shared/event-emitter");
const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
const {indexedDB} = require("sdk/indexed-db");
/**
* IndexedDB wrapper that just save project objects

View File

@ -4,7 +4,7 @@
"use strict";
const {Cc, Ci} = require("chrome");
const {Cc, Ci, Cu, CC} = require("chrome");
const events = require("sdk/event/core");
const protocol = require("devtools/shared/protocol");
const {LongStringActor} = require("devtools/server/actors/string");
@ -18,6 +18,20 @@ const { Task } = require("devtools/shared/task");
loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
loader.lazyImporter(this, "Sqlite", "resource://gre/modules/Sqlite.jsm");
// We give this a funny name to avoid confusion with the global
// indexedDB.
loader.lazyGetter(this, "indexedDBForStorage", () => {
// On xpcshell, we can't instantiate indexedDB without crashing
try {
let sandbox
= Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
{wantGlobalProperties: ["indexedDB"]});
return sandbox.indexedDB;
} catch (e) {
return {};
}
});
var gTrackedMessageManager = new Map();
// Maximum number of cookies/local storage key-value-pairs that can be sent
@ -1736,12 +1750,12 @@ var indexedDBHelpers = {
* database `name`.
*/
openWithPrincipal(principal, name) {
return require("indexedDB").openForPrincipal(principal, name);
return indexedDBForStorage.openForPrincipal(principal, name);
},
removeDB: Task.async(function* (host, principal, name) {
let result = new promise(resolve => {
let request = require("indexedDB").deleteForPrincipal(principal, name);
let request = indexedDBForStorage.deleteForPrincipal(principal, name);
request.onsuccess = () => {
resolve({});

View File

@ -39,155 +39,150 @@
* DOM elements, but they may include things like Blobs and typed arrays.
*
*/
const {Cc, Ci, Cu, Cr} = require("chrome");
const {indexedDB} = require("sdk/indexed-db");
"use strict";
const Promise = require("promise");
module.exports = (function () {
"use strict";
const DBNAME = "devtools-async-storage";
const DBVERSION = 1;
const STORENAME = "keyvaluepairs";
var db = null;
var DBNAME = "devtools-async-storage";
var DBVERSION = 1;
var STORENAME = "keyvaluepairs";
var db = null;
function withStore(type, onsuccess, onerror) {
if (db) {
var transaction = db.transaction(STORENAME, type);
var store = transaction.objectStore(STORENAME);
function withStore(type, onsuccess, onerror) {
if (db) {
let transaction = db.transaction(STORENAME, type);
let store = transaction.objectStore(STORENAME);
onsuccess(store);
} else {
let openreq = indexedDB.open(DBNAME, DBVERSION);
openreq.onerror = function withStoreOnError() {
onerror();
};
openreq.onupgradeneeded = function withStoreOnUpgradeNeeded() {
// First time setup: create an empty object store
openreq.result.createObjectStore(STORENAME);
};
openreq.onsuccess = function withStoreOnSuccess() {
db = openreq.result;
let transaction = db.transaction(STORENAME, type);
let store = transaction.objectStore(STORENAME);
onsuccess(store);
} else {
var openreq = indexedDB.open(DBNAME, DBVERSION);
openreq.onerror = function withStoreOnError() {
onerror();
};
}
}
function getItem(itemKey) {
return new Promise((resolve, reject) => {
let req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
let value = req.result;
if (value === undefined) {
value = null;
}
resolve(value);
};
openreq.onupgradeneeded = function withStoreOnUpgradeNeeded() {
// First time setup: create an empty object store
openreq.result.createObjectStore(STORENAME);
req = store.get(itemKey);
req.onerror = function getItemOnError() {
reject("Error in asyncStorage.getItem(): ", req.error.name);
};
openreq.onsuccess = function withStoreOnSuccess() {
db = openreq.result;
var transaction = db.transaction(STORENAME, type);
var store = transaction.objectStore(STORENAME);
onsuccess(store);
}, reject);
});
}
function setItem(itemKey, value) {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
let req = store.put(value, itemKey);
req.onerror = function setItemOnError() {
reject("Error in asyncStorage.setItem(): ", req.error.name);
};
}, reject);
});
}
function removeItem(itemKey) {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
let req = store.delete(itemKey);
req.onerror = function removeItemOnError() {
reject("Error in asyncStorage.removeItem(): ", req.error.name);
};
}, reject);
});
}
function clear() {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
let req = store.clear();
req.onerror = function clearOnError() {
reject("Error in asyncStorage.clear(): ", req.error.name);
};
}, reject);
});
}
function length() {
return new Promise((resolve, reject) => {
let req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
resolve(req.result);
};
req = store.count();
req.onerror = function lengthOnError() {
reject("Error in asyncStorage.length(): ", req.error.name);
};
}, reject);
});
}
function key(n) {
return new Promise((resolve, reject) => {
if (n < 0) {
resolve(null);
return;
}
}
function getItem(key) {
return new Promise((resolve, reject) => {
var req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
var value = req.result;
if (value === undefined) {
value = null;
}
resolve(value);
};
req = store.get(key);
req.onerror = function getItemOnError() {
reject("Error in asyncStorage.getItem(): ", req.error.name);
};
}, reject);
});
}
let req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
let cursor = req.result;
resolve(cursor ? cursor.key : null);
};
let advanced = false;
req = store.openCursor();
req.onsuccess = function keyOnSuccess() {
let cursor = req.result;
if (!cursor) {
// this means there weren"t enough keys
return;
}
if (n === 0 || advanced) {
// Either 1) we have the first key, return it if that's what they
// wanted, or 2) we"ve got the nth key.
return;
}
function setItem(key, value) {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
var req = store.put(value, key);
req.onerror = function setItemOnError() {
reject("Error in asyncStorage.setItem(): ", req.error.name);
};
}, reject);
});
}
// Otherwise, ask the cursor to skip ahead n records
advanced = true;
cursor.advance(n);
};
req.onerror = function keyOnError() {
reject("Error in asyncStorage.key(): ", req.error.name);
};
}, reject);
});
}
function removeItem(key) {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
var req = store.delete(key);
req.onerror = function removeItemOnError() {
reject("Error in asyncStorage.removeItem(): ", req.error.name);
};
}, reject);
});
}
function clear() {
return new Promise((resolve, reject) => {
withStore("readwrite", (store) => {
store.transaction.oncomplete = resolve;
var req = store.clear();
req.onerror = function clearOnError() {
reject("Error in asyncStorage.clear(): ", req.error.name);
};
}, reject);
});
}
function length() {
return new Promise((resolve, reject) => {
var req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
resolve(req.result);
};
req = store.count();
req.onerror = function lengthOnError() {
reject("Error in asyncStorage.length(): ", req.error.name);
};
}, reject);
});
}
function key(n) {
return new Promise((resolve, reject) => {
if (n < 0) {
resolve(null);
return;
}
var req;
withStore("readonly", (store) => {
store.transaction.oncomplete = function onComplete() {
var cursor = req.result;
resolve(cursor ? cursor.key : null);
};
var advanced = false;
req = store.openCursor();
req.onsuccess = function keyOnSuccess() {
var cursor = req.result;
if (!cursor) {
// this means there weren"t enough keys
return;
}
if (n === 0 || advanced) {
// Either 1) we have the first key, return it if that's what they
// wanted, or 2) we"ve got the nth key.
return;
}
// Otherwise, ask the cursor to skip ahead n records
advanced = true;
cursor.advance(n);
};
req.onerror = function keyOnError() {
reject("Error in asyncStorage.key(): ", req.error.name);
};
}, reject);
});
}
return {
getItem: getItem,
setItem: setItem,
removeItem: removeItem,
clear: clear,
length: length,
key: key
};
}());
exports.getItem = getItem;
exports.setItem = setItem;
exports.removeItem = removeItem;
exports.clear = clear;
exports.length = length;
exports.key = key;

View File

@ -204,19 +204,6 @@ defineLazyGetter(exports.modules, "xpcInspector", () => {
return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
});
defineLazyGetter(exports.modules, "indexedDB", () => {
// On xpcshell, we can't instantiate indexedDB without crashing
try {
let sandbox
= Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
{wantGlobalProperties: ["indexedDB"]});
return sandbox.indexedDB;
} catch (e) {
return {};
}
});
defineLazyGetter(exports.modules, "FileReader", () => {
let sandbox
= Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
@ -295,3 +282,4 @@ defineLazyGetter(globals, "CSS", () => {
defineLazyGetter(globals, "WebSocket", () => {
return Services.appShell.hiddenDOMWindow.WebSocket;
});
lazyRequireGetter(globals, "indexedDB", "sdk/indexed-db", true);

View File

@ -40,7 +40,7 @@ enum class ListAllowance { eDisallow, eAllow };
/**
* A comparator to sort nsCSSProperty values such that longhands are sorted
* before shorthands, and shorthands with less components are sorted before
* before shorthands, and shorthands with fewer components are sorted before
* shorthands with more components.
*
* Using this allows us to prioritize values specified by longhands (or smaller

View File

@ -291,6 +291,55 @@ Element::UpdateEditableState(bool aNotify)
}
}
int32_t
Element::TabIndex()
{
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::tabindex);
if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
return attrVal->GetIntegerValue();
}
return TabIndexDefault();
}
void
Element::Focus(mozilla::ErrorResult& aError)
{
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && domElement) {
aError = fm->SetFocus(domElement, 0);
}
}
void
Element::SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError)
{
nsAutoString value;
value.AppendInt(aTabIndex);
SetAttr(nsGkAtoms::tabindex, value, aError);
}
void
Element::Blur(mozilla::ErrorResult& aError)
{
if (!ShouldBlur(this)) {
return;
}
nsIDocument* doc = GetComposedDoc();
if (!doc) {
return;
}
nsPIDOMWindowOuter* win = doc->GetWindow();
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (win && fm) {
aError = fm->ClearFocus(win);
}
}
EventStates
Element::StyleStateFromLocks() const
{

View File

@ -193,6 +193,31 @@ public:
*/
void UpdateLinkState(EventStates aState);
virtual int32_t TabIndexDefault()
{
return -1;
}
/**
* Get tabIndex of this element. If not found, return TabIndexDefault.
*/
int32_t TabIndex();
/**
* Set tabIndex value to this element.
*/
void SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError);
/**
* Make focus on this element.
*/
virtual void Focus(mozilla::ErrorResult& aError);
/**
* Show blur and clear focus.
*/
virtual void Blur(mozilla::ErrorResult& aError);
/**
* The style state of this element. This is the real state of the element
* with any style locks applied for pseudo-class inspecting.

View File

@ -812,4 +812,22 @@ AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMP
"returned null, and inited correctly otherwise!");
}
AutoSlowOperation::AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: AutoJSAPI()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
Init();
}
void
AutoSlowOperation::CheckForInterrupt()
{
// JS_CheckForInterrupt expects us to be in a compartment.
JSAutoCompartment ac(cx(), xpc::UnprivilegedJunkScope());
JS_CheckForInterrupt(cx());
}
} // namespace mozilla

View File

@ -443,6 +443,23 @@ private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/**
* Use AutoSlowOperation when native side calls many JS callbacks in a row
* and slow script dialog should be activated if too much time is spent going
* through those callbacks.
* AutoSlowOperation puts a JSAutoRequest on the stack so that we don't continue
* to reset the watchdog and CheckForInterrupt can be then used to check whether
* JS execution should be interrupted.
*/
class MOZ_RAII AutoSlowOperation : public dom::AutoJSAPI
{
public:
explicit AutoSlowOperation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
void CheckForInterrupt();
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
} // namespace mozilla
#endif // mozilla_dom_ScriptSettings_h

View File

@ -885,10 +885,7 @@ nsDOMMutationObserver::HandleMutationsInternal()
return;
}
// We need the AutoSafeJSContext to ensure the slow script dialog is
// triggered. AutoSafeJSContext does that by pushing JSAutoRequest to stack.
// This needs to be outside the while loop.
AutoSafeJSContext cx;
AutoSlowOperation aso;
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
@ -910,7 +907,7 @@ nsDOMMutationObserver::HandleMutationsInternal()
}
}
delete observers;
JS_CheckForInterrupt(cx);
aso.CheckForInterrupt();
}
if (suppressedObservers) {

View File

@ -100,7 +100,7 @@ function getXHRLoadHandler(expectedResult, expectedLength, testName) {
"[XHR] Length of result in test " + testName);
ok(convertedData == expectedResult,
"[XHR] Content of result in test " + testName);
is(event.lengthComputable, true,
is(event.lengthComputable, event.total != 0,
"[XHR] lengthComputable in test " + testName);
is(event.loaded, expectedLength,
"[XHR] Loaded length in test " + testName);

View File

@ -24,6 +24,7 @@ var upload = null;
var currentEvents = null;
var expectedResponseText = null;
var uploadTotal = 0;
var currentProgress = -1;
function logEvent(evt) {
var i = 0;
@ -33,20 +34,41 @@ function logEvent(evt) {
!(evt.target instanceof currentEvents[i].target))) {
++i;
}
if (evt.target instanceof XMLHttpRequestUpload) {
if (evt.type == "loadstart") {
uploadTotal = evt.total
} else {
if (evt.type == "progress") {
ok(evt.lengthComputable, "event(" + evt.type + ").lengthComputable should be true.");
is(evt.lengthComputable, evt.total != 0, "event(" + evt.type + ").lengthComputable should be " + (evt.total != 0 ? true : false) + ".");
}
if (evt.total != uploadTotal && evt.total != 0) {
ok(false, "event(" + evt.type + ").total should not change during upload except to become 0 on error/abort/timeout.");
}
is(evt.total, uploadTotal, "event(" + evt.type + ").total should not change during upload.");
}
}
// There can be any number of repeated progress events, so special-case this.
if (evt.type == "progress") {
// Progress events can repeat, but their "loaded" value must increase.
if (currentProgress >= 0) {
ok(currentProgress < evt.loaded, "Progress should increase, got " +
evt.loaded + " after " + currentProgress);
currentProgress = evt.loaded;
return; // stay at the currentEvent, since we got progress instead of it.
}
// Starting a new progress event group.
currentProgress = evt.loaded;
} else {
// Reset the progress indicator on any other event type.
currentProgress = -1;
}
ok(i != currentEvents.length, "Extra or wrong event?");
is(evt.type, currentEvents[i].type, "Wrong event!")
ok(evt.target instanceof currentEvents[i].target,
"Wrong event target [" + evt.target + "," + evt.type + "]!");
// If we handled non-optional event, remove all optional events before the
// handled event and then the non-optional event from the list.
if (!currentEvents[i].optional) {
@ -84,6 +106,7 @@ function start(obj) {
upload = xhr.upload;
currentEvents = obj.expectedEvents;
expectedResponseText = obj.withUpload;
currentProgress = -1;
xhr.onload =
function(evt) {
if (expectedResponseText) {
@ -189,11 +212,12 @@ var tests =
[
{ method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false,
@ -207,11 +231,12 @@ var tests =
{ method: "GET", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false,
@ -225,11 +250,12 @@ var tests =
{ method: "GET", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false,
@ -243,11 +269,12 @@ var tests =
{ method: "GET", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "GET", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false,
@ -261,11 +288,12 @@ var tests =
{ method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false,
@ -280,101 +308,104 @@ var tests =
{ method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "load", optional: false},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "abort", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: true,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "load", optional: false},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "abort", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: true,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "load", optional: false},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: true},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "load", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "progress", optional: false},
{target: UPLOAD, type: "abort", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "progress", optional: false},
{target: XHR, type: "abort", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
{ method: "POST", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: true,
expectedEvents: [{target: XHR, type: "loadstart", optional: false},
{target: UPLOAD, type: "loadstart", optional: false},
{target: UPLOAD, type: "progress", optional: true},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false},
{target: UPLOAD, type: "error", optional: false},
{target: UPLOAD, type: "loadend", optional: false}]},
{target: UPLOAD, type: "loadend", optional: false},
{target: XHR, type: "error", optional: false},
{target: XHR, type: "loadend", optional: false}]},
];
function runTest() {
@ -383,7 +414,7 @@ function runTest() {
}
function nextTest() {
if (tests.length > 1) {
if (tests.length) {
setTimeout("runTest()", 0);
} else {
SimpleTest.finish();

View File

@ -41,10 +41,6 @@ const unsigned kFirstAxis = 0x30;
const unsigned kDesktopUsagePage = 0x1;
const unsigned kButtonUsagePage = 0x9;
// Arbitrary. In practice 10 buttons/6 axes is the near maximum.
const unsigned kMaxButtons = 32;
const unsigned kMaxAxes = 32;
// Multiple devices-changed notifications can be sent when a device
// is connected, because USB devices consist of multiple logical devices.
// Therefore, we wait a bit after receiving one before looking for
@ -104,7 +100,8 @@ WindowsGamepadService* MOZ_NON_OWNING_REF gService = nullptr;
nsCOMPtr<nsIThread> gMonitorThread = nullptr;
static bool sIsShutdown = false;
struct Gamepad {
class Gamepad {
public:
GamepadType type;
// Handle to raw input device
@ -120,20 +117,38 @@ struct Gamepad {
// WindowsGamepadService::mGamepads.
int id;
// Information about the physical device.
unsigned numAxes;
unsigned numButtons;
bool hasDpad;
HIDP_VALUE_CAPS dpadCaps;
bool buttons[kMaxButtons];
struct {
nsTArray<bool> buttons;
struct axisValue {
HIDP_VALUE_CAPS caps;
double value;
} axes[kMaxAxes];
};
nsTArray<axisValue> axes;
// Used during rescan to find devices that were disconnected.
bool present;
Gamepad(uint32_t aNumAxes,
uint32_t aNumButtons,
bool aHasDpad,
GamepadType aType) :
numAxes(aNumAxes),
numButtons(aNumButtons),
hasDpad(aHasDpad),
type(aType),
present(true)
{
buttons.SetLength(numButtons);
axes.SetLength(numAxes);
}
private:
Gamepad() {}
};
// Drop this in favor of decltype when we require a new enough SDK.
@ -212,7 +227,7 @@ ScaleAxis(ULONG value, LONG min, LONG max)
* represent it as 4 buttons, one for each cardinal direction.
*/
void
UnpackDpad(LONG dpad_value, const Gamepad* gamepad, bool buttons[kMaxButtons])
UnpackDpad(LONG dpad_value, const Gamepad* gamepad, nsTArray<bool>& buttons)
{
const unsigned kUp = gamepad->numButtons - 4;
const unsigned kDown = gamepad->numButtons - 3;
@ -449,13 +464,12 @@ WindowsGamepadService::ScanForXInputDevices()
}
// Not already present, add it.
Gamepad gamepad = {};
gamepad.type = kXInputGamepad;
gamepad.present = true;
gamepad.state = state;
Gamepad gamepad(kStandardGamepadAxes,
kStandardGamepadButtons,
true,
kXInputGamepad);
gamepad.userIndex = i;
gamepad.numButtons = kStandardGamepadButtons;
gamepad.numAxes = kStandardGamepadAxes;
gamepad.state = state;
gamepad.id = service->AddGamepad("xinput",
GamepadMappingType::Standard,
kStandardGamepadButtons,
@ -621,8 +635,6 @@ WindowsGamepadService::GetRawGamepad(HANDLE handle)
return false;
}
Gamepad gamepad = {};
// Device name is a mostly-opaque string.
if (GetRawInputDeviceInfo(handle, RIDI_DEVICENAME, nullptr, &size) == kRawInputError) {
return false;
@ -689,12 +701,12 @@ WindowsGamepadService::GetRawGamepad(HANDLE handle)
!= HIDP_STATUS_SUCCESS) {
return false;
}
uint32_t numButtons = 0;
for (unsigned i = 0; i < count; i++) {
// Each buttonCaps is typically a range of buttons.
gamepad.numButtons +=
numButtons +=
buttonCaps[i].Range.UsageMax - buttonCaps[i].Range.UsageMin + 1;
}
gamepad.numButtons = std::min(gamepad.numButtons, kMaxButtons);
// Enumerate value caps, which represent axes and d-pads.
count = caps.NumberInputValueCaps;
@ -706,36 +718,41 @@ WindowsGamepadService::GetRawGamepad(HANDLE handle)
}
nsTArray<HIDP_VALUE_CAPS> axes;
// Sort the axes by usagePage and usage to expose a consistent ordering.
bool hasDpad;
HIDP_VALUE_CAPS dpadCaps;
HidValueComparator comparator;
for (unsigned i = 0; i < count; i++) {
if (valueCaps[i].UsagePage == kDesktopUsagePage
&& valueCaps[i].Range.UsageMin == kUsageDpad
// Don't know how to handle d-pads that return weird values.
&& valueCaps[i].LogicalMax - valueCaps[i].LogicalMin == 7
// Can't overflow buttons
&& gamepad.numButtons + 4 < kMaxButtons) {
&& valueCaps[i].LogicalMax - valueCaps[i].LogicalMin == 7) {
// d-pad gets special handling.
// Ostensibly HID devices can expose multiple d-pads, but this
// doesn't happen in practice.
gamepad.hasDpad = true;
gamepad.dpadCaps = valueCaps[i];
hasDpad = true;
dpadCaps = valueCaps[i];
// Expose d-pad as 4 additional buttons.
gamepad.numButtons += 4;
numButtons += 4;
} else {
axes.InsertElementSorted(valueCaps[i], comparator);
}
}
gamepad.numAxes = std::min<size_t>(axes.Length(), kMaxAxes);
uint32_t numAxes = axes.Length();
// Not already present, add it.
Gamepad gamepad(numAxes,
numButtons,
true,
kRawInputGamepad);
gamepad.handle = handle;
for (unsigned i = 0; i < gamepad.numAxes; i++) {
if (i >= kMaxAxes) {
break;
}
gamepad.axes[i].caps = axes[i];
}
gamepad.type = kRawInputGamepad;
gamepad.handle = handle;
gamepad.present = true;
gamepad.id = service->AddGamepad(gamepad_id,
GamepadMappingType::_empty,
gamepad.numButtons,
@ -753,8 +770,8 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle)
RefPtr<GamepadPlatformService> service =
GamepadPlatformService::GetParentService();
if (service) {
return true;
if (!service) {
return false;
}
// First, get data from the handle
@ -798,8 +815,11 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle)
return false;
}
bool buttons[kMaxButtons] = { false };
usageLength = std::min<ULONG>(usageLength, kMaxButtons);
nsTArray<bool> buttons(gamepad->numButtons);
buttons.SetLength(gamepad->numButtons);
// If we don't zero out the buttons array first, sometimes it can reuse values.
memset(buttons.Elements(), 0, gamepad->numButtons * sizeof(bool));
for (unsigned i = 0; i < usageLength; i++) {
buttons[usages[i] - 1] = true;
}

View File

@ -1145,6 +1145,7 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
, mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown)
, mDisabledChanged(false)
, mValueChanged(false)
, mLastValueChangeWasInteractive(false)
, mCheckedChanged(false)
, mChecked(false)
, mHandlingSelectEvent(false)
@ -1326,6 +1327,7 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
break;
}
it->mLastValueChangeWasInteractive = mLastValueChangeWasInteractive;
it.forget(aResult);
return NS_OK;
}
@ -3071,7 +3073,8 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue, uint32_t aFlags)
}
}
if (!mParserCreating) {
OnValueChanged(true);
OnValueChanged(/* aNotify = */ true,
/* aWasInteractiveUserChange = */ false);
}
// else DoneCreatingElement calls us again once mParserCreating is false
}
@ -6065,6 +6068,7 @@ HTMLInputElement::Reset()
// We should be able to reset all dirty flags regardless of the type.
SetCheckedChanged(false);
SetValueChanged(false);
mLastValueChangeWasInteractive = false;
switch (GetValueMode()) {
case VALUE_MODE_VALUE:
@ -6917,9 +6921,10 @@ HTMLInputElement::SetCustomValidity(const nsAString& aError)
bool
HTMLInputElement::IsTooLong()
{
if (!MaxLengthApplies() ||
!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength) ||
!mValueChanged) {
if (!mValueChanged ||
!mLastValueChangeWasInteractive ||
!MaxLengthApplies() ||
!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength)) {
return false;
}
@ -7192,10 +7197,7 @@ HTMLInputElement::HasBadInput() const
void
HTMLInputElement::UpdateTooLongValidityState()
{
// TODO: this code will be re-enabled with bug 613016 and bug 613019.
#if 0
SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
#endif
}
void
@ -7735,8 +7737,10 @@ HTMLInputElement::InitializeKeyboardEventListeners()
}
NS_IMETHODIMP_(void)
HTMLInputElement::OnValueChanged(bool aNotify)
HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
{
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
UpdateAllValidityStates(aNotify);
if (HasDirAuto()) {

View File

@ -229,7 +229,7 @@ public:
NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) override;
NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify) override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
NS_IMETHOD_(bool) HasCachedSelection() override;
void GetDisplayFileName(nsAString& aFileName) const;
@ -1449,6 +1449,7 @@ protected:
nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
bool mDisabledChanged : 1;
bool mValueChanged : 1;
bool mLastValueChangeWasInteractive : 1;
bool mCheckedChanged : 1;
bool mChecked : 1;
bool mHandlingSelectEvent : 1;

View File

@ -55,6 +55,7 @@ HTMLTextAreaElement::HTMLTextAreaElement(already_AddRefed<mozilla::dom::NodeInfo
FromParser aFromParser)
: nsGenericHTMLFormElementWithState(aNodeInfo),
mValueChanged(false),
mLastValueChangeWasInteractive(false),
mHandlingSelect(false),
mDoneAddingChildren(!aFromParser),
mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
@ -1344,7 +1345,9 @@ HTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
bool
HTMLTextAreaElement::IsTooLong()
{
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength) || !mValueChanged) {
if (!mValueChanged ||
!mLastValueChangeWasInteractive ||
!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength)) {
return false;
}
@ -1375,10 +1378,7 @@ HTMLTextAreaElement::IsValueMissing() const
void
HTMLTextAreaElement::UpdateTooLongValidityState()
{
// TODO: this code will be re-enabled with bug 613016 and bug 613019.
#if 0
SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
#endif
}
void
@ -1525,8 +1525,10 @@ HTMLTextAreaElement::InitializeKeyboardEventListeners()
}
NS_IMETHODIMP_(void)
HTMLTextAreaElement::OnValueChanged(bool aNotify)
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
{
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
// Update the validity state
bool validBefore = IsValid();
UpdateTooLongValidityState();

View File

@ -106,7 +106,7 @@ public:
NS_IMETHOD_(void) UpdatePlaceholderVisibility(bool aNotify) override;
NS_IMETHOD_(bool) GetPlaceholderVisibility() override;
NS_IMETHOD_(void) InitializeKeyboardEventListeners() override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify) override;
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) override;
NS_IMETHOD_(bool) HasCachedSelection() override;
// nsIContent
@ -293,6 +293,8 @@ protected:
nsCOMPtr<nsIControllers> mControllers;
/** Whether or not the value has changed since its default value was given. */
bool mValueChanged;
/** Whether or not the last change to the value was made interactively by the user. */
bool mLastValueChangeWasInteractive;
/** Whether or not we are already handling select event. */
bool mHandlingSelect;
/** Whether or not we are done adding children (always true if not

View File

@ -33,6 +33,7 @@
#include "nsIObserver.h"
#include "nsIStreamListener.h"
#include "nsISupportsImpl.h"
#include "nsISupportsPrimitives.h"
#include "nsMappedAttributes.h"
#include "nsNetUtil.h"
#include "nsRuleData.h"
@ -73,15 +74,72 @@ static constexpr nsAttrValue::EnumTable kKindTable[] = {
// at all is specified, it's treated as "subtitles" in GetKind
static constexpr const nsAttrValue::EnumTable* kKindTableInvalidValueDefault = &kKindTable[4];
class WindowDestroyObserver final : public nsIObserver
{
NS_DECL_ISUPPORTS
public:
explicit WindowDestroyObserver(HTMLTrackElement* aElement, uint64_t aWinID)
: mTrackElement(aElement)
, mInnerID(aWinID)
{
RegisterWindowDestroyObserver();
}
void RegisterWindowDestroyObserver()
{
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, "inner-window-destroyed", false);
}
}
void UnRegisterWindowDestroyObserver()
{
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, "inner-window-destroyed");
}
mTrackElement = nullptr;
}
NS_IMETHODIMP Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) override
{
MOZ_ASSERT(NS_IsMainThread());
if (strcmp(aTopic, "inner-window-destroyed") == 0) {
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
uint64_t innerID;
nsresult rv = wrapper->GetData(&innerID);
NS_ENSURE_SUCCESS(rv, rv);
if (innerID == mInnerID) {
if (mTrackElement) {
mTrackElement->NotifyShutdown();
}
UnRegisterWindowDestroyObserver();
}
}
return NS_OK;
}
private:
~WindowDestroyObserver() {};
HTMLTrackElement* mTrackElement;
uint64_t mInnerID;
};
NS_IMPL_ISUPPORTS(WindowDestroyObserver, nsIObserver);
/** HTMLTrackElement */
HTMLTrackElement::HTMLTrackElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mLoadResourceDispatched(false)
, mWindowDestroyObserver(nullptr)
{
}
HTMLTrackElement::~HTMLTrackElement()
{
if (mWindowDestroyObserver) {
mWindowDestroyObserver->UnRegisterWindowDestroyObserver();
}
NotifyShutdown();
}
NS_IMPL_ELEMENT_CLONE(HTMLTrackElement)
@ -263,6 +321,10 @@ HTMLTrackElement::LoadResource()
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
mChannel = channel;
nsISupports* parentObject = OwnerDoc()->GetParentObject();
NS_ENSURE_TRUE_VOID(parentObject);
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(parentObject);
mWindowDestroyObserver = new WindowDestroyObserver(this, window->WindowID());
}
nsresult
@ -371,5 +433,15 @@ HTMLTrackElement::DropChannel()
mChannel = nullptr;
}
void
HTMLTrackElement::NotifyShutdown()
{
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
}
mChannel = nullptr;
mListener = nullptr;
}
} // namespace dom
} // namespace mozilla

View File

@ -24,6 +24,7 @@ namespace mozilla {
namespace dom {
class WebVTTListener;
class WindowDestroyObserver;
class HTMLTrackElement final : public nsGenericHTMLElement
{
@ -113,6 +114,8 @@ public:
void DropChannel();
void NotifyShutdown();
protected:
virtual ~HTMLTrackElement();
@ -136,6 +139,8 @@ protected:
private:
void DispatchLoadResource();
bool mLoadResourceDispatched;
RefPtr<WindowDestroyObserver> mWindowDestroyObserver;
};
} // namespace dom

View File

@ -2582,34 +2582,6 @@ nsGenericHTMLFormElement::IsLabelable() const
//----------------------------------------------------------------------
void
nsGenericHTMLElement::Blur(mozilla::ErrorResult& aError)
{
if (!ShouldBlur(this)) {
return;
}
nsIDocument* doc = GetComposedDoc();
if (!doc) {
return;
}
nsPIDOMWindowOuter* win = doc->GetWindow();
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (win && fm) {
aError = fm->ClearFocus(win);
}
}
void
nsGenericHTMLElement::Focus(ErrorResult& aError)
{
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
aError = fm->SetFocus(this, 0);
}
}
void
nsGenericHTMLElement::Click()
{

View File

@ -51,6 +51,8 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase,
public nsIDOMHTMLElement
{
public:
using Element::SetTabIndex;
using Element::Focus;
explicit nsGenericHTMLElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElementBase(aNodeInfo)
{
@ -103,20 +105,6 @@ public:
SetHTMLBoolAttr(nsGkAtoms::hidden, aHidden, aError);
}
virtual void Click();
virtual int32_t TabIndexDefault()
{
return -1;
}
int32_t TabIndex()
{
return GetIntAttr(nsGkAtoms::tabindex, TabIndexDefault());
}
void SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError)
{
SetHTMLIntAttr(nsGkAtoms::tabindex, aTabIndex, aError);
}
virtual void Focus(mozilla::ErrorResult& aError);
virtual void Blur(mozilla::ErrorResult& aError);
void GetAccessKey(nsString& aAccessKey)
{
GetHTMLAttr(nsGkAtoms::accesskey, aAccessKey);

View File

@ -169,7 +169,7 @@ public:
/**
* Callback called whenever the value is changed.
*/
NS_IMETHOD_(void) OnValueChanged(bool aNotify) = 0;
NS_IMETHOD_(void) OnValueChanged(bool aNotify, bool aWasInteractiveUserChange) = 0;
static const int32_t DEFAULT_COLS = 20;
static const int32_t DEFAULT_ROWS = 1;

View File

@ -978,7 +978,8 @@ nsTextInputListener::EditAction()
}
if (!mSettingValue) {
mTxtCtrlElement->OnValueChanged(true);
mTxtCtrlElement->OnValueChanged(/* aNotify = */ true,
/* aWasInteractiveUserChange = */ true);
}
return NS_OK;
@ -2182,7 +2183,8 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
// can assume that it's safe to notify.
ValueWasChanged(!!mRootNode);
mTextCtrlElement->OnValueChanged(!!mRootNode);
mTextCtrlElement->OnValueChanged(/* aNotify = */ !!mRootNode,
/* aWasInteractiveUserChange = */ false);
return true;
}

View File

@ -368,6 +368,7 @@ skip-if = buildapp == 'mulet' # TC: Bug 1144079 - Re-enable Mulet mochitests and
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-debug(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-desktop(form control not selected/checked with synthesizeMouse, also fails on Android)
[test_bug613113.html]
skip-if = buildapp == 'b2g' # b2g(bug 587671, need an invalidformsubmit observer) b2g-debug(bug 587671, need an invalidformsubmit observer) b2g-desktop(bug 587671, need an invalidformsubmit observer)
[test_bug613019.html]
[test_bug613722.html]
[test_bug613979.html]
[test_bug615595.html]

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=613019
-->
<head>
<title>Test for Bug 613019</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613019">Mozilla Bug 613019</a>
<div id="content">
<input type="text" maxlength="2" style="width:200px" value="Test">
<textarea maxlength="2" style="width:200px">Test</textarea>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 613019 **/
function testInteractivityOfValidityStates(elem) {
// verify that user interactivity is necessary for validity state to apply.
is(elem.value, "Test", "Element has incorrect starting value.");
is(elem.validity.tooLong, false, "Element should not be tooLong.");
elem.focus();
synthesizeKey("VK_BACK_SPACE", {});
is(elem.value, "Tes", "Element value was not changed correctly.");
is(elem.validity.tooLong, true, "Element should still be tooLong.");
synthesizeKey("VK_BACK_SPACE", {});
is(elem.value, "Te", "Element value was not changed correctly.");
is(elem.validity.tooLong, false, "Element should no longer be tooLong.");
elem.value = "Test";
is(elem.validity.tooLong, false,
"Element should not be tooLong after non-interactive value change.");
}
function test() {
window.getSelection().removeAllRanges();
testInteractivityOfValidityStates(document.querySelector("input[type=text]"));
testInteractivityOfValidityStates(document.querySelector("textarea"));
SimpleTest.finish();
}
window.onload = function() {
SimpleTest.waitForExplicitFinish();
setTimeout(test, 0);
};
</script>
</pre>
</body>
</html>

View File

@ -164,7 +164,7 @@
#endif
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#include "nsAccessibilityService.h"
#endif
#ifndef MOZ_SIMPLEPUSH
@ -2469,8 +2469,7 @@ ContentChild::RecvActivateA11y()
#ifdef ACCESSIBILITY
// Start accessibility in content process if it's running in chrome
// process.
nsCOMPtr<nsIAccessibilityService> accService =
services::GetAccessibilityService();
GetOrCreateAccService();
#endif
return true;
}

View File

@ -89,6 +89,7 @@ NS_IMETHODIMP
WebVTTListener::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
VTT_LOG("WebVTTListener::OnStartRequest\n");
return NS_OK;
}
@ -97,6 +98,7 @@ WebVTTListener::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatus)
{
VTT_LOG("WebVTTListener::OnStopRequest\n");
if (NS_FAILED(aStatus)) {
mElement->SetReadyState(TextTrackReadyState::FailedToLoad);
}
@ -136,6 +138,7 @@ WebVTTListener::OnDataAvailable(nsIRequest* aRequest,
uint64_t aOffset,
uint32_t aCount)
{
VTT_LOG("WebVTTListener::OnDataAvailable\n");
uint32_t count = aCount;
while (count > 0) {
uint32_t read;

View File

@ -304,7 +304,7 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason)
D3DPRESENT_PARAMETERS params = {0};
params.BackBufferWidth = 1;
params.BackBufferHeight = 1;
params.BackBufferFormat = D3DFMT_UNKNOWN;
params.BackBufferFormat = D3DFMT_A8R8G8B8;
params.BackBufferCount = 1;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.hDeviceWindow = nullptr;

View File

@ -89,13 +89,13 @@ class VideoPuppeteer(object):
self.video = videos_found[0]
self.marionette.execute_script("log('video element obtained');")
if autostart:
self.start();
self.start()
def start(self):
# To get an accurate expected_duration, playback must have started
wait = Wait(self, timeout=self.timeout)
verbose_until(wait, self, lambda v: v.current_time > 0,
"Check if video current_time > 0")
verbose_until(wait, self, playback_started,
"Check if video has played some range")
self._start_time = self.current_time
self._start_wall_time = clock()
self.update_expected_duration()
@ -173,6 +173,20 @@ class VideoPuppeteer(object):
"""
return self.expected_duration - self.current_time
@property
def played(self):
"""
:return: A TimeRanges objected containing the played time ranges.
"""
raw_time_ranges = self.execute_video_script(
'var played = arguments[0].wrappedJSObject.played;'
'var timeRanges = [];'
'for (var i = 0; i < played.length; i++) {'
'timeRanges.push([played.start(i), played.end(i)]);'
'}'
'return [played.length, timeRanges];')
return TimeRanges(raw_time_ranges[0], raw_time_ranges[1])
@property
def video_src(self):
"""
@ -277,6 +291,26 @@ class VideoException(Exception):
pass
class TimeRanges:
"""
Class to represent the TimeRanges data returned by played(). Exposes a
similar interface to the JavaScript TimeRanges object.
"""
def __init__(self, length, ranges):
self.length = length
self.ranges = [(pair[0], pair[1]) for pair in ranges]
def __repr__(self):
return 'TimeRanges: length: {}, ranges: {}'\
.format(self.length, self.ranges)
def start(self, index):
return self.ranges[index][0]
def end(self, index):
return self.ranges[index][1]
def playback_started(video):
"""
Determine if video has started
@ -286,9 +320,12 @@ def playback_started(video):
:return: True if is playing; False otherwise
"""
try:
return video.current_time > video._start_time
played_ranges = video.played
return played_ranges.length > 0 and \
played_ranges.start(0) < played_ranges.end(0) and \
played_ranges.end(0) > 0.0
except Exception as e:
print ('Got exception %s' % e)
print ('Got exception {}'.format(e))
return False

View File

@ -23,8 +23,8 @@ class TestBasicYouTubePlayback(MediaTestCase):
interval=1)
try:
verbose_until(wait, youtube,
lambda y: y.video_src.startswith('mediasource'),
"Failed to find 'mediasource' in video src url.")
lambda y: y.video_src.startswith('blob'),
"Failed to find 'blob' in video src url.")
except TimeoutException as e:
raise self.failureException(e)

View File

@ -17,4 +17,4 @@ mozversion==1.4
wptserve==1.3.0
marionette-client==3.1.0
marionette-driver==2.0.0
firefox-puppeteer >= 50.0.0, <51.0.0
firefox-puppeteer >= 51.0.0, <52.0.0

View File

@ -25,7 +25,7 @@ support-files =
[test_a_noOp.html]
[test_dataChannel_basicAudio.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Bug 962984 for debug, bug 963244 for opt
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # Bug 962984 for debug, bug 963244 for opt
[test_dataChannel_basicAudioVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_dataChannel_basicAudioVideoNoBundle.html]
@ -85,7 +85,7 @@ skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # copied from basi
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing slow on b2g)
[test_peerConnection_addIceCandidate.html]
[test_peerConnection_addtrack_removetrack_events.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudio.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
[test_peerConnection_basicAudioNATSrflx.html]
@ -204,9 +204,9 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' &
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_toJSON.html]
[test_peerConnection_trackDisabling_clones.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_trackDisabling.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_twoAudioStreams.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_twoAudioTracksInOneStream.html]
@ -227,13 +227,13 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == "android"
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (android_version == '18' && debug)
[test_peerConnection_addSecondAudioStream.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # emulator is too slow to finish a renegotiation test in under 5 minutes
[test_peerConnection_answererAddSecondAudioStream.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # emulator is too slow to finish a renegotiation test in under 5 minutes
[test_peerConnection_removeAudioTrack.html]
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_removeThenAddAudioTrack.html]
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_addSecondVideoStream.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || android_version == '18'
@ -257,12 +257,12 @@ skip-if = toolkit == 'gonk' || android_version == '18'
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || android_version == '18'
[test_peerConnection_addDataChannel.html]
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # emulator seems to be so slow that DTLS cannot establish properly, android(bug 1240256, intermittent ICE failures starting w/bug 1232082, possibly from timeout)
[test_peerConnection_addDataChannelNoBundle.html]
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # b2g(emulator seems to be so slow that DTLS cannot establish properly), android(bug 1240256, intermittent ICE failures starting w/bug 1232082, possibly from timeout)
[test_peerConnection_verifyAudioAfterRenegotiation.html]
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || android_version == '18' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_verifyVideoAfterRenegotiation.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || android_version == '18'
@ -274,7 +274,7 @@ skip-if = toolkit == 'gonk' || android_version == '18'
skip-if = toolkit == 'gonk' || android_version == '18'
[test_peerConnection_webAudio.html]
tags = webaudio webrtc
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_localRollback.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
[test_peerConnection_localReofferRollback.html]
@ -282,7 +282,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
[test_peerConnection_remoteRollback.html]
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_remoteReofferRollback.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_selftest.html]
# Bug 1227781: Crash with bogus TURN server.
[test_peerConnection_bug1227781.html]

View File

@ -1460,10 +1460,10 @@ PeerConnectionWrapper.prototype = {
info("Checking RTP packet flow for track " + track.id);
var retry = () => this._pc.getStats(track)
var retry = (delay) => this._pc.getStats(track)
.then(stats => hasFlow(stats)? ok(true, "RTP flowing for track " + track.id) :
wait(200).then(retry));
return retry();
wait(delay).then(retry(1000)));
return retry(200);
},
/**

View File

@ -125,9 +125,6 @@ MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
#endif
// XXX
gFarendObserver = new AudioOutputObserver();
NS_NewNamedThread("AudioGUM", getter_AddRefs(mThread));
MOZ_ASSERT(mThread);
}
void
@ -409,7 +406,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
// XXX Small window where the device list/index could change!
audioinput = new mozilla::AudioInputCubeb(mVoiceEngine, i);
}
aSource = new MediaEngineWebRTCMicrophoneSource(mThread, mVoiceEngine, audioinput,
aSource = new MediaEngineWebRTCMicrophoneSource(mVoiceEngine, audioinput,
i, deviceName, uniqueId);
mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
aASources->AppendElement(aSource);
@ -450,11 +447,6 @@ MediaEngineWebRTC::Shutdown()
mozilla::camera::Shutdown();
AudioInputCubeb::CleanupGlobalData();
if (mThread) {
mThread->Shutdown();
mThread = nullptr;
}
}
}

View File

@ -419,8 +419,7 @@ class MediaEngineWebRTCMicrophoneSource : public MediaEngineAudioSource,
{
typedef MediaEngineAudioSource Super;
public:
MediaEngineWebRTCMicrophoneSource(nsIThread* aThread,
webrtc::VoiceEngine* aVoiceEnginePtr,
MediaEngineWebRTCMicrophoneSource(webrtc::VoiceEngine* aVoiceEnginePtr,
mozilla::AudioInput* aAudioInput,
int aIndex,
const char* name,
@ -543,7 +542,6 @@ private:
nsTArray<RefPtr<SourceMediaStream>> mSources;
nsTArray<PrincipalHandle> mPrincipalHandles; // Maps to mSources.
nsCOMPtr<nsIThread> mThread;
int mCapIndex;
int mChannel;
TrackID mTrackID;

View File

@ -184,7 +184,6 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame
}
MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
nsIThread* aThread,
webrtc::VoiceEngine* aVoiceEnginePtr,
mozilla::AudioInput* aAudioInput,
int aIndex,
@ -194,7 +193,6 @@ MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
, mVoiceEngine(aVoiceEnginePtr)
, mAudioInput(aAudioInput)
, mMonitor("WebRTCMic.Monitor")
, mThread(aThread)
, mCapIndex(aIndex)
, mChannel(-1)
, mStarted(false)
@ -616,11 +614,7 @@ MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
mPrincipalHandles[i]);
segment->GetStartTime(insertTime);
RUN_ON_THREAD(mThread,
WrapRunnable(mSources[i], &SourceMediaStream::AppendToTrack,
mTrackID, segment,
static_cast<AudioSegment*>(nullptr)),
NS_DISPATCH_NORMAL);
mSources[i]->AppendToTrack(mTrackID, segment);
}
}

View File

@ -954,8 +954,9 @@ PluginInstanceParent::RecvShow(const NPRect& updatedRect,
updatedRect.bottom - updatedRect.top);
surface->MarkDirty(ur);
bool isPlugin = true;
RefPtr<gfx::SourceSurface> sourceSurface =
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface);
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, surface, isPlugin);
RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), sourceSurface);
AutoTArray<ImageContainer::NonOwningImage,1> imageList;

View File

@ -992,7 +992,7 @@ Promise::PerformMicroTaskCheckpoint()
return false;
}
AutoSafeJSContext cx;
AutoSlowOperation aso;
do {
nsCOMPtr<nsIRunnable> runnable = microtaskQueue.front().forget();
@ -1004,7 +1004,7 @@ Promise::PerformMicroTaskCheckpoint()
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
JS_CheckForInterrupt(cx);
aso.CheckForInterrupt();
runtime->AfterProcessMicrotask();
} while (!microtaskQueue.empty());

View File

@ -759,8 +759,10 @@ function runTest() {
"wrong responseXML in test for " + test.toSource());
is(res.responseText, "",
"wrong responseText in test for " + test.toSource());
var expectedProgressCount = 0;
if (!res.sendThrew) {
if (test.username) {
expectedProgressCount = 1;
is(res.events.join(","),
"opening,rs1,sending,loadstart,rs4,error,loadend",
"wrong events in test for " + test.toSource());
@ -770,7 +772,7 @@ function runTest() {
"wrong events in test for " + test.toSource());
}
}
is(res.progressEvents, 0,
is(res.progressEvents, expectedProgressCount,
"wrong events in test for " + test.toSource());
if (test.responseHeaders) {
for (header in test.responseHeaders) {

View File

@ -154,12 +154,12 @@ var _fromToTestLists = {
],
URIsAndNone: [
new AnimTestcaseFromTo("url(#idA)", "url(#idB)",
{ fromComp: "url(\"" + document.URL + "#idA\")",
toComp: "url(\"" + document.URL + "#idB\")"}),
{ fromComp: "url(\"#idA\")",
toComp: "url(\"#idB\")"}),
new AnimTestcaseFromTo("none", "url(#idB)",
{ toComp: "url(\"" + document.URL + "#idB\")"}),
{ toComp: "url(\"#idB\")"}),
new AnimTestcaseFromTo("url(#idB)", "inherit",
{ fromComp: "url(\"" + document.URL + "#idB\")",
{ fromComp: "url(\"#idB\")",
toComp: "none"}),
],
};

View File

@ -194,6 +194,9 @@ SVGAElement::IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse)
}
return true;
}
if (nsSVGElement::IsFocusableInternal(aTabIndex, aWithMouse)) {
return true;
}
if (aTabIndex) {
*aTabIndex = -1;

View File

@ -610,6 +610,9 @@ nsSVGElement::ParseAttribute(int32_t aNamespaceID,
didSetResult = true;
}
foundMatch = true;
} else if (aAttribute == nsGkAtoms::tabindex) {
didSetResult = aResult.ParseIntValue(aValue);
foundMatch = true;
}
}
@ -1120,6 +1123,19 @@ nsSVGElement::ClassName()
return mClassAttribute.ToDOMAnimatedString(this);
}
bool
nsSVGElement::IsFocusableInternal(int32_t* aTabIndex, bool)
{
int32_t index = TabIndex();
if (index == -1) {
return false;
}
*aTabIndex = index;
return true;
}
//------------------------------------------------------------------------
// Helper class: MappedAttrParser, for parsing values of mapped attributes

Some files were not shown because too many files have changed in this diff Show More