mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
9806a7d7f1
@ -36,6 +36,7 @@ MOCHITEST_FILES = \
|
||||
test_offline_gzip.html \
|
||||
test_offlineNotification.html \
|
||||
video.ogg \
|
||||
offlineByDefault.js \
|
||||
$(NULL)
|
||||
|
||||
# test_contextmenu.html and test_contextmenu_input are disabled on Linux due to bug 513558
|
||||
|
@ -14,6 +14,7 @@ registerCleanupFunction(function() {
|
||||
var principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
|
||||
Services.perms.removeFromPrincipal(principal, "offline-app");
|
||||
Services.prefs.clearUserPref("offline-apps.quota.warn");
|
||||
Services.prefs.clearUserPref("offline-apps.allow_by_default");
|
||||
});
|
||||
|
||||
// Check that the "preferences" UI is opened and showing which websites have
|
||||
@ -70,5 +71,6 @@ function test() {
|
||||
PopupNotifications.panel.firstElementChild.button.click();
|
||||
}, true);
|
||||
|
||||
Services.prefs.setBoolPref("offline-apps.allow_by_default", false);
|
||||
gBrowser.contentWindow.location = URL;
|
||||
}
|
||||
|
17
browser/base/content/test/offlineByDefault.js
Normal file
17
browser/base/content/test/offlineByDefault.js
Normal file
@ -0,0 +1,17 @@
|
||||
var offlineByDefault = {
|
||||
defaultValue: false,
|
||||
prefBranch: SpecialPowers.Cc["@mozilla.org/preferences-service;1"].getService(SpecialPowers.Ci.nsIPrefBranch),
|
||||
set: function(allow) {
|
||||
try {
|
||||
this.defaultValue = this.prefBranch.getBoolPref("offline-apps.allow_by_default");
|
||||
} catch (e) {
|
||||
this.defaultValue = false
|
||||
}
|
||||
this.prefBranch.setBoolPref("offline-apps.allow_by_default", allow);
|
||||
},
|
||||
reset: function() {
|
||||
this.prefBranch.setBoolPref("offline-apps.allow_by_default", this.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
offlineByDefault.set(false);
|
@ -6,6 +6,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=462856
|
||||
<head>
|
||||
<title>Test offline app notification</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="offlineByDefault.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="loaded()">
|
||||
@ -52,6 +53,8 @@ window.addEventListener("message", function(event) {
|
||||
pm.removeFromPrincipal(principal1, "offline-app");
|
||||
pm.removeFromPrincipal(principal2, "offline-app");
|
||||
|
||||
offlineByDefault.reset();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}, false);
|
||||
|
@ -13,6 +13,7 @@ cache, it can be fetched from the cache successfully.
|
||||
src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="offlineByDefault.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body onload="loaded()">
|
||||
@ -46,6 +47,7 @@ function finishTest() {
|
||||
|
||||
window.removeEventListener("message", handleMessageEvents, false);
|
||||
|
||||
offlineByDefault.reset();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -1503,6 +1503,12 @@ public:
|
||||
*/
|
||||
static bool OfflineAppAllowed(nsIPrincipal *aPrincipal);
|
||||
|
||||
/**
|
||||
* If offline-apps.allow_by_default is true, we set offline-app permission
|
||||
* for the principal and return true. Otherwise false.
|
||||
*/
|
||||
static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal);
|
||||
|
||||
/**
|
||||
* Increases the count of blockers preventing scripts from running.
|
||||
* NOTE: You might want to use nsAutoScriptBlocker rather than calling
|
||||
|
@ -1061,8 +1061,11 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
|
||||
action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST;
|
||||
}
|
||||
else {
|
||||
// Only continue if the document has permission to use offline APIs.
|
||||
if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
|
||||
// Only continue if the document has permission to use offline APIs or
|
||||
// when preferences indicate to permit it automatically.
|
||||
if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) &&
|
||||
!nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal()) &&
|
||||
!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1405,6 +1405,38 @@ nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal)
|
||||
return NS_SUCCEEDED(rv) && allowed;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal)
|
||||
{
|
||||
if (!Preferences::GetRootBranch())
|
||||
return false;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
bool allowedByDefault;
|
||||
rv = Preferences::GetRootBranch()->GetBoolPref(
|
||||
"offline-apps.allow_by_default", &allowedByDefault);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
if (!allowedByDefault)
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
|
||||
if (!permissionManager)
|
||||
return false;
|
||||
|
||||
rv = permissionManager->AddFromPrincipal(
|
||||
aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION,
|
||||
nsIPermissionManager::EXPIRE_NEVER, 0);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
// We have added the permission
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsContentUtils::Shutdown()
|
||||
@ -3191,9 +3223,12 @@ nsContentUtils::IsEventAttributeName(nsIAtom* aName, int32_t aType)
|
||||
uint32_t
|
||||
nsContentUtils::GetEventId(nsIAtom* aName)
|
||||
{
|
||||
EventNameMapping mapping;
|
||||
if (sAtomEventTable->Get(aName, &mapping))
|
||||
return mapping.mId;
|
||||
if (aName) {
|
||||
EventNameMapping mapping;
|
||||
if (sAtomEventTable->Get(aName, &mapping)) {
|
||||
return mapping.mId;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_USER_DEFINED_EVENT;
|
||||
}
|
||||
|
@ -2170,13 +2170,15 @@ nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
#define EVENT(name_, id_, type_, struct_) \
|
||||
EventHandlerNonNull* nsINode::GetOn##name_() { \
|
||||
nsEventListenerManager *elm = GetListenerManager(false); \
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_) : nullptr; \
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
|
||||
: nullptr; \
|
||||
} \
|
||||
void nsINode::SetOn##name_(EventHandlerNonNull* handler, \
|
||||
ErrorResult& error) { \
|
||||
nsEventListenerManager *elm = GetListenerManager(true); \
|
||||
if (elm) { \
|
||||
error = elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
|
||||
error = elm->SetEventHandler(nsGkAtoms::on##name_, \
|
||||
EmptyString(), handler); \
|
||||
} else { \
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
|
||||
} \
|
||||
|
@ -48,18 +48,16 @@ public:
|
||||
ErrorResult& aRv);
|
||||
bool DispatchEvent(nsDOMEvent& aEvent, ErrorResult& aRv);
|
||||
|
||||
// Note, this takes the type in onfoo form!
|
||||
EventHandlerNonNull* GetEventHandler(const nsAString& aType)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
|
||||
return GetEventHandler(type);
|
||||
return GetEventHandler(type, EmptyString());
|
||||
}
|
||||
|
||||
// Note, this takes the type in onfoo form!
|
||||
void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
|
||||
return SetEventHandler(type, aHandler, rv);
|
||||
}
|
||||
ErrorResult& rv);
|
||||
|
||||
// Note, for an event 'foo' aType will be 'onfoo'.
|
||||
virtual void EventListenerAdded(nsIAtom* aType) {}
|
||||
@ -71,9 +69,10 @@ public:
|
||||
virtual nsIDOMWindow* GetOwnerGlobal() = 0;
|
||||
|
||||
protected:
|
||||
EventHandlerNonNull* GetEventHandler(nsIAtom* aType);
|
||||
void SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
|
||||
ErrorResult& rv);
|
||||
EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
|
||||
const nsAString& aTypeString);
|
||||
void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
|
||||
EventHandlerNonNull* aHandler, ErrorResult& rv);
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
|
||||
|
@ -23,17 +23,34 @@ EventTarget::RemoveEventListener(const nsAString& aType,
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
EventTarget::GetEventHandler(nsIAtom* aType)
|
||||
EventTarget::GetEventHandler(nsIAtom* aType, const nsAString& aTypeString)
|
||||
{
|
||||
nsEventListenerManager* elm = GetListenerManager(false);
|
||||
return elm ? elm->GetEventHandler(aType) : nullptr;
|
||||
return elm ? elm->GetEventHandler(aType, aTypeString) : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
|
||||
EventTarget::SetEventHandler(const nsAString& aType,
|
||||
EventHandlerNonNull* aHandler,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
rv = GetListenerManager(true)->SetEventHandler(aType, aHandler);
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
|
||||
return SetEventHandler(type, EmptyString(), aHandler, rv);
|
||||
}
|
||||
return SetEventHandler(nullptr,
|
||||
Substring(aType, 2), // Remove "on"
|
||||
aHandler, rv);
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
|
||||
EventHandlerNonNull* aHandler,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
rv = GetListenerManager(true)->SetEventHandler(aType,
|
||||
aTypeString,
|
||||
aHandler);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -58,6 +58,7 @@ nsDOMEvent::ConstructorInit(mozilla::dom::EventTarget* aOwner,
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
SetOwner(aOwner);
|
||||
mIsMainThreadEvent = mOwner || NS_IsMainThread();
|
||||
|
||||
mPrivateDataDuplicated = false;
|
||||
|
||||
@ -222,19 +223,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
// nsIDOMEventInterface
|
||||
NS_METHOD nsDOMEvent::GetType(nsAString& aType)
|
||||
{
|
||||
if (!mCachedType.IsEmpty()) {
|
||||
aType = mCachedType;
|
||||
if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) {
|
||||
aType = mEvent->typeString;
|
||||
return NS_OK;
|
||||
}
|
||||
const char* name = GetEventName(mEvent->message);
|
||||
|
||||
if (name) {
|
||||
CopyASCIItoUTF16(name, aType);
|
||||
mCachedType = aType;
|
||||
return NS_OK;
|
||||
} else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
|
||||
aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
|
||||
mCachedType = aType;
|
||||
mEvent->typeString = aType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -460,9 +460,15 @@ nsDOMEvent::PreventDefault()
|
||||
void
|
||||
nsDOMEvent::SetEventType(const nsAString& aEventTypeArg)
|
||||
{
|
||||
mEvent->userType =
|
||||
nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
|
||||
&(mEvent->message));
|
||||
if (mIsMainThreadEvent) {
|
||||
mEvent->userType =
|
||||
nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
|
||||
&(mEvent->message));
|
||||
} else {
|
||||
mEvent->userType = nullptr;
|
||||
mEvent->message = NS_USER_DEFINED_EVENT;
|
||||
mEvent->typeString = aEventTypeArg;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -489,7 +495,6 @@ nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, bool aCanBubbleArg, bool a
|
||||
// re-dispatching it.
|
||||
mEvent->target = nullptr;
|
||||
mEvent->originalTarget = nullptr;
|
||||
mCachedType = aEventTypeArg;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -185,9 +185,9 @@ protected:
|
||||
nsRefPtr<nsPresContext> mPresContext;
|
||||
nsCOMPtr<mozilla::dom::EventTarget> mExplicitOriginalTarget;
|
||||
nsCOMPtr<nsPIDOMWindow> mOwner; // nsPIDOMWindow for now.
|
||||
nsString mCachedType;
|
||||
bool mEventIsInternal;
|
||||
bool mPrivateDataDuplicated;
|
||||
bool mIsMainThreadEvent;
|
||||
};
|
||||
|
||||
#define NS_FORWARD_TO_NSDOMEVENT \
|
||||
|
@ -292,7 +292,7 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
|
||||
handler = new EventHandlerNonNull(callable);
|
||||
}
|
||||
ErrorResult rv;
|
||||
SetEventHandler(aType, handler, rv);
|
||||
SetEventHandler(aType, EmptyString(), handler, rv);
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ nsDOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
|
||||
JSContext* aCx,
|
||||
JS::Value* aValue)
|
||||
{
|
||||
EventHandlerNonNull* handler = GetEventHandler(aType);
|
||||
EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
|
||||
if (handler) {
|
||||
*aValue = JS::ObjectValue(*handler->Callable());
|
||||
} else {
|
||||
|
@ -168,12 +168,21 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEventTargetHelper,
|
||||
#define IMPL_EVENT_HANDLER(_event) \
|
||||
inline mozilla::dom::EventHandlerNonNull* GetOn##_event() \
|
||||
{ \
|
||||
return GetEventHandler(nsGkAtoms::on##_event); \
|
||||
if (NS_IsMainThread()) { \
|
||||
return GetEventHandler(nsGkAtoms::on##_event, EmptyString()); \
|
||||
} \
|
||||
return GetEventHandler(nullptr, NS_LITERAL_STRING(#_event)); \
|
||||
} \
|
||||
inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback, \
|
||||
mozilla::ErrorResult& aRv) \
|
||||
{ \
|
||||
SetEventHandler(nsGkAtoms::on##_event, aCallback, aRv); \
|
||||
if (NS_IsMainThread()) { \
|
||||
SetEventHandler(nsGkAtoms::on##_event, EmptyString(), \
|
||||
aCallback, aRv); \
|
||||
} else { \
|
||||
SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), \
|
||||
aCallback, aRv); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Use this macro to declare functions that forward the behavior of this
|
||||
|
@ -52,64 +52,27 @@ private:
|
||||
class nsEventTargetChainItem
|
||||
{
|
||||
private:
|
||||
nsEventTargetChainItem(EventTarget* aTarget,
|
||||
nsEventTargetChainItem* aChild = nullptr);
|
||||
|
||||
// This is the ETCI recycle pool, which is used to avoid some malloc/free
|
||||
// churn. It's implemented as a linked list.
|
||||
static nsEventTargetChainItem* sEtciRecyclePool;
|
||||
static uint32_t sNumRecycledEtcis;
|
||||
static const uint32_t kMaxNumRecycledEtcis = 128;
|
||||
|
||||
nsEventTargetChainItem(EventTarget* aTarget);
|
||||
public:
|
||||
static nsEventTargetChainItem* Create(EventTarget* aTarget,
|
||||
nsEventTargetChainItem()
|
||||
: mFlags(0), mItemFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
static nsEventTargetChainItem* Create(nsTArray<nsEventTargetChainItem>& aChain,
|
||||
EventTarget* aTarget,
|
||||
nsEventTargetChainItem* aChild = nullptr)
|
||||
{
|
||||
// Allocate from the ETCI recycle pool if possible.
|
||||
void* place = nullptr;
|
||||
if (sNumRecycledEtcis > 0) {
|
||||
MOZ_ASSERT(sEtciRecyclePool);
|
||||
place = sEtciRecyclePool;
|
||||
sEtciRecyclePool = sEtciRecyclePool->mNext;
|
||||
--sNumRecycledEtcis;
|
||||
} else {
|
||||
place = malloc(sizeof(nsEventTargetChainItem));
|
||||
}
|
||||
return place
|
||||
? ::new (place) nsEventTargetChainItem(aTarget, aChild)
|
||||
: nullptr;
|
||||
MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
|
||||
return new (aChain.AppendElement()) nsEventTargetChainItem(aTarget);
|
||||
}
|
||||
|
||||
static void Destroy(nsEventTargetChainItem* aItem)
|
||||
static void DestroyLast(nsTArray<nsEventTargetChainItem>& aChain,
|
||||
nsEventTargetChainItem* aItem)
|
||||
{
|
||||
// ::Destroy deletes ancestor chain.
|
||||
nsEventTargetChainItem* item = aItem;
|
||||
if (item->mChild) {
|
||||
item->mChild->mParent = nullptr;
|
||||
item->mChild = nullptr;
|
||||
}
|
||||
// Put destroyed ETCIs into the recycle pool if it's not already full.
|
||||
while (item) {
|
||||
nsEventTargetChainItem* parent = item->mParent;
|
||||
item->~nsEventTargetChainItem();
|
||||
if (sNumRecycledEtcis < kMaxNumRecycledEtcis) {
|
||||
item->mNext = sEtciRecyclePool;
|
||||
sEtciRecyclePool = item;
|
||||
++sNumRecycledEtcis;
|
||||
} else {
|
||||
free(item);
|
||||
}
|
||||
item = parent;
|
||||
}
|
||||
}
|
||||
|
||||
static void ShutdownRecyclePool()
|
||||
{
|
||||
while (sEtciRecyclePool) {
|
||||
nsEventTargetChainItem* tmp = sEtciRecyclePool;
|
||||
sEtciRecyclePool = sEtciRecyclePool->mNext;
|
||||
free(tmp);
|
||||
}
|
||||
uint32_t lastIndex = aChain.Length() - 1;
|
||||
MOZ_ASSERT(&aChain[lastIndex] == aItem);
|
||||
aChain.RemoveElementAt(lastIndex);
|
||||
}
|
||||
|
||||
bool IsValid()
|
||||
@ -181,10 +144,11 @@ public:
|
||||
* and system event group and calls also PostHandleEvent for each
|
||||
* item in the chain.
|
||||
*/
|
||||
nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
|
||||
nsDispatchingCallback* aCallback,
|
||||
ELMCreationDetector& aCd,
|
||||
nsCxPusher* aPusher);
|
||||
static void HandleEventTargetChain(nsTArray<nsEventTargetChainItem>& aChain,
|
||||
nsEventChainPostVisitor& aVisitor,
|
||||
nsDispatchingCallback* aCallback,
|
||||
ELMCreationDetector& aCd,
|
||||
nsCxPusher* aPusher);
|
||||
|
||||
/**
|
||||
* Resets aVisitor object and calls PreHandleEvent.
|
||||
@ -233,21 +197,7 @@ public:
|
||||
nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor,
|
||||
nsCxPusher* aPusher);
|
||||
|
||||
static uint32_t MaxEtciCount() { return sMaxEtciCount; }
|
||||
|
||||
static void ResetMaxEtciCount()
|
||||
{
|
||||
MOZ_ASSERT(!sCurrentEtciCount, "Wrong time to call ResetMaxEtciCount()!");
|
||||
sMaxEtciCount = 0;
|
||||
}
|
||||
|
||||
nsCOMPtr<EventTarget> mTarget;
|
||||
nsEventTargetChainItem* mChild;
|
||||
union {
|
||||
nsEventTargetChainItem* mParent;
|
||||
// This is used only when recycling ETCIs.
|
||||
nsEventTargetChainItem* mNext;
|
||||
};
|
||||
uint16_t mFlags;
|
||||
uint16_t mItemFlags;
|
||||
nsCOMPtr<nsISupports> mItemData;
|
||||
@ -255,22 +205,12 @@ public:
|
||||
nsCOMPtr<EventTarget> mNewTarget;
|
||||
// Cache mTarget's event listener manager.
|
||||
nsRefPtr<nsEventListenerManager> mManager;
|
||||
|
||||
static uint32_t sMaxEtciCount;
|
||||
static uint32_t sCurrentEtciCount;
|
||||
};
|
||||
|
||||
nsEventTargetChainItem* nsEventTargetChainItem::sEtciRecyclePool = nullptr;
|
||||
uint32_t nsEventTargetChainItem::sNumRecycledEtcis = 0;
|
||||
|
||||
nsEventTargetChainItem::nsEventTargetChainItem(EventTarget* aTarget,
|
||||
nsEventTargetChainItem* aChild)
|
||||
: mTarget(aTarget), mChild(aChild), mParent(nullptr), mFlags(0), mItemFlags(0)
|
||||
nsEventTargetChainItem::nsEventTargetChainItem(EventTarget* aTarget)
|
||||
: mTarget(aTarget), mFlags(0), mItemFlags(0)
|
||||
{
|
||||
MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
|
||||
if (mChild) {
|
||||
mChild->mParent = this;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -297,8 +237,9 @@ nsEventTargetChainItem::PostHandleEvent(nsEventChainPostVisitor& aVisitor,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsEventTargetChainItem::HandleEventTargetChain(
|
||||
nsTArray<nsEventTargetChainItem>& aChain,
|
||||
nsEventChainPostVisitor& aVisitor,
|
||||
nsDispatchingCallback* aCallback,
|
||||
ELMCreationDetector& aCd,
|
||||
@ -306,50 +247,49 @@ nsEventTargetChainItem::HandleEventTargetChain(
|
||||
{
|
||||
// Save the target so that it can be restored later.
|
||||
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target;
|
||||
uint32_t chainLength = aChain.Length();
|
||||
|
||||
// Capture
|
||||
nsEventTargetChainItem* item = this;
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = true;
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
||||
while (item->mChild) {
|
||||
for (uint32_t i = chainLength - 1; i > 0; --i) {
|
||||
nsEventTargetChainItem& item = aChain[i];
|
||||
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
item->ForceContentDispatch()) &&
|
||||
item.ForceContentDispatch()) &&
|
||||
!aVisitor.mEvent->mFlags.mPropagationStopped) {
|
||||
item->HandleEvent(aVisitor, aCd, aPusher);
|
||||
item.HandleEvent(aVisitor, aCd, aPusher);
|
||||
}
|
||||
|
||||
if (item->GetNewTarget()) {
|
||||
if (item.GetNewTarget()) {
|
||||
// item is at anonymous boundary. Need to retarget for the child items.
|
||||
nsEventTargetChainItem* nextTarget = item->mChild;
|
||||
while (nextTarget) {
|
||||
EventTarget* newTarget = nextTarget->GetNewTarget();
|
||||
for (uint32_t j = i; j > 0; --j) {
|
||||
uint32_t childIndex = j - 1;
|
||||
EventTarget* newTarget = aChain[childIndex].GetNewTarget();
|
||||
if (newTarget) {
|
||||
aVisitor.mEvent->target = newTarget;
|
||||
break;
|
||||
}
|
||||
nextTarget = nextTarget->mChild;
|
||||
}
|
||||
}
|
||||
|
||||
item = item->mChild;
|
||||
}
|
||||
|
||||
// Target
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = true;
|
||||
nsEventTargetChainItem& targetItem = aChain[0];
|
||||
if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
|
||||
(!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
item->ForceContentDispatch())) {
|
||||
item->HandleEvent(aVisitor, aCd, aPusher);
|
||||
targetItem.ForceContentDispatch())) {
|
||||
targetItem.HandleEvent(aVisitor, aCd, aPusher);
|
||||
}
|
||||
if (aVisitor.mEvent->mFlags.mInSystemGroup) {
|
||||
item->PostHandleEvent(aVisitor, aPusher);
|
||||
targetItem.PostHandleEvent(aVisitor, aPusher);
|
||||
}
|
||||
|
||||
// Bubble
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = false;
|
||||
item = item->mParent;
|
||||
while (item) {
|
||||
EventTarget* newTarget = item->GetNewTarget();
|
||||
for (uint32_t i = 1; i < chainLength; ++i) {
|
||||
nsEventTargetChainItem& item = aChain[i];
|
||||
EventTarget* newTarget = item.GetNewTarget();
|
||||
if (newTarget) {
|
||||
// Item is at anonymous boundary. Need to retarget for the current item
|
||||
// and for parent items.
|
||||
@ -358,15 +298,14 @@ nsEventTargetChainItem::HandleEventTargetChain(
|
||||
|
||||
if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
|
||||
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
item->ForceContentDispatch()) &&
|
||||
item.ForceContentDispatch()) &&
|
||||
!aVisitor.mEvent->mFlags.mPropagationStopped) {
|
||||
item->HandleEvent(aVisitor, aCd, aPusher);
|
||||
item.HandleEvent(aVisitor, aCd, aPusher);
|
||||
}
|
||||
if (aVisitor.mEvent->mFlags.mInSystemGroup) {
|
||||
item->PostHandleEvent(aVisitor, aPusher);
|
||||
item.PostHandleEvent(aVisitor, aPusher);
|
||||
}
|
||||
}
|
||||
item = item->mParent;
|
||||
}
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
||||
|
||||
@ -390,7 +329,8 @@ nsEventTargetChainItem::HandleEventTargetChain(
|
||||
// Setting back the target which was used also for default event group.
|
||||
aVisitor.mEvent->target = firstTarget;
|
||||
aVisitor.mEvent->mFlags.mInSystemGroup = true;
|
||||
HandleEventTargetChain(aVisitor,
|
||||
HandleEventTargetChain(aChain,
|
||||
aVisitor,
|
||||
aCallback,
|
||||
aCd,
|
||||
aPusher);
|
||||
@ -401,17 +341,11 @@ nsEventTargetChainItem::HandleEventTargetChain(
|
||||
aVisitor.mEvent->mFlags.mPropagationStopped = false;
|
||||
aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void NS_ShutdownEventTargetChainItemRecyclePool()
|
||||
{
|
||||
nsEventTargetChainItem::ShutdownRecyclePool();
|
||||
}
|
||||
|
||||
nsEventTargetChainItem*
|
||||
EventTargetChainItemForChromeTarget(nsINode* aNode,
|
||||
EventTargetChainItemForChromeTarget(nsTArray<nsEventTargetChainItem>& aChain,
|
||||
nsINode* aNode,
|
||||
nsEventTargetChainItem* aChild = nullptr)
|
||||
{
|
||||
if (!aNode->IsInDoc()) {
|
||||
@ -422,11 +356,11 @@ EventTargetChainItemForChromeTarget(nsINode* aNode,
|
||||
NS_ENSURE_TRUE(piTarget, nullptr);
|
||||
|
||||
nsEventTargetChainItem* etci =
|
||||
nsEventTargetChainItem::Create(piTarget->GetTargetForEventTargetChain(),
|
||||
nsEventTargetChainItem::Create(aChain,
|
||||
piTarget->GetTargetForEventTargetChain(),
|
||||
aChild);
|
||||
NS_ENSURE_TRUE(etci, nullptr);
|
||||
if (!etci->IsValid()) {
|
||||
nsEventTargetChainItem::Destroy(etci);
|
||||
nsEventTargetChainItem::DestroyLast(aChain, etci);
|
||||
return nullptr;
|
||||
}
|
||||
return etci;
|
||||
@ -522,12 +456,13 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
// event dispatching is finished.
|
||||
nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
|
||||
|
||||
nsTArray<nsEventTargetChainItem> chain(128);
|
||||
|
||||
// Create the event target chain item for the event target.
|
||||
nsEventTargetChainItem* targetEtci =
|
||||
nsEventTargetChainItem::Create(target->GetTargetForEventTargetChain());
|
||||
NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsEventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
|
||||
if (!targetEtci->IsValid()) {
|
||||
nsEventTargetChainItem::Destroy(targetEtci);
|
||||
nsEventTargetChainItem::DestroyLast(chain, targetEtci);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -570,8 +505,8 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
|
||||
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||
nsEventTargetChainItem::Destroy(targetEtci);
|
||||
targetEtci = EventTargetChainItemForChromeTarget(content);
|
||||
nsEventTargetChainItem::DestroyLast(chain, targetEtci);
|
||||
targetEtci = EventTargetChainItemForChromeTarget(chain, content);
|
||||
NS_ENSURE_STATE(targetEtci);
|
||||
targetEtci->PreHandleEvent(preVisitor);
|
||||
}
|
||||
@ -584,12 +519,9 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
while (preVisitor.mParentTarget) {
|
||||
EventTarget* parentTarget = preVisitor.mParentTarget;
|
||||
nsEventTargetChainItem* parentEtci =
|
||||
nsEventTargetChainItem::Create(preVisitor.mParentTarget, topEtci);
|
||||
if (!parentEtci) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
nsEventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
|
||||
if (!parentEtci->IsValid()) {
|
||||
nsEventTargetChainItem::DestroyLast(chain, parentEtci);
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
@ -606,14 +538,15 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
if (preVisitor.mCanHandle) {
|
||||
topEtci = parentEtci;
|
||||
} else {
|
||||
nsEventTargetChainItem::Destroy(parentEtci);
|
||||
nsEventTargetChainItem::DestroyLast(chain, parentEtci);
|
||||
parentEtci = nullptr;
|
||||
if (preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Even if the current target can't handle the event, try to
|
||||
// propagate to chrome.
|
||||
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
||||
if (disabledTarget) {
|
||||
parentEtci = EventTargetChainItemForChromeTarget(disabledTarget,
|
||||
parentEtci = EventTargetChainItemForChromeTarget(chain,
|
||||
disabledTarget,
|
||||
topEtci);
|
||||
if (parentEtci) {
|
||||
parentEtci->PreHandleEvent(preVisitor);
|
||||
@ -631,20 +564,20 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aTargets) {
|
||||
aTargets->Clear();
|
||||
nsEventTargetChainItem* item = targetEtci;
|
||||
while(item) {
|
||||
aTargets->AppendObject(item->CurrentTarget()->GetTargetForDOMEvent());
|
||||
item = item->mParent;
|
||||
aTargets->SetCapacity(chain.Length());
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
aTargets->AppendObject(chain[i].CurrentTarget()->GetTargetForDOMEvent());
|
||||
}
|
||||
} else {
|
||||
// Event target chain is created. Handle the chain.
|
||||
nsEventChainPostVisitor postVisitor(preVisitor);
|
||||
nsCxPusher pusher;
|
||||
ELMCreationDetector cd;
|
||||
rv = topEtci->HandleEventTargetChain(postVisitor,
|
||||
aCallback,
|
||||
cd,
|
||||
&pusher);
|
||||
nsEventTargetChainItem::HandleEventTargetChain(chain,
|
||||
postVisitor,
|
||||
aCallback,
|
||||
cd,
|
||||
&pusher);
|
||||
|
||||
preVisitor.mEventStatus = postVisitor.mEventStatus;
|
||||
// If the DOM event was created during event flow.
|
||||
@ -655,7 +588,9 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
}
|
||||
}
|
||||
|
||||
nsEventTargetChainItem::Destroy(targetEtci);
|
||||
// Note, nsEventTargetChainItem objects are deleted when the chain goes out of
|
||||
// the scope.
|
||||
|
||||
targetEtci = nullptr;
|
||||
|
||||
aEvent->mFlags.mIsBeingDispatched = false;
|
||||
|
@ -59,9 +59,11 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
#define EVENT_TYPE_EQUALS(ls, type, userType, allEvents) \
|
||||
((ls->mEventType == type && \
|
||||
(ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType)) || \
|
||||
#define EVENT_TYPE_EQUALS(ls, type, userType, typeString, allEvents) \
|
||||
((ls->mEventType == type && \
|
||||
(ls->mEventType != NS_USER_DEFINED_EVENT || \
|
||||
(mIsMainThreadELM && ls->mTypeAtom == userType) || \
|
||||
(!mIsMainThreadELM && ls->mTypeString.Equals(typeString)))) || \
|
||||
(allEvents && ls->mAllEvents))
|
||||
|
||||
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
|
||||
@ -111,12 +113,13 @@ nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
|
||||
mMayHaveTouchEventListener(false),
|
||||
mMayHaveMouseEnterLeaveEventListener(false),
|
||||
mClearingListeners(false),
|
||||
mIsMainThreadELM(NS_IsMainThread()),
|
||||
mNoListenerForEvent(0),
|
||||
mTarget(aTarget)
|
||||
{
|
||||
NS_ASSERTION(aTarget, "unexpected null pointer");
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
if (mIsMainThreadELM) {
|
||||
++sMainThreadCreatedCount;
|
||||
}
|
||||
}
|
||||
@ -223,11 +226,14 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
const EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aTypeAtom,
|
||||
const nsAString& aTypeString,
|
||||
const EventListenerFlags& aFlags,
|
||||
bool aHandler,
|
||||
bool aAllEvents)
|
||||
{
|
||||
NS_ABORT_IF_FALSE((aType && aTypeAtom) || aAllEvents, "Missing type");
|
||||
MOZ_ASSERT((NS_IsMainThread() && aType && aTypeAtom) || // Main thread
|
||||
(!NS_IsMainThread() && aType && !aTypeString.IsEmpty()) || // non-main-thread
|
||||
aAllEvents, "Missing type"); // all-events listener
|
||||
|
||||
if (!aListener || mClearingListeners) {
|
||||
return;
|
||||
@ -244,7 +250,7 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
if (ls->mListener == aListener &&
|
||||
ls->mListenerIsHandler == aHandler &&
|
||||
ls->mFlags == aFlags &&
|
||||
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aAllEvents)) {
|
||||
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -254,7 +260,9 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
|
||||
ls = aAllEvents ? mListeners.InsertElementAt(0) : mListeners.AppendElement();
|
||||
ls->mListener = aListener;
|
||||
MOZ_ASSERT(aType < PR_UINT16_MAX);
|
||||
ls->mEventType = aType;
|
||||
ls->mTypeString = aTypeString;
|
||||
ls->mTypeAtom = aTypeAtom;
|
||||
ls->mFlags = aFlags;
|
||||
ls->mListenerIsHandler = aHandler;
|
||||
@ -457,6 +465,7 @@ nsEventListenerManager::RemoveEventListenerInternal(
|
||||
const EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aUserType,
|
||||
const nsAString& aTypeString,
|
||||
const EventListenerFlags& aFlags,
|
||||
bool aAllEvents)
|
||||
{
|
||||
@ -477,7 +486,7 @@ nsEventListenerManager::RemoveEventListenerInternal(
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
ls = &mListeners.ElementAt(i);
|
||||
if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aAllEvents)) {
|
||||
if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aTypeString, aAllEvents)) {
|
||||
++typeCount;
|
||||
if (ls->mListener == aListener &&
|
||||
ls->mFlags.EqualsIgnoringTrustness(aFlags)) {
|
||||
@ -519,15 +528,23 @@ nsEventListenerManager::RemoveEventListenerInternal(
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
|
||||
bool
|
||||
nsEventListenerManager::ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
|
||||
{
|
||||
// This is slightly different from EVENT_TYPE_EQUALS in that it returns
|
||||
// true even when aEvent->message == NS_USER_DEFINED_EVENT and
|
||||
// aLs=>mEventType != NS_USER_DEFINED_EVENT as long as the atoms are the same
|
||||
return (aEvent->message == NS_USER_DEFINED_EVENT ?
|
||||
(aLs->mTypeAtom == aEvent->userType) :
|
||||
(aLs->mEventType == aEvent->message)) || aLs->mAllEvents;
|
||||
if (aLs->mAllEvents) {
|
||||
return true;
|
||||
}
|
||||
if (aEvent->message == NS_USER_DEFINED_EVENT) {
|
||||
if (mIsMainThreadELM) {
|
||||
return aLs->mTypeAtom == aEvent->userType;
|
||||
}
|
||||
return aLs->mTypeString.Equals(aEvent->typeString);
|
||||
}
|
||||
MOZ_ASSERT(mIsMainThreadELM);
|
||||
return aLs->mEventType == aEvent->message;
|
||||
}
|
||||
|
||||
void
|
||||
@ -535,9 +552,10 @@ nsEventListenerManager::AddEventListenerByType(const EventListenerHolder& aListe
|
||||
const nsAString& aType,
|
||||
const EventListenerFlags& aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
|
||||
nsCOMPtr<nsIAtom> atom =
|
||||
mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
|
||||
uint32_t type = nsContentUtils::GetEventId(atom);
|
||||
AddEventListenerInternal(aListener, type, atom, aFlags);
|
||||
AddEventListenerInternal(aListener, type, atom, aType, aFlags);
|
||||
}
|
||||
|
||||
void
|
||||
@ -546,14 +564,16 @@ nsEventListenerManager::RemoveEventListenerByType(
|
||||
const nsAString& aType,
|
||||
const EventListenerFlags& aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
|
||||
nsCOMPtr<nsIAtom> atom =
|
||||
mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
|
||||
uint32_t type = nsContentUtils::GetEventId(atom);
|
||||
RemoveEventListenerInternal(aListener, type, atom, aFlags);
|
||||
RemoveEventListenerInternal(aListener, type, atom, aType, aFlags);
|
||||
}
|
||||
|
||||
nsListenerStruct*
|
||||
nsEventListenerManager::FindEventHandler(uint32_t aEventType,
|
||||
nsIAtom* aTypeAtom)
|
||||
nsIAtom* aTypeAtom,
|
||||
const nsAString& aTypeString)
|
||||
{
|
||||
// Run through the listeners for this type and see if a script
|
||||
// listener is registered
|
||||
@ -562,7 +582,7 @@ nsEventListenerManager::FindEventHandler(uint32_t aEventType,
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
ls = &mListeners.ElementAt(i);
|
||||
if (ls->mListenerIsHandler &&
|
||||
EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, false)) {
|
||||
EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, aTypeString, false)) {
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
@ -573,6 +593,7 @@ nsresult
|
||||
nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
JS::Handle<JSObject*> aScopeObject,
|
||||
nsIAtom* aName,
|
||||
const nsAString& aTypeString,
|
||||
const nsEventHandler& aHandler,
|
||||
bool aPermitUntrustedEvents,
|
||||
nsListenerStruct **aListenerStruct)
|
||||
@ -582,7 +603,7 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
uint32_t eventType = nsContentUtils::GetEventId(aName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
|
||||
|
||||
if (!ls) {
|
||||
// If we didn't find a script listener or no listeners existed
|
||||
@ -596,9 +617,10 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
EventListenerHolder holder(scriptListener);
|
||||
AddEventListenerInternal(holder, eventType, aName, flags, true);
|
||||
AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
|
||||
true);
|
||||
|
||||
ls = FindEventHandler(eventType, aName);
|
||||
ls = FindEventHandler(eventType, aName, aTypeString);
|
||||
}
|
||||
} else {
|
||||
nsIJSEventListener* scriptListener = ls->GetJSListener();
|
||||
@ -753,8 +775,8 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
|
||||
global->GetGlobalJSObject());
|
||||
|
||||
nsListenerStruct *ls;
|
||||
rv = SetEventHandlerInternal(context, scope, aName, nsEventHandler(),
|
||||
aPermitUntrustedEvents, &ls);
|
||||
rv = SetEventHandlerInternal(context, scope, aName, EmptyString(),
|
||||
nsEventHandler(), aPermitUntrustedEvents, &ls);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aDeferCompilation) {
|
||||
@ -765,14 +787,15 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
|
||||
}
|
||||
|
||||
void
|
||||
nsEventListenerManager::RemoveEventHandler(nsIAtom* aName)
|
||||
nsEventListenerManager::RemoveEventHandler(nsIAtom* aName,
|
||||
const nsAString& aTypeString)
|
||||
{
|
||||
if (mClearingListeners) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t eventType = nsContentUtils::GetEventId(aName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
|
||||
|
||||
if (ls) {
|
||||
mListeners.RemoveElementAt(uint32_t(ls - &mListeners.ElementAt(0)));
|
||||
@ -1084,8 +1107,8 @@ nsEventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aListener,
|
||||
flags.mAllowUntrustedEvents = aWantsUntrusted;
|
||||
flags.mInSystemGroup = aSystemEventGroup;
|
||||
EventListenerHolder holder(aListener);
|
||||
AddEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
false, true);
|
||||
AddEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, EmptyString(),
|
||||
flags, false, true);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1097,8 +1120,8 @@ nsEventListenerManager::RemoveListenerForAllEvents(nsIDOMEventListener* aListene
|
||||
flags.mCapture = aUseCapture;
|
||||
flags.mInSystemGroup = aSystemEventGroup;
|
||||
EventListenerHolder holder(aListener);
|
||||
RemoveEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
true);
|
||||
RemoveEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, EmptyString(),
|
||||
flags, true);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1219,10 +1242,11 @@ nsEventListenerManager::HasUnloadListeners()
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
|
||||
const nsAString& aTypeString,
|
||||
EventHandlerNonNull* aHandler)
|
||||
{
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(aEventName);
|
||||
RemoveEventHandler(aEventName, aTypeString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1230,15 +1254,17 @@ nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
|
||||
// handlers.
|
||||
nsListenerStruct *ignored;
|
||||
return SetEventHandlerInternal(nullptr, JS::NullPtr(), aEventName,
|
||||
nsEventHandler(aHandler),
|
||||
!nsContentUtils::IsCallerChrome(), &ignored);
|
||||
aTypeString, nsEventHandler(aHandler),
|
||||
!mIsMainThreadELM ||
|
||||
!nsContentUtils::IsCallerChrome(),
|
||||
&ignored);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
|
||||
{
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(nsGkAtoms::onerror);
|
||||
RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1246,15 +1272,17 @@ nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
|
||||
// handlers.
|
||||
nsListenerStruct *ignored;
|
||||
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
|
||||
nsEventHandler(aHandler),
|
||||
!nsContentUtils::IsCallerChrome(), &ignored);
|
||||
EmptyString(), nsEventHandler(aHandler),
|
||||
!mIsMainThreadELM ||
|
||||
!nsContentUtils::IsCallerChrome(),
|
||||
&ignored);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandler)
|
||||
{
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(nsGkAtoms::onbeforeunload);
|
||||
RemoveEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1262,15 +1290,18 @@ nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandle
|
||||
// handlers.
|
||||
nsListenerStruct *ignored;
|
||||
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onbeforeunload,
|
||||
nsEventHandler(aHandler),
|
||||
!nsContentUtils::IsCallerChrome(), &ignored);
|
||||
EmptyString(), nsEventHandler(aHandler),
|
||||
!mIsMainThreadELM ||
|
||||
!nsContentUtils::IsCallerChrome(),
|
||||
&ignored);
|
||||
}
|
||||
|
||||
const nsEventHandler*
|
||||
nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName)
|
||||
nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName,
|
||||
const nsAString& aTypeString)
|
||||
{
|
||||
uint32_t eventType = nsContentUtils::GetEventId(aEventName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aEventName);
|
||||
nsListenerStruct* ls = FindEventHandler(eventType, aEventName, aTypeString);
|
||||
|
||||
if (!ls) {
|
||||
return nullptr;
|
||||
|
@ -163,8 +163,9 @@ typedef enum
|
||||
struct nsListenerStruct
|
||||
{
|
||||
mozilla::dom::EventListenerHolder mListener;
|
||||
nsCOMPtr<nsIAtom> mTypeAtom;
|
||||
uint32_t mEventType;
|
||||
nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
|
||||
nsString mTypeString; // for non-main-threads
|
||||
uint16_t mEventType;
|
||||
uint8_t mListenerType;
|
||||
bool mListenerIsHandler : 1;
|
||||
bool mHandlerIsString : 1;
|
||||
@ -298,7 +299,7 @@ public:
|
||||
/**
|
||||
* Remove the current "inline" event listener for aName.
|
||||
*/
|
||||
void RemoveEventHandler(nsIAtom *aName);
|
||||
void RemoveEventHandler(nsIAtom *aName, const nsAString& aTypeString);
|
||||
|
||||
void HandleEvent(nsPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
@ -432,7 +433,8 @@ protected:
|
||||
/**
|
||||
* Find the nsListenerStruct for the "inline" event listener for aTypeAtom.
|
||||
*/
|
||||
nsListenerStruct* FindEventHandler(uint32_t aEventType, nsIAtom* aTypeAtom);
|
||||
nsListenerStruct* FindEventHandler(uint32_t aEventType, nsIAtom* aTypeAtom,
|
||||
const nsAString& aTypeString);
|
||||
|
||||
/**
|
||||
* Set the "inline" event listener for aName to aHandler. aHandler may be
|
||||
@ -445,6 +447,7 @@ protected:
|
||||
nsresult SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
JS::Handle<JSObject*> aScopeGlobal,
|
||||
nsIAtom* aName,
|
||||
const nsAString& aTypeString,
|
||||
const nsEventHandler& aHandler,
|
||||
bool aPermitUntrustedEvents,
|
||||
nsListenerStruct **aListenerStruct);
|
||||
@ -459,6 +462,7 @@ public:
|
||||
* aHandler is null, this will actually remove the event listener
|
||||
*/
|
||||
nsresult SetEventHandler(nsIAtom* aEventName,
|
||||
const nsAString& aTypeString,
|
||||
mozilla::dom::EventHandlerNonNull* aHandler);
|
||||
nsresult SetEventHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler);
|
||||
nsresult SetEventHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler);
|
||||
@ -472,20 +476,23 @@ public:
|
||||
* OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
|
||||
* for others.
|
||||
*/
|
||||
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom *aEventName)
|
||||
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom *aEventName,
|
||||
const nsAString& aTypeString)
|
||||
{
|
||||
const nsEventHandler* handler = GetEventHandlerInternal(aEventName);
|
||||
const nsEventHandler* handler =
|
||||
GetEventHandlerInternal(aEventName, aTypeString);
|
||||
return handler ? handler->EventHandler() : nullptr;
|
||||
}
|
||||
mozilla::dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
|
||||
{
|
||||
const nsEventHandler* handler = GetEventHandlerInternal(nsGkAtoms::onerror);
|
||||
const nsEventHandler* handler =
|
||||
GetEventHandlerInternal(nsGkAtoms::onerror, EmptyString());
|
||||
return handler ? handler->OnErrorEventHandler() : nullptr;
|
||||
}
|
||||
mozilla::dom::BeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
|
||||
{
|
||||
const nsEventHandler* handler =
|
||||
GetEventHandlerInternal(nsGkAtoms::onbeforeunload);
|
||||
GetEventHandlerInternal(nsGkAtoms::onbeforeunload, EmptyString());
|
||||
return handler ? handler->BeforeUnloadEventHandler() : nullptr;
|
||||
}
|
||||
|
||||
@ -494,7 +501,8 @@ protected:
|
||||
* Helper method for implementing the various Get*EventHandler above. Will
|
||||
* return null if we don't have an event handler for this event name.
|
||||
*/
|
||||
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName);
|
||||
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName,
|
||||
const nsAString& aTypeString);
|
||||
|
||||
void AddEventListener(const nsAString& aType,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
@ -508,6 +516,7 @@ protected:
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aTypeAtom,
|
||||
const nsAString& aTypeString,
|
||||
const mozilla::dom::EventListenerFlags& aFlags,
|
||||
bool aHandler = false,
|
||||
bool aAllEvents = false);
|
||||
@ -515,6 +524,7 @@ protected:
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aUserType,
|
||||
const nsAString& aTypeString,
|
||||
const mozilla::dom::EventListenerFlags& aFlags,
|
||||
bool aAllEvents = false);
|
||||
void RemoveAllListeners();
|
||||
@ -523,6 +533,8 @@ protected:
|
||||
nsPIDOMWindow* GetInnerWindowForTarget();
|
||||
already_AddRefed<nsPIDOMWindow> GetTargetAsInnerWindow() const;
|
||||
|
||||
bool ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent);
|
||||
|
||||
uint32_t mMayHavePaintEventListener : 1;
|
||||
uint32_t mMayHaveMutationListeners : 1;
|
||||
uint32_t mMayHaveCapturingListeners : 1;
|
||||
@ -531,7 +543,8 @@ protected:
|
||||
uint32_t mMayHaveTouchEventListener : 1;
|
||||
uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
|
||||
uint32_t mClearingListeners : 1;
|
||||
uint32_t mNoListenerForEvent : 24;
|
||||
uint32_t mIsMainThreadELM : 1;
|
||||
uint32_t mNoListenerForEvent : 23;
|
||||
|
||||
nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
|
||||
mozilla::dom::EventTarget* mTarget; //WEAK
|
||||
|
@ -1010,7 +1010,7 @@ nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
else if (IsEventAttributeName(aAttribute)) {
|
||||
nsEventListenerManager* manager = GetListenerManager(false);
|
||||
if (manager) {
|
||||
manager->RemoveEventHandler(aAttribute);
|
||||
manager->RemoveEventHandler(aAttribute, EmptyString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
|
||||
}
|
||||
AudioChunk* chunk = &a->mLastChunks[mInputs[i]->OutputNumber()];
|
||||
MOZ_ASSERT(chunk);
|
||||
if (chunk->IsNull()) {
|
||||
if (chunk->IsNull() || chunk->mChannelData.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2929,6 +2929,7 @@ void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime,
|
||||
metadata->mChannels = aChannels;
|
||||
metadata->mRate = aRate;
|
||||
metadata->mHasAudio = aHasAudio;
|
||||
metadata->mHasVideo = aHasVideo;
|
||||
metadata->mTags = aTags;
|
||||
mMetadataManager.QueueMetadata(metadata);
|
||||
}
|
||||
|
@ -666,7 +666,7 @@ nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsEventListenerManager* manager = GetListenerManager(false);
|
||||
if (manager) {
|
||||
nsIAtom* eventName = GetEventNameForAttr(aName);
|
||||
manager->RemoveEventHandler(eventName);
|
||||
manager->RemoveEventHandler(eventName, EmptyString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -703,14 +703,16 @@ public:
|
||||
mozilla::dom::EventHandlerNonNull* GetOn##name_() \
|
||||
{ \
|
||||
nsEventListenerManager *elm = GetListenerManager(false); \
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_) : nullptr; \
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
|
||||
: nullptr; \
|
||||
} \
|
||||
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler, \
|
||||
mozilla::ErrorResult& error) \
|
||||
{ \
|
||||
nsEventListenerManager *elm = GetListenerManager(true); \
|
||||
if (elm) { \
|
||||
error = elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
|
||||
error = elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), \
|
||||
handler); \
|
||||
} else { \
|
||||
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
|
||||
} \
|
||||
|
@ -84,7 +84,6 @@ nsDOMOfflineResourceList::nsDOMOfflineResourceList(nsIURI *aManifestURI,
|
||||
, mManifestURI(aManifestURI)
|
||||
, mDocumentURI(aDocumentURI)
|
||||
, mExposeCacheUpdateStatus(true)
|
||||
, mDontSetDocumentCache(false)
|
||||
, mStatus(nsIDOMOfflineResourceList::IDLE)
|
||||
, mCachedKeys(nullptr)
|
||||
, mCachedKeysCount(0)
|
||||
@ -429,6 +428,11 @@ nsDOMOfflineResourceList::GetStatus(uint16_t *aStatus)
|
||||
}
|
||||
}
|
||||
|
||||
if (mAvailableApplicationCache) {
|
||||
*aStatus = nsIDOMOfflineResourceList::UPDATEREADY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aStatus = mStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -455,10 +459,6 @@ nsDOMOfflineResourceList::Update()
|
||||
window, getter_AddRefs(update));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Since we are invoking the cache update, cache on the document must not
|
||||
// be updated until swapCache() method is called on applicationCache object.
|
||||
mDontSetDocumentCache = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -488,6 +488,8 @@ nsDOMOfflineResourceList::SwapCache()
|
||||
mAvailableApplicationCache->GetClientID(availClientId);
|
||||
if (availClientId == currClientId)
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
} else if (mStatus != OBSOLETE) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
ClearCachedKeys();
|
||||
@ -629,16 +631,36 @@ nsDOMOfflineResourceList::UpdateStateChanged(nsIOfflineCacheUpdate *aUpdate,
|
||||
NS_IMETHODIMP
|
||||
nsDOMOfflineResourceList::ApplicationCacheAvailable(nsIApplicationCache *aApplicationCache)
|
||||
{
|
||||
mAvailableApplicationCache = aApplicationCache;
|
||||
nsCOMPtr<nsIApplicationCache> currentAppCache = GetDocumentAppCache();
|
||||
if (currentAppCache) {
|
||||
// Document already has a cache, we cannot override it. swapCache is
|
||||
// here to do it on demand.
|
||||
|
||||
if (!mDontSetDocumentCache) {
|
||||
nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
|
||||
GetDocumentAppCacheContainer();
|
||||
// If the newly available cache is identical to the current cache, then
|
||||
// just ignore this event.
|
||||
if (aApplicationCache == currentAppCache) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (appCacheContainer)
|
||||
appCacheContainer->SetApplicationCache(aApplicationCache);
|
||||
nsCString currClientId, availClientId;
|
||||
currentAppCache->GetClientID(currClientId);
|
||||
aApplicationCache->GetClientID(availClientId);
|
||||
if (availClientId == currClientId) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mAvailableApplicationCache = aApplicationCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer =
|
||||
GetDocumentAppCacheContainer();
|
||||
|
||||
if (appCacheContainer) {
|
||||
appCacheContainer->SetApplicationCache(aApplicationCache);
|
||||
}
|
||||
|
||||
mAvailableApplicationCache = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -737,14 +759,12 @@ nsDOMOfflineResourceList::UpdateCompleted(nsIOfflineCacheUpdate *aUpdate)
|
||||
|
||||
mCacheUpdate->RemoveObserver(this);
|
||||
mCacheUpdate = nullptr;
|
||||
mDontSetDocumentCache = false;
|
||||
|
||||
if (NS_SUCCEEDED(rv) && succeeded && !partial) {
|
||||
mStatus = nsIDOMOfflineResourceList::IDLE;
|
||||
if (isUpgrade) {
|
||||
mStatus = nsIDOMOfflineResourceList::UPDATEREADY;
|
||||
SendEvent(NS_LITERAL_STRING(UPDATEREADY_STR));
|
||||
} else {
|
||||
mStatus = nsIDOMOfflineResourceList::IDLE;
|
||||
SendEvent(NS_LITERAL_STRING(CACHED_STR));
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,6 @@ private:
|
||||
nsCOMPtr<nsIApplicationCache> mAvailableApplicationCache;
|
||||
nsCOMPtr<nsIOfflineCacheUpdate> mCacheUpdate;
|
||||
bool mExposeCacheUpdateStatus;
|
||||
bool mDontSetDocumentCache;
|
||||
uint16_t mStatus;
|
||||
|
||||
// The set of dynamic keys for this application cache object.
|
||||
|
@ -12,6 +12,10 @@ applicationCache.oncached = function() {
|
||||
parent.frameOnUpdate("same", true, applicationCache.status);
|
||||
}
|
||||
|
||||
applicationCache.onnoupdate = function() {
|
||||
parent.frameOnUpdate("same", true, applicationCache.status);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
@ -28,8 +28,7 @@ function startTest()
|
||||
testScriptPresence("namespace1/sub2/script2.js", "scriptNo2Function();", true);
|
||||
testScriptPresence("namespace2/script3.js", "scriptNo3Function();", true);
|
||||
|
||||
opener.OfflineTest.teardown();
|
||||
opener.OfflineTest.finish();
|
||||
opener.OfflineTest.teardownAndFinish();
|
||||
window.close(window);
|
||||
}
|
||||
|
||||
|
@ -16,16 +16,15 @@ function manifestUpdated()
|
||||
var foreign2cache = appCacheService.chooseApplicationCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
|
||||
|
||||
OfflineTest.ok(foreign2cache, "Foreign 2 cache present, chosen for foreign2.html");
|
||||
OfflineTest.is(foreign2cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest")
|
||||
window.opener.OfflineTest.ok(foreign2cache, "Foreign 2 cache present, chosen for foreign2.html");
|
||||
window.opener.OfflineTest.is(foreign2cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest")
|
||||
|
||||
var foreign1cache = OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
|
||||
OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
window.opener.OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
foreign1cache.discard();
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
window.opener.onDone();
|
||||
}
|
||||
|
||||
function onLoaded()
|
||||
@ -33,36 +32,33 @@ function onLoaded()
|
||||
var appCacheService = SpecialPowers.Components.classes["@mozilla.org/network/application-cache-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIApplicationCacheService);
|
||||
|
||||
var foreign1cache = OfflineTest.getActiveCache(
|
||||
var foreign1cache = window.opener.OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
|
||||
OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
window.opener.OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
|
||||
|
||||
var foreign2cache = OfflineTest.getActiveCache(
|
||||
var foreign2cache = window.opener.OfflineTest.getActiveCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest");
|
||||
OfflineTest.ok(!foreign2cache, "Foreign 2 cache not present");
|
||||
window.opener.OfflineTest.ok(!foreign2cache, "Foreign 2 cache not present");
|
||||
|
||||
foreign1cache = appCacheService.chooseApplicationCache(
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
|
||||
OfflineTest.ok(!foreign1cache, "foreign2.html not chosen from foreign1 cache");
|
||||
"http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", window.opener.OfflineTest.loadContext());
|
||||
window.opener.OfflineTest.ok(!foreign1cache, "foreign2.html not chosen from foreign1 cache");
|
||||
|
||||
try
|
||||
{
|
||||
OfflineTest.ok(applicationCache.status == SpecialPowers.Ci.nsIDOMOfflineResourceList.UNCACHED,
|
||||
window.opener.OfflineTest.ok(applicationCache.status == SpecialPowers.Ci.nsIDOMOfflineResourceList.UNCACHED,
|
||||
"there is no associated application cache");
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
OfflineTest.ok(false, "applicationCache.status must not throw an exception");
|
||||
window.opener.OfflineTest.ok(false, "applicationCache.status must not throw an exception");
|
||||
}
|
||||
}
|
||||
|
||||
if (OfflineTest.setup())
|
||||
{
|
||||
applicationCache.onerror = OfflineTest.failEvent;
|
||||
applicationCache.onupdateready = OfflineTest.failEvent;
|
||||
applicationCache.onnoupdate = OfflineTest.failEvent;
|
||||
applicationCache.oncached = OfflineTest.priv(manifestUpdated);
|
||||
}
|
||||
applicationCache.onerror = window.opener.OfflineTest.failEvent;
|
||||
applicationCache.onupdateready = window.opener.OfflineTest.failEvent;
|
||||
applicationCache.onnoupdate = window.opener.OfflineTest.failEvent;
|
||||
applicationCache.oncached = window.opener.OfflineTest.priv(manifestUpdated);
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
// (since we don't get those events)
|
||||
function doneLoading()
|
||||
{
|
||||
window.top.childFinished();
|
||||
window.parent.childFinished();
|
||||
}
|
||||
|
||||
if (OfflineTest.setupChild()) {
|
||||
|
@ -58,6 +58,8 @@ fetch: function(callback)
|
||||
|
||||
var OfflineTest = {
|
||||
|
||||
_allowedByDefault: false,
|
||||
|
||||
_hasSlave: false,
|
||||
|
||||
// The window where test results should be sent.
|
||||
@ -71,6 +73,11 @@ _SJSsStated: [],
|
||||
|
||||
setupChild: function()
|
||||
{
|
||||
if (this._allowedByDefault) {
|
||||
this._masterWindow = window;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (window.parent.OfflineTest._hasSlave) {
|
||||
return false;
|
||||
}
|
||||
@ -91,6 +98,17 @@ setup: function()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
try {
|
||||
this._allowedByDefault = prefBranch.getBoolPref("offline-apps.allow_by_default");
|
||||
} catch (e) {}
|
||||
|
||||
if (this._allowedByDefault) {
|
||||
this._masterWindow = window;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!window.opener || !window.opener.OfflineTest ||
|
||||
!window.opener.OfflineTest._hasSlave) {
|
||||
// Offline applications must be toplevel windows and have the
|
||||
@ -126,35 +144,46 @@ setup: function()
|
||||
return true;
|
||||
},
|
||||
|
||||
teardown: function()
|
||||
teardownAndFinish: function()
|
||||
{
|
||||
// Remove the offline-app permission we gave ourselves.
|
||||
this.teardown(function(self) { self.finish(); });
|
||||
},
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
teardown: function(callback)
|
||||
{
|
||||
// First wait for any pending scheduled updates to finish
|
||||
this.waitForUpdates(function(self) {
|
||||
// Remove the offline-app permission we gave ourselves.
|
||||
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService)
|
||||
.newURI(window.location.href, null, null);
|
||||
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
pm.removeFromPrincipal(principal, "offline-app");
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Ci.nsIPermissionManager);
|
||||
var uri = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService)
|
||||
.newURI(window.location.href, null, null);
|
||||
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
|
||||
// Clear all overrides on the server
|
||||
for (override in this._pathOverrides)
|
||||
this.deleteData(this._pathOverrides[override]);
|
||||
for (statedSJS in this._SJSsStated)
|
||||
this.setSJSState(this._SJSsStated[statedSJS], "");
|
||||
pm.removeFromPrincipal(principal, "offline-app");
|
||||
|
||||
this.clear();
|
||||
// Clear all overrides on the server
|
||||
for (override in self._pathOverrides)
|
||||
self.deleteData(self._pathOverrides[override]);
|
||||
for (statedSJS in self._SJSsStated)
|
||||
self.setSJSState(self._SJSsStated[statedSJS], "");
|
||||
|
||||
self.clear();
|
||||
callback(self);
|
||||
});
|
||||
},
|
||||
|
||||
finish: function()
|
||||
{
|
||||
if (this._masterWindow) {
|
||||
if (this._allowedByDefault) {
|
||||
SimpleTest.executeSoon(SimpleTest.finish);
|
||||
} else if (this._masterWindow) {
|
||||
// Slave window: pass control back to master window, close itself.
|
||||
this._masterWindow.SimpleTest.executeSoon(this._masterWindow.OfflineTest.finish);
|
||||
window.close();
|
||||
@ -196,6 +225,48 @@ clear: function()
|
||||
}
|
||||
},
|
||||
|
||||
waitForUpdates: function(callback)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var self = this;
|
||||
var observer = {
|
||||
notified: false,
|
||||
observe: function(subject, topic, data) {
|
||||
if (subject) {
|
||||
subject.QueryInterface(SpecialPowers.Ci.nsIOfflineCacheUpdate);
|
||||
dump("Update of " + subject.manifestURI.spec + " finished\n");
|
||||
}
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
if (observer.notified) {
|
||||
return;
|
||||
}
|
||||
|
||||
var updateservice = SpecialPowers.Cc["@mozilla.org/offlinecacheupdate-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIOfflineCacheUpdateService);
|
||||
var updatesPending = updateservice.numUpdates;
|
||||
if (updatesPending == 0) {
|
||||
try {
|
||||
SpecialPowers.removeObserver(observer, "offline-cache-update-completed");
|
||||
} catch(ex) {}
|
||||
dump("All pending updates done\n");
|
||||
observer.notified = true;
|
||||
callback(self);
|
||||
return;
|
||||
}
|
||||
|
||||
dump("Waiting for " + updateservice.numUpdates + " update(s) to finish\n");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.addObserver(observer, "offline-cache-update-completed", false);
|
||||
|
||||
// Call now to check whether there are some updates scheduled
|
||||
observer.observe();
|
||||
},
|
||||
|
||||
failEvent: function(e)
|
||||
{
|
||||
OfflineTest.ok(false, "Unexpected event: " + e.type);
|
||||
@ -237,7 +308,19 @@ waitForAdd: function(url, onFinished) {
|
||||
|
||||
manifestURL: function(overload)
|
||||
{
|
||||
var manifestURLspec = overload || window.top.document.documentElement.getAttribute("manifest");
|
||||
var manifestURLspec;
|
||||
if (overload) {
|
||||
manifestURLspec = overload;
|
||||
} else {
|
||||
var win = window;
|
||||
while (win && !win.document.documentElement.getAttribute("manifest")) {
|
||||
if (win == win.parent)
|
||||
break;
|
||||
win = win.parent;
|
||||
}
|
||||
if (win)
|
||||
manifestURLspec = win.document.documentElement.getAttribute("manifest");
|
||||
}
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService)
|
||||
@ -267,8 +350,9 @@ getActiveCache: function(overload)
|
||||
getActiveSession: function()
|
||||
{
|
||||
var cache = this.getActiveCache();
|
||||
if (!cache)
|
||||
if (!cache) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var cacheService = Cc["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Ci.nsICacheService);
|
||||
@ -302,6 +386,7 @@ checkCacheEntries: function(entries, callback)
|
||||
|
||||
checkCache: function(url, expectEntry, callback)
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var cacheSession = this.getActiveSession();
|
||||
this._checkCache(cacheSession, url, expectEntry, callback);
|
||||
},
|
||||
@ -310,11 +395,11 @@ _checkCache: function(cacheSession, url, expectEntry, callback)
|
||||
{
|
||||
if (!cacheSession) {
|
||||
if (expectEntry) {
|
||||
this.ok(false, url + " should exist in the offline cache");
|
||||
this.ok(false, url + " should exist in the offline cache (no session)");
|
||||
} else {
|
||||
this.ok(true, url + " should not exist in the offline cache");
|
||||
this.ok(true, url + " should not exist in the offline cache (no session)");
|
||||
}
|
||||
setTimeout(this.priv(callback), 0);
|
||||
if (callback) setTimeout(this.priv(callback), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -346,7 +431,7 @@ _checkCache: function(cacheSession, url, expectEntry, callback)
|
||||
OfflineTest.ok(false, "got invalid error for " + url);
|
||||
}
|
||||
}
|
||||
setTimeout(OfflineTest.priv(callback), 0);
|
||||
if (callback) setTimeout(OfflineTest.priv(callback), 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,8 +11,7 @@
|
||||
var gGotChecking = false;
|
||||
|
||||
function finishTest() {
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function handleError() {
|
||||
|
@ -17,8 +17,7 @@ var gTimeoutId;
|
||||
function finish()
|
||||
{
|
||||
gTestWin.close();
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function error()
|
||||
|
@ -16,10 +16,16 @@
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var result = new Array();
|
||||
var expectedUpdates = 2;
|
||||
var expectedUpdates = 3; // 2 iframes and our self
|
||||
|
||||
init();
|
||||
|
||||
function onUpdatePassed()
|
||||
{
|
||||
if (!(--expectedUpdates))
|
||||
SimpleTest.executeSoon(finish);
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
@ -35,6 +41,9 @@ function init()
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
pm.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
applicationCache.oncached = onUpdatePassed;
|
||||
applicationCache.onnoupdate = onUpdatePassed;
|
||||
}
|
||||
|
||||
function frameOnLoad(frameid, status)
|
||||
@ -52,8 +61,7 @@ function frameOnUpdate(frameid, ok, status)
|
||||
result[frameid].updateOK = ok;
|
||||
result[frameid].cacheStatus = status;
|
||||
|
||||
if (!(--expectedUpdates))
|
||||
finish();
|
||||
onUpdatePassed();
|
||||
}
|
||||
|
||||
function finish()
|
||||
@ -87,10 +95,12 @@ function finish()
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
pm.removeFromPrincipal(principal, "offline-app");
|
||||
|
||||
cleanCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest");
|
||||
cleanCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingManifest.sjs");
|
||||
OfflineTest.waitForUpdates(function() {
|
||||
cleanCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest");
|
||||
cleanCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingManifest.sjs");
|
||||
|
||||
SimpleTest.finish();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
function cleanCache(manifestURL)
|
||||
@ -98,6 +108,7 @@ function cleanCache(manifestURL)
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var cache = OfflineTest.getActiveCache(manifestURL);
|
||||
dump("Discarding cache for " + manifestURL + " cache=" + cache + "\n");
|
||||
if (cache)
|
||||
cache.discard();
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ function manifestUpdated()
|
||||
|
||||
function onFallbackLoad(fallbackIdentification)
|
||||
{
|
||||
OfflineTest.is(fallbackIdentification, 1, "Got correct fallback for namespace1");
|
||||
OfflineTest.is(fallbackIdentification, 1, "Got correct fallback for namespace1 (2)");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
applicationCache.onerror = function() {}; // the update invoked by the iframe will finish after we discard the cache, ignore error
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
@ -26,7 +26,6 @@ SimpleTest.waitForExplicitFinish();
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = OfflineTest.failEvent;
|
||||
applicationCache.onupdateready = OfflineTest.failEvent;
|
||||
applicationCache.onnoupdate = OfflineTest.failEvent;
|
||||
applicationCache.oncached = OfflineTest.priv(manifestUpdated);
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,7 @@ function finishTheTest()
|
||||
{
|
||||
OfflineTest.is(gImageLoaded[1], true, "Image from a different origin not cointained in the offline cache has loaded");
|
||||
OfflineTest.is(gImageLoaded[2], true, "Image not cointained in the offline cache has loaded");
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -19,46 +19,44 @@ ok(applicationCache.mozItems.length == 0,
|
||||
|
||||
function updateCanceled()
|
||||
{
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest", false);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", false);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", false);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest", false, null);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", false, null);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", false, null);
|
||||
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/nonexistent744719?010", false);
|
||||
OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/nonexistent744719?010", false, null);
|
||||
|
||||
var URL = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/subresource744719.html?";
|
||||
OfflineTest.checkCache(URL + "001", false);
|
||||
OfflineTest.checkCache(URL + "002", false);
|
||||
OfflineTest.checkCache(URL + "003", false);
|
||||
OfflineTest.checkCache(URL + "004", false);
|
||||
OfflineTest.checkCache(URL + "005", false);
|
||||
OfflineTest.checkCache(URL + "006", false);
|
||||
OfflineTest.checkCache(URL + "007", false);
|
||||
OfflineTest.checkCache(URL + "008", false);
|
||||
OfflineTest.checkCache(URL + "009", false);
|
||||
OfflineTest.checkCache(URL + "011", false);
|
||||
OfflineTest.checkCache(URL + "012", false);
|
||||
OfflineTest.checkCache(URL + "013", false);
|
||||
OfflineTest.checkCache(URL + "014", false);
|
||||
OfflineTest.checkCache(URL + "015", false);
|
||||
OfflineTest.checkCache(URL + "016", false);
|
||||
OfflineTest.checkCache(URL + "017", false);
|
||||
OfflineTest.checkCache(URL + "018", false);
|
||||
OfflineTest.checkCache(URL + "019", false);
|
||||
OfflineTest.checkCache(URL + "020", false);
|
||||
OfflineTest.checkCache(URL + "021", false);
|
||||
OfflineTest.checkCache(URL + "022", false);
|
||||
OfflineTest.checkCache(URL + "023", false);
|
||||
OfflineTest.checkCache(URL + "024", false);
|
||||
OfflineTest.checkCache(URL + "025", false);
|
||||
OfflineTest.checkCache(URL + "026", false);
|
||||
OfflineTest.checkCache(URL + "027", false);
|
||||
OfflineTest.checkCache(URL + "028", false);
|
||||
OfflineTest.checkCache(URL + "029", false);
|
||||
OfflineTest.checkCache(URL + "030", false);
|
||||
OfflineTest.checkCache(URL + "001", false, null);
|
||||
OfflineTest.checkCache(URL + "002", false, null);
|
||||
OfflineTest.checkCache(URL + "003", false, null);
|
||||
OfflineTest.checkCache(URL + "004", false, null);
|
||||
OfflineTest.checkCache(URL + "005", false, null);
|
||||
OfflineTest.checkCache(URL + "006", false, null);
|
||||
OfflineTest.checkCache(URL + "007", false, null);
|
||||
OfflineTest.checkCache(URL + "008", false, null);
|
||||
OfflineTest.checkCache(URL + "009", false, null);
|
||||
OfflineTest.checkCache(URL + "011", false, null);
|
||||
OfflineTest.checkCache(URL + "012", false, null);
|
||||
OfflineTest.checkCache(URL + "013", false, null);
|
||||
OfflineTest.checkCache(URL + "014", false, null);
|
||||
OfflineTest.checkCache(URL + "015", false, null);
|
||||
OfflineTest.checkCache(URL + "016", false, null);
|
||||
OfflineTest.checkCache(URL + "017", false, null);
|
||||
OfflineTest.checkCache(URL + "018", false, null);
|
||||
OfflineTest.checkCache(URL + "019", false, null);
|
||||
OfflineTest.checkCache(URL + "020", false, null);
|
||||
OfflineTest.checkCache(URL + "021", false, null);
|
||||
OfflineTest.checkCache(URL + "022", false, null);
|
||||
OfflineTest.checkCache(URL + "023", false, null);
|
||||
OfflineTest.checkCache(URL + "024", false, null);
|
||||
OfflineTest.checkCache(URL + "025", false, null);
|
||||
OfflineTest.checkCache(URL + "026", false, null);
|
||||
OfflineTest.checkCache(URL + "027", false, null);
|
||||
OfflineTest.checkCache(URL + "028", false, null);
|
||||
OfflineTest.checkCache(URL + "029", false, null);
|
||||
OfflineTest.checkCache(URL + "030", false, null);
|
||||
|
||||
OfflineTest.teardown();
|
||||
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -52,11 +52,9 @@ function manifestUpdated()
|
||||
OfflineTest.checkCache(URL + "027", true);
|
||||
OfflineTest.checkCache(URL + "028", true);
|
||||
OfflineTest.checkCache(URL + "029", true);
|
||||
OfflineTest.checkCache(URL + "030", true);
|
||||
|
||||
OfflineTest.teardown();
|
||||
|
||||
OfflineTest.finish();
|
||||
OfflineTest.checkCache(URL + "030", true, function() {
|
||||
OfflineTest.teardownAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -35,8 +35,7 @@ function manifestUpdated()
|
||||
OfflineTest.checkCacheEntries(
|
||||
entries,
|
||||
function() {
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -18,15 +18,13 @@ var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
|
||||
function manifestCached () {
|
||||
OfflineTest.ok(false, "The update was supposed to be canceled");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function onError () {
|
||||
OfflineTest.ok(true, "Expected error: Update canceled");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function onProgress () {
|
||||
@ -43,6 +41,7 @@ function onProgress () {
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
applicationCache.onerror = OfflineTest.priv(onError);
|
||||
applicationCache.onnoupdate = OfflineTest.failEvent;
|
||||
applicationCache.onprogress = OfflineTest.priv(onProgress);
|
||||
applicationCache.oncached = OfflineTest.priv(manifestCached);
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ var gCacheContents = null;
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function manifestUpdatedAgain()
|
||||
|
@ -96,8 +96,7 @@ function onFallbackLoad(fallbackIdentification)
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function finalize()
|
||||
|
@ -19,9 +19,11 @@
|
||||
* chosen by foreign.html page.
|
||||
*/
|
||||
|
||||
var win;
|
||||
|
||||
function manifestUpdated()
|
||||
{
|
||||
var appCacheService = SpecialPowers.Components.classes["@mozilla.org/network/application-cache-service;1"]
|
||||
var appCacheService = SpecialPowers.Cc["@mozilla.org/network/application-cache-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIApplicationCacheService);
|
||||
|
||||
foreign1cache = appCacheService.chooseApplicationCache(
|
||||
@ -30,7 +32,13 @@ function manifestUpdated()
|
||||
OfflineTest.ok(foreign1cache, "foreign2.html chosen from foreign1 cache");
|
||||
OfflineTest.is(foreign1cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest")
|
||||
|
||||
window.location = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html";
|
||||
win = window.open("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html");
|
||||
}
|
||||
|
||||
function onDone() // called by the open window after stuff is finished
|
||||
{
|
||||
win.close();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -13,8 +13,7 @@ var gGotDownloading = false;
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function noUpdate()
|
||||
|
@ -32,8 +32,7 @@ var errorReceived = false;
|
||||
function finish() {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "free");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
@ -46,7 +45,6 @@ if (OfflineTest.setup()) {
|
||||
aUpdate.removeObserver(this);
|
||||
errorReceived = true;
|
||||
OfflineTest.ok(true, "Expected error. Update canceled");
|
||||
finish();
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
|
||||
OfflineTest.ok(errorReceived,
|
||||
|
@ -22,8 +22,7 @@ var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
function finish() {
|
||||
obs.notifyObservers(updateService, "disk-space-watcher", "free");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function onError() {
|
||||
|
@ -12,8 +12,7 @@ var gGotChecking = false;
|
||||
var gGotDownloading = false;
|
||||
|
||||
function finishTest() {
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function handleError() {
|
||||
|
@ -23,8 +23,7 @@ function checkEntries() {
|
||||
|
||||
function childFinished()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -99,8 +99,7 @@ function finalize()
|
||||
OfflineTest.is(gGotDynamicVersion, 1, "Dynamic entry loaded");
|
||||
OfflineTest.ok(gGotOnError, "Got onerror event invoked by implicit page load in offline mode");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,7 @@ function manifestUpdated()
|
||||
xhr.send();
|
||||
|
||||
OfflineTest.is(xhr.status, 200, "Should have fallen back.");
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -25,8 +25,7 @@ function manifestError()
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -108,8 +108,7 @@ function manifestError()
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -9,8 +9,7 @@
|
||||
|
||||
function finish()
|
||||
{
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
function failAndFinish(e)
|
||||
|
@ -49,8 +49,7 @@ function removeItem()
|
||||
false,
|
||||
function() {
|
||||
// We're done
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,7 @@ function manifestUpdated()
|
||||
observe: function(subject, topic, data) {
|
||||
OfflineTest.is(topic, "offline-cache-update-unavailable", "No update avail (2)");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ function waitForLocations(frames, doneFunc)
|
||||
if (frame)
|
||||
// toString() might cause problems when this test will
|
||||
// completely be changed to test IDN behavior.
|
||||
OfflineTest.waitForAdd(frame.location.toString(), function()
|
||||
OfflineTest.waitForAdd(frame, function()
|
||||
{
|
||||
waitForLocations(frames, doneFunc);
|
||||
}
|
||||
@ -94,7 +94,7 @@ function frameLoad(version)
|
||||
{
|
||||
var call = gCallOnUpdatingFrameLoad;
|
||||
gCallOnUpdatingFrameLoad = null;
|
||||
OfflineTest.priv(call)();
|
||||
SimpleTest.executeSoon(OfflineTest.priv(call));
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,12 +112,15 @@ function manifestCached()
|
||||
OfflineTest.is(gStep, 0, "Got manifestCached in step 0, gStep=" + gStep);
|
||||
|
||||
reloadLocations([fallbackFrame1, fallbackFrame2]);
|
||||
waitForLocations([fallbackFrame1, fallbackFrame2],
|
||||
fallbackLoaded);
|
||||
waitForLocations(
|
||||
["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html"],
|
||||
fallbackLoaded
|
||||
);
|
||||
}
|
||||
|
||||
function fallbackLoaded()
|
||||
{
|
||||
dump("in fallbackLoaded\n");
|
||||
applicationCache.mozAdd("http://mochi.test:8888/tests/SimpleTest/EventUtils.js");
|
||||
OfflineTest.waitForAdd("http://mochi.test:8888/tests/SimpleTest/EventUtils.js",
|
||||
dynamicLoaded);
|
||||
@ -126,7 +129,7 @@ function fallbackLoaded()
|
||||
function dynamicLoaded()
|
||||
{
|
||||
window.open("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html");
|
||||
// window.onload invokes implicitLoaded()
|
||||
// window.applicationCache.noupdate invokes implicitLoaded()
|
||||
}
|
||||
|
||||
function implicitLoaded(aWindow, errorOccured)
|
||||
@ -237,8 +240,8 @@ function manifestUpdated()
|
||||
OfflineTest.setSJSState("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingIframe.sjs", "second");
|
||||
|
||||
gGotFrameVersion = 0;
|
||||
gCallOnUpdatingFrameLoad = function() {applicationCache.update();};
|
||||
updatingFrame.location.reload();
|
||||
// Since the frame is offline-cached, reload of it invokes update
|
||||
});
|
||||
|
||||
break;
|
||||
@ -298,6 +301,7 @@ function manifestNoUpdate()
|
||||
applicationCache.onnoupdate = null;
|
||||
|
||||
OfflineTest.ok(gStep == 3, "Got manifestNoUpdate in step 3, gStep=" + gStep);
|
||||
++gStep;
|
||||
|
||||
OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.UPDATEREADY,
|
||||
"we have associated application cache and update is pending (4)");
|
||||
@ -314,8 +318,7 @@ function checkNewVersionOfIFrame()
|
||||
{
|
||||
OfflineTest.is(gGotFrameVersion, 2, "IFrame version 2");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
// End of the test function chain
|
||||
|
@ -12,8 +12,7 @@ function manifestUpdated()
|
||||
{
|
||||
OfflineTest.ok(true, "Application cache updated.");
|
||||
|
||||
OfflineTest.teardown();
|
||||
OfflineTest.finish();
|
||||
OfflineTest.teardownAndFinish();
|
||||
}
|
||||
|
||||
if (OfflineTest.setup()) {
|
||||
|
@ -29,7 +29,8 @@ class BasicCanvasLayer : public CopyableCanvasLayer,
|
||||
{
|
||||
public:
|
||||
BasicCanvasLayer(BasicLayerManager* aLayerManager) :
|
||||
CopyableCanvasLayer(aLayerManager, static_cast<BasicImplData*>(this))
|
||||
CopyableCanvasLayer(aLayerManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{ }
|
||||
|
||||
virtual void SetVisibleRegion(const nsIntRegion& aRegion)
|
||||
|
@ -14,7 +14,8 @@ namespace layers {
|
||||
class BasicColorLayer : public ColorLayer, public BasicImplData {
|
||||
public:
|
||||
BasicColorLayer(BasicLayerManager* aLayerManager) :
|
||||
ColorLayer(aLayerManager, static_cast<BasicImplData*>(this))
|
||||
ColorLayer(aLayerManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicColorLayer);
|
||||
}
|
||||
|
@ -178,7 +178,8 @@ class BasicContainerLayer : public ContainerLayer, public BasicImplData {
|
||||
|
||||
public:
|
||||
BasicContainerLayer(BasicLayerManager* aManager) :
|
||||
ContainerLayer(aManager, static_cast<BasicImplData*>(this))
|
||||
ContainerLayer(aManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicContainerLayer);
|
||||
mSupportsComponentAlphaChildren = true;
|
||||
|
@ -22,7 +22,8 @@ namespace layers {
|
||||
class BasicImageLayer : public ImageLayer, public BasicImplData {
|
||||
public:
|
||||
BasicImageLayer(BasicLayerManager* aLayerManager) :
|
||||
ImageLayer(aLayerManager, static_cast<BasicImplData*>(this)),
|
||||
ImageLayer(aLayerManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
mSize(-1, -1)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicImageLayer);
|
||||
|
@ -41,7 +41,8 @@ class BasicReadbackLayer : public ReadbackLayer,
|
||||
{
|
||||
public:
|
||||
BasicReadbackLayer(BasicLayerManager* aLayerManager) :
|
||||
ReadbackLayer(aLayerManager, static_cast<BasicImplData*>(this))
|
||||
ReadbackLayer(aLayerManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicReadbackLayer);
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ public:
|
||||
typedef ThebesLayerBuffer::ContentType ContentType;
|
||||
|
||||
BasicThebesLayer(BasicLayerManager* aLayerManager) :
|
||||
ThebesLayer(aLayerManager, static_cast<BasicImplData*>(this)),
|
||||
ThebesLayer(aLayerManager,
|
||||
static_cast<BasicImplData*>(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
mContentClient(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicThebesLayer);
|
||||
|
@ -28,7 +28,8 @@ class ClientCanvasLayer : public CopyableCanvasLayer,
|
||||
typedef CanvasClient::CanvasClientType CanvasClientType;
|
||||
public:
|
||||
ClientCanvasLayer(ClientLayerManager* aLayerManager) :
|
||||
CopyableCanvasLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
CopyableCanvasLayer(aLayerManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientCanvasLayer);
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ class ClientColorLayer : public ColorLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
ClientColorLayer(ClientLayerManager* aLayerManager) :
|
||||
ColorLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
ColorLayer(aLayerManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientColorLayer);
|
||||
}
|
||||
|
@ -139,7 +139,8 @@ class ClientContainerLayer : public ContainerLayer,
|
||||
|
||||
public:
|
||||
ClientContainerLayer(ClientLayerManager* aManager) :
|
||||
ContainerLayer(aManager, static_cast<ClientLayer*>(this))
|
||||
ContainerLayer(aManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientContainerLayer);
|
||||
mSupportsComponentAlphaChildren = true;
|
||||
@ -250,7 +251,8 @@ class ClientRefLayer : public RefLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
ClientRefLayer(ClientLayerManager* aManager) :
|
||||
RefLayer(aManager, static_cast<ClientLayer*>(this))
|
||||
RefLayer(aManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientRefLayer);
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ class ClientImageLayer : public ImageLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
ClientImageLayer(ClientLayerManager* aLayerManager)
|
||||
: ImageLayer(aLayerManager, static_cast<ClientLayer*>(this))
|
||||
: ImageLayer(aLayerManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
, mImageClientTypeContainer(BUFFER_UNKNOWN)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientImageLayer);
|
||||
|
@ -20,7 +20,8 @@ public:
|
||||
typedef ThebesLayerBuffer::ContentType ContentType;
|
||||
|
||||
ClientThebesLayer(ClientLayerManager* aLayerManager) :
|
||||
ThebesLayer(aLayerManager, static_cast<ClientLayer*>(this)),
|
||||
ThebesLayer(aLayerManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
mContentClient(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientThebesLayer);
|
||||
|
@ -14,7 +14,8 @@ namespace layers {
|
||||
|
||||
|
||||
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager)
|
||||
: ThebesLayer(aManager, static_cast<ClientLayer*>(this))
|
||||
: ThebesLayer(aManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
, mContentClient()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientTiledThebesLayer);
|
||||
|
@ -171,8 +171,8 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mRefPtrMonitor("RefPtrMonitor"),
|
||||
mMonitor("AsyncPanZoomController"),
|
||||
mTouchListenerTimeoutTask(nullptr),
|
||||
mX(this),
|
||||
mY(this),
|
||||
mX(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
mY(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
mAllowZoom(true),
|
||||
mMinZoom(MIN_ZOOM),
|
||||
mMaxZoom(MAX_ZOOM),
|
||||
|
@ -247,7 +247,8 @@ static const char *gPrefLangNames[] = {
|
||||
};
|
||||
|
||||
gfxPlatform::gfxPlatform()
|
||||
: mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
|
||||
: mAzureCanvasBackendCollector(MOZ_THIS_IN_INITIALIZER_LIST(),
|
||||
&gfxPlatform::GetAzureBackendInfo)
|
||||
, mDrawLayerBorders(false)
|
||||
, mDrawTileBorders(false)
|
||||
, mDrawBigImageBorders(false)
|
||||
@ -2004,4 +2005,4 @@ gfxPlatform::ComponentAlphaEnabled()
|
||||
|
||||
InitLayersAccelerationPrefs();
|
||||
return sComponentAlphaEnabled;
|
||||
}
|
||||
}
|
||||
|
@ -906,17 +906,6 @@ class Value
|
||||
Value(const Value& v) = default;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* clang 4.1 doesn't corectly create a default assignment operator
|
||||
* for this class, so we need to explicitly declare one.
|
||||
*/
|
||||
#if defined(__clang__) && (__clang_major__ == 4) && (__clang_minor__ <= 1)
|
||||
Value &operator=(const Value &r) {
|
||||
data = r.data;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*** Mutators ***/
|
||||
|
||||
void setNull() {
|
||||
|
@ -892,6 +892,16 @@ DisableSPSProfiling(JSContext *cx, unsigned argc, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EnableOsiPointRegisterChecks(JSContext *, unsigned, jsval *vp)
|
||||
{
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
ion::js_IonOptions.checkOsiPointRegisters = true;
|
||||
#endif
|
||||
JS_SET_RVAL(cx, vp, JSVAL_VOID);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DisplayName(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
@ -1136,6 +1146,11 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
"disableSPSProfiling()",
|
||||
" Disables SPS instrumentation"),
|
||||
|
||||
JS_FN_HELP("enableOsiPointRegisterChecks", EnableOsiPointRegisterChecks, 0, 0,
|
||||
"enableOsiPointRegisterChecks()",
|
||||
"Emit extra code to verify live regs at the start of a VM call are not\n"
|
||||
"modified before its OsiPoint."),
|
||||
|
||||
JS_FN_HELP("displayName", DisplayName, 1, 0,
|
||||
"displayName(fn)",
|
||||
" Gets the display name for a function, which can possibly be a guessed or\n"
|
||||
|
@ -1,3 +1,5 @@
|
||||
enableOsiPointRegisterChecks();
|
||||
|
||||
function convertToInt(str) {
|
||||
return str | 0;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
enableOsiPointRegisterChecks();
|
||||
|
||||
function DiagModule(stdlib, foreign) {
|
||||
"use asm";
|
||||
|
||||
|
14
js/src/jit-test/tests/ion/try-catch-6.js
Normal file
14
js/src/jit-test/tests/ion/try-catch-6.js
Normal file
@ -0,0 +1,14 @@
|
||||
var o = {
|
||||
valueOf: function() {}
|
||||
};
|
||||
var threw = false;
|
||||
function test(t) {
|
||||
try {
|
||||
for (x[t++] in o) {}
|
||||
} catch (err) {
|
||||
assertEq(t, 3.14);
|
||||
threw = true;
|
||||
}
|
||||
}
|
||||
test(3.14);
|
||||
assertEq(threw, true);
|
@ -1,3 +1,4 @@
|
||||
enableOsiPointRegisterChecks();
|
||||
|
||||
gczeal(4);
|
||||
eval("(function() { " + "\
|
||||
|
@ -818,6 +818,25 @@ CodeGenerator::visitOsiPoint(LOsiPoint *lir)
|
||||
LSafepoint *safepoint = lir->associatedSafepoint();
|
||||
JS_ASSERT(!safepoint->osiCallPointOffset());
|
||||
safepoint->setOsiCallPointOffset(osiCallPointOffset);
|
||||
|
||||
#ifdef DEBUG
|
||||
// There should be no movegroups or other instructions between
|
||||
// an instruction and its OsiPoint. This is necessary because
|
||||
// we use the OsiPoint's snapshot from within VM calls.
|
||||
for (LInstructionReverseIterator iter(current->rbegin(lir)); iter != current->rend(); iter++) {
|
||||
if (*iter == lir || iter->isNop())
|
||||
continue;
|
||||
JS_ASSERT(!iter->isMoveGroup());
|
||||
JS_ASSERT(iter->safepoint() == safepoint);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (shouldVerifyOsiPointRegs(safepoint))
|
||||
verifyOsiPointRegs(safepoint);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2717,6 +2736,20 @@ CodeGenerator::generateBody()
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (iter->safepoint() && shouldVerifyOsiPointRegs(iter->safepoint())) {
|
||||
// Set checkRegs to 0. If we perform a VM call, the instruction
|
||||
// will set it to 1.
|
||||
GeneralRegisterSet allRegs(GeneralRegisterSet::All());
|
||||
Register scratch = allRegs.takeAny();
|
||||
masm.push(scratch);
|
||||
masm.loadJitActivation(scratch);
|
||||
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
|
||||
masm.store32(Imm32(0), checkRegs);
|
||||
masm.pop(scratch);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!callTraceLIR(i, *iter))
|
||||
return false;
|
||||
|
||||
|
@ -92,6 +92,14 @@ struct IonOptions
|
||||
// Default: true iff there are at least two CPUs available
|
||||
bool parallelCompilation;
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
// Emit extra code to verify live regs at the start of a VM call
|
||||
// are not modified before its OsiPoint.
|
||||
//
|
||||
// Default: false
|
||||
bool checkOsiPointRegisters;
|
||||
#endif
|
||||
|
||||
// How many invocations or loop iterations are needed before functions
|
||||
// are compiled with the baseline compiler.
|
||||
//
|
||||
@ -207,6 +215,9 @@ struct IonOptions
|
||||
uce(true),
|
||||
eaa(true),
|
||||
parallelCompilation(false),
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
checkOsiPointRegisters(false),
|
||||
#endif
|
||||
baselineUsesBeforeCompile(10),
|
||||
usesBeforeCompile(1000),
|
||||
usesBeforeInliningFactor(.125),
|
||||
|
@ -291,14 +291,14 @@ IonFrameIterator::machineState() const
|
||||
SafepointReader reader(ionScript(), safepoint());
|
||||
uintptr_t *spill = spillBase();
|
||||
|
||||
// see CodeGeneratorShared::saveLive, we are only copying GPRs for now, FPUs
|
||||
// are stored after but are not saved in the safepoint. This means that we
|
||||
// are unable to restore any FPUs registers from an OOL VM call. This can
|
||||
// cause some trouble for f.arguments.
|
||||
MachineState machine;
|
||||
for (GeneralRegisterBackwardIterator iter(reader.allSpills()); iter.more(); iter++)
|
||||
for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
|
||||
machine.setRegisterLocation(*iter, --spill);
|
||||
|
||||
double *floatSpill = reinterpret_cast<double *>(spill);
|
||||
for (FloatRegisterBackwardIterator iter(reader.allFloatSpills()); iter.more(); iter++)
|
||||
machine.setRegisterLocation(*iter, --floatSpill);
|
||||
|
||||
return machine;
|
||||
}
|
||||
|
||||
@ -779,7 +779,7 @@ MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame)
|
||||
uintptr_t *spill = frame.spillBase();
|
||||
GeneralRegisterSet gcRegs = safepoint.gcSpills();
|
||||
GeneralRegisterSet valueRegs = safepoint.valueSpills();
|
||||
for (GeneralRegisterBackwardIterator iter(safepoint.allSpills()); iter.more(); iter++) {
|
||||
for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
|
||||
--spill;
|
||||
if (gcRegs.has(*iter))
|
||||
gc::MarkGCThingRoot(trc, reinterpret_cast<void **>(spill), "ion-gc-spill");
|
||||
@ -812,7 +812,7 @@ MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame)
|
||||
|
||||
GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
|
||||
spill = frame.spillBase();
|
||||
for (GeneralRegisterBackwardIterator iter(safepoint.allSpills()); iter.more(); iter++) {
|
||||
for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
|
||||
--spill;
|
||||
if (slotsRegs.has(*iter))
|
||||
trc->runtime->gcNursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
|
||||
@ -1021,6 +1021,16 @@ MarkIonExitFrame(JSTracer *trc, const IonFrameIterator &frame)
|
||||
static void
|
||||
MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
|
||||
{
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (js_IonOptions.checkOsiPointRegisters) {
|
||||
// GC can modify spilled registers, breaking our register checks.
|
||||
// To handle this, we disable these checks for the current VM call
|
||||
// when a GC happens.
|
||||
JitActivation *activation = activations.activation()->asJit();
|
||||
activation->setCheckRegs(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (IonFrameIterator frames(activations); !frames.done(); ++frames) {
|
||||
switch (frames.type()) {
|
||||
case IonFrame_Exit:
|
||||
|
@ -204,6 +204,10 @@ IsNullOrUndefined(MIRType type)
|
||||
#ifdef DEBUG
|
||||
// Track the pipeline of opcodes which has produced a snapshot.
|
||||
#define TRACK_SNAPSHOTS 1
|
||||
|
||||
// Make sure registers are not modified between an instruction and
|
||||
// its OsiPoint.
|
||||
#define CHECK_OSIPOINT_REGISTERS 1
|
||||
#endif
|
||||
|
||||
} // namespace ion
|
||||
|
@ -985,6 +985,12 @@ class LSafepoint : public TempObject
|
||||
// The subset of liveRegs which contains gcthing pointers.
|
||||
GeneralRegisterSet gcRegs_;
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
// Temp regs of the current instruction. This set is never written to the
|
||||
// safepoint; it's only used by assertions during compilation.
|
||||
RegisterSet tempRegs_;
|
||||
#endif
|
||||
|
||||
// Offset to a position in the safepoint stream, or
|
||||
// INVALID_SAFEPOINT_OFFSET.
|
||||
uint32_t safepointOffset_;
|
||||
@ -1029,6 +1035,14 @@ class LSafepoint : public TempObject
|
||||
const RegisterSet &liveRegs() const {
|
||||
return liveRegs_;
|
||||
}
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
void addTempRegister(AnyRegister reg) {
|
||||
tempRegs_.addUnchecked(reg);
|
||||
}
|
||||
const RegisterSet &tempRegs() const {
|
||||
return tempRegs_;
|
||||
}
|
||||
#endif
|
||||
void addGcRegister(Register reg) {
|
||||
gcRegs_.addUnchecked(reg);
|
||||
}
|
||||
|
@ -309,6 +309,25 @@ LinearScanAllocator::moveInputAlloc(CodePosition pos, LAllocation *from, LAlloca
|
||||
return moves->add(from, to);
|
||||
}
|
||||
|
||||
static inline void
|
||||
SetOsiPointUses(LiveInterval *interval, CodePosition defEnd, const LAllocation &allocation)
|
||||
{
|
||||
// Moves are inserted after OsiPoint instructions. This function sets
|
||||
// any OsiPoint uses of this interval to the allocation of the value
|
||||
// before the move.
|
||||
|
||||
JS_ASSERT(interval->index() == 0);
|
||||
|
||||
for (UsePositionIterator usePos(interval->usesBegin());
|
||||
usePos != interval->usesEnd();
|
||||
usePos++)
|
||||
{
|
||||
if (usePos->pos > defEnd)
|
||||
break;
|
||||
*static_cast<LAllocation *>(usePos->use) = allocation;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes the allocations assigned to the live intervals and
|
||||
* erases all virtual registers in the function with the allocations
|
||||
@ -349,24 +368,17 @@ LinearScanAllocator::reifyAllocations()
|
||||
LDefinition *def = reg->def();
|
||||
LAllocation *spillFrom;
|
||||
|
||||
// Insert the moves after any OsiPoint or Nop instructions
|
||||
// following this one. See minimalDefEnd for more info.
|
||||
CodePosition defEnd = minimalDefEnd(reg->ins());
|
||||
|
||||
if (def->policy() == LDefinition::PRESET && def->output()->isRegister()) {
|
||||
AnyRegister fixedReg = def->output()->toRegister();
|
||||
LiveInterval *from = fixedIntervals[fixedReg.code()];
|
||||
|
||||
// Insert the move after any OsiPoint or Nop instructions
|
||||
// following this one. See minimalDefEnd for more info.
|
||||
CodePosition defEnd = minimalDefEnd(reg->ins());
|
||||
|
||||
// If we just skipped an OsiPoint, and it uses this vreg, it
|
||||
// should use the fixed register instead.
|
||||
for (UsePositionIterator usePos(interval->usesBegin());
|
||||
usePos != interval->usesEnd();
|
||||
usePos++)
|
||||
{
|
||||
if (usePos->pos > defEnd)
|
||||
break;
|
||||
*static_cast<LAllocation *>(usePos->use) = LAllocation(fixedReg);
|
||||
}
|
||||
// If we insert the move after an OsiPoint that uses this vreg,
|
||||
// it should use the fixed register instead.
|
||||
SetOsiPointUses(interval, defEnd, LAllocation(fixedReg));
|
||||
|
||||
if (!moveAfter(defEnd, from, interval))
|
||||
return false;
|
||||
@ -401,11 +413,14 @@ LinearScanAllocator::reifyAllocations()
|
||||
if (reg->mustSpillAtDefinition() && !reg->ins()->isPhi() &&
|
||||
(*reg->canonicalSpill() != *spillFrom))
|
||||
{
|
||||
// Insert a spill at the input of the next instruction. Control
|
||||
// instructions never have outputs, so the next instruction is
|
||||
// always valid. Note that we explicitly ignore phis, which
|
||||
// should have been handled in resolveControlFlow().
|
||||
LMoveGroup *moves = getMoveGroupAfter(outputOf(reg->ins()));
|
||||
// If we move the spill after an OsiPoint, the OsiPoint should
|
||||
// use the original location instead.
|
||||
SetOsiPointUses(interval, defEnd, *spillFrom);
|
||||
|
||||
// Insert a spill after this instruction (or after any OsiPoint
|
||||
// or Nop instructions). Note that we explicitly ignore phis,
|
||||
// which should have been handled in resolveControlFlow().
|
||||
LMoveGroup *moves = getMoveGroupAfter(defEnd);
|
||||
if (!moves->add(spillFrom, reg->canonicalSpill()))
|
||||
return false;
|
||||
}
|
||||
|
@ -625,6 +625,11 @@ class LiveRangeAllocator : public RegisterAllocator
|
||||
|
||||
LSafepoint *safepoint = ins->safepoint();
|
||||
safepoint->addLiveRegister(a->toRegister());
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (reg->isTemp())
|
||||
safepoint->addTempRegister(a->toRegister());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,8 +357,7 @@ class RegisterAllocator
|
||||
// Compute the shortest interval that captures vregs defined by ins.
|
||||
// Watch for instructions that are followed by an OSI point and/or Nop.
|
||||
// If moves are introduced between the instruction and the OSI point then
|
||||
// safepoint information for the instruction may be incorrect. This is
|
||||
// pretty disgusting and should be fixed somewhere else in the compiler.
|
||||
// safepoint information for the instruction may be incorrect.
|
||||
while (true) {
|
||||
LInstruction *next = insData[outputOf(ins).next()].ins();
|
||||
if (!next->isNop() && !next->isOsiPoint())
|
||||
|
@ -85,6 +85,21 @@ struct FloatRegister {
|
||||
}
|
||||
};
|
||||
|
||||
class RegisterDump
|
||||
{
|
||||
protected: // Silence Clang warning.
|
||||
uintptr_t regs_[Registers::Total];
|
||||
double fpregs_[FloatRegisters::Total];
|
||||
|
||||
public:
|
||||
static size_t offsetOfRegister(Register reg) {
|
||||
return offsetof(RegisterDump, regs_) + reg.code() * sizeof(uintptr_t);
|
||||
}
|
||||
static size_t offsetOfRegister(FloatRegister reg) {
|
||||
return offsetof(RegisterDump, fpregs_) + reg.code() * sizeof(double);
|
||||
}
|
||||
};
|
||||
|
||||
// Information needed to recover machine register state.
|
||||
class MachineState
|
||||
{
|
||||
|
@ -52,12 +52,13 @@ void
|
||||
SafepointWriter::writeGcRegs(LSafepoint *safepoint)
|
||||
{
|
||||
GeneralRegisterSet gc = safepoint->gcRegs();
|
||||
GeneralRegisterSet spilled = safepoint->liveRegs().gprs();
|
||||
GeneralRegisterSet spilledGpr = safepoint->liveRegs().gprs();
|
||||
FloatRegisterSet spilledFloat = safepoint->liveRegs().fpus();
|
||||
GeneralRegisterSet slots = safepoint->slotsOrElementsRegs();
|
||||
GeneralRegisterSet valueRegs;
|
||||
|
||||
WriteRegisterMask(stream_, spilled.bits());
|
||||
if (!spilled.empty()) {
|
||||
WriteRegisterMask(stream_, spilledGpr.bits());
|
||||
if (!spilledGpr.empty()) {
|
||||
WriteRegisterMask(stream_, gc.bits());
|
||||
WriteRegisterMask(stream_, slots.bits());
|
||||
|
||||
@ -68,12 +69,14 @@ SafepointWriter::writeGcRegs(LSafepoint *safepoint)
|
||||
}
|
||||
|
||||
// GC registers are a subset of the spilled registers.
|
||||
JS_ASSERT((valueRegs.bits() & ~spilled.bits()) == 0);
|
||||
JS_ASSERT((gc.bits() & ~spilled.bits()) == 0);
|
||||
JS_ASSERT((valueRegs.bits() & ~spilledGpr.bits()) == 0);
|
||||
JS_ASSERT((gc.bits() & ~spilledGpr.bits()) == 0);
|
||||
|
||||
WriteRegisterMask(stream_, spilledFloat.bits());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (IonSpewEnabled(IonSpew_Safepoints)) {
|
||||
for (GeneralRegisterForwardIterator iter(spilled); iter.more(); iter++) {
|
||||
for (GeneralRegisterForwardIterator iter(spilledGpr); iter.more(); iter++) {
|
||||
const char *type = gc.has(*iter)
|
||||
? "gc"
|
||||
: slots.has(*iter)
|
||||
@ -83,6 +86,8 @@ SafepointWriter::writeGcRegs(LSafepoint *safepoint)
|
||||
: "any";
|
||||
IonSpew(IonSpew_Safepoints, " %s reg: %s", type, (*iter).name());
|
||||
}
|
||||
for (FloatRegisterForwardIterator iter(spilledFloat); iter.more(); iter++)
|
||||
IonSpew(IonSpew_Safepoints, " float reg: %s", (*iter).name());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -332,12 +337,12 @@ SafepointReader::SafepointReader(IonScript *script, const SafepointIndex *si)
|
||||
{
|
||||
osiCallPointOffset_ = stream_.readUnsigned();
|
||||
|
||||
// gcSpills is a subset of allSpills.
|
||||
allSpills_ = GeneralRegisterSet(stream_.readUnsigned());
|
||||
if (allSpills_.empty()) {
|
||||
gcSpills_ = allSpills_;
|
||||
valueSpills_ = allSpills_;
|
||||
slotsOrElementsSpills_ = allSpills_;
|
||||
// gcSpills is a subset of allGprSpills.
|
||||
allGprSpills_ = GeneralRegisterSet(stream_.readUnsigned());
|
||||
if (allGprSpills_.empty()) {
|
||||
gcSpills_ = allGprSpills_;
|
||||
valueSpills_ = allGprSpills_;
|
||||
slotsOrElementsSpills_ = allGprSpills_;
|
||||
} else {
|
||||
gcSpills_ = GeneralRegisterSet(stream_.readUnsigned());
|
||||
slotsOrElementsSpills_ = GeneralRegisterSet(stream_.readUnsigned());
|
||||
@ -346,6 +351,8 @@ SafepointReader::SafepointReader(IonScript *script, const SafepointIndex *si)
|
||||
#endif
|
||||
}
|
||||
|
||||
allFloatSpills_ = FloatRegisterSet(stream_.readUnsigned());
|
||||
|
||||
advanceFromGcRegs();
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,8 @@ class SafepointReader
|
||||
GeneralRegisterSet gcSpills_;
|
||||
GeneralRegisterSet valueSpills_;
|
||||
GeneralRegisterSet slotsOrElementsSpills_;
|
||||
GeneralRegisterSet allSpills_;
|
||||
GeneralRegisterSet allGprSpills_;
|
||||
FloatRegisterSet allFloatSpills_;
|
||||
uint32_t nunboxSlotsRemaining_;
|
||||
uint32_t slotsOrElementsSlotsRemaining_;
|
||||
|
||||
@ -95,8 +96,11 @@ class SafepointReader
|
||||
GeneralRegisterSet valueSpills() const {
|
||||
return valueSpills_;
|
||||
}
|
||||
GeneralRegisterSet allSpills() const {
|
||||
return allSpills_;
|
||||
GeneralRegisterSet allGprSpills() const {
|
||||
return allGprSpills_;
|
||||
}
|
||||
FloatRegisterSet allFloatSpills() const {
|
||||
return allFloatSpills_;
|
||||
}
|
||||
uint32_t osiReturnPointOffset() const;
|
||||
|
||||
|
@ -422,6 +422,159 @@ CodeGeneratorShared::markOsiPoint(LOsiPoint *ins, uint32_t *callPointOffset)
|
||||
return osiIndices_.append(OsiIndex(*callPointOffset, so));
|
||||
}
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
template <class Op>
|
||||
static void
|
||||
HandleRegisterDump(Op op, MacroAssembler &masm, RegisterSet liveRegs, Register activation,
|
||||
Register scratch)
|
||||
{
|
||||
const size_t baseOffset = JitActivation::offsetOfRegs();
|
||||
|
||||
// Handle live GPRs.
|
||||
for (GeneralRegisterIterator iter(liveRegs.gprs()); iter.more(); iter++) {
|
||||
Register reg = *iter;
|
||||
Address dump(activation, baseOffset + RegisterDump::offsetOfRegister(reg));
|
||||
|
||||
if (reg == activation) {
|
||||
// To use the original value of the activation register (that's
|
||||
// now on top of the stack), we need the scratch register.
|
||||
masm.push(scratch);
|
||||
masm.loadPtr(Address(StackPointer, sizeof(uintptr_t)), scratch);
|
||||
op(scratch, dump);
|
||||
masm.pop(scratch);
|
||||
} else {
|
||||
op(reg, dump);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle live FPRs.
|
||||
for (FloatRegisterIterator iter(liveRegs.fpus()); iter.more(); iter++) {
|
||||
FloatRegister reg = *iter;
|
||||
Address dump(activation, baseOffset + RegisterDump::offsetOfRegister(reg));
|
||||
op(reg, dump);
|
||||
}
|
||||
}
|
||||
|
||||
class StoreOp
|
||||
{
|
||||
MacroAssembler &masm;
|
||||
|
||||
public:
|
||||
StoreOp(MacroAssembler &masm)
|
||||
: masm(masm)
|
||||
{}
|
||||
|
||||
void operator()(Register reg, Address dump) {
|
||||
masm.storePtr(reg, dump);
|
||||
}
|
||||
void operator()(FloatRegister reg, Address dump) {
|
||||
masm.storeDouble(reg, dump);
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
StoreAllLiveRegs(MacroAssembler &masm, RegisterSet liveRegs)
|
||||
{
|
||||
// Store a copy of all live registers before performing the call.
|
||||
// When we reach the OsiPoint, we can use this to check nothing
|
||||
// modified them in the meantime.
|
||||
|
||||
// Load pointer to the JitActivation in a scratch register.
|
||||
GeneralRegisterSet allRegs(GeneralRegisterSet::All());
|
||||
Register scratch = allRegs.takeAny();
|
||||
masm.push(scratch);
|
||||
masm.loadJitActivation(scratch);
|
||||
|
||||
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
|
||||
masm.store32(Imm32(1), checkRegs);
|
||||
|
||||
StoreOp op(masm);
|
||||
HandleRegisterDump<StoreOp>(op, masm, liveRegs, scratch, allRegs.getAny());
|
||||
|
||||
masm.pop(scratch);
|
||||
}
|
||||
|
||||
class VerifyOp
|
||||
{
|
||||
MacroAssembler &masm;
|
||||
Label *failure_;
|
||||
|
||||
public:
|
||||
VerifyOp(MacroAssembler &masm, Label *failure)
|
||||
: masm(masm), failure_(failure)
|
||||
{}
|
||||
|
||||
void operator()(Register reg, Address dump) {
|
||||
masm.branchPtr(Assembler::NotEqual, dump, reg, failure_);
|
||||
}
|
||||
void operator()(FloatRegister reg, Address dump) {
|
||||
masm.loadDouble(dump, ScratchFloatReg);
|
||||
masm.branchDouble(Assembler::DoubleNotEqual, ScratchFloatReg, reg, failure_);
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
OsiPointRegisterCheckFailed()
|
||||
{
|
||||
// Any live register captured by a safepoint (other than temp registers)
|
||||
// must remain unchanged between the call and the OsiPoint instruction.
|
||||
MOZ_ASSUME_UNREACHABLE("Modified registers between VM call and OsiPoint");
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorShared::verifyOsiPointRegs(LSafepoint *safepoint)
|
||||
{
|
||||
// Ensure the live registers stored by callVM did not change between
|
||||
// the call and this OsiPoint. Try-catch relies on this invariant.
|
||||
|
||||
// Load pointer to the JitActivation in a scratch register.
|
||||
GeneralRegisterSet allRegs(GeneralRegisterSet::All());
|
||||
Register scratch = allRegs.takeAny();
|
||||
masm.push(scratch);
|
||||
masm.loadJitActivation(scratch);
|
||||
|
||||
// If we should not check registers (because the instruction did not call
|
||||
// into the VM, or a GC happened), we're done.
|
||||
Label failure, done;
|
||||
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
|
||||
masm.branch32(Assembler::Equal, checkRegs, Imm32(0), &done);
|
||||
|
||||
// Ignore temp registers. Some instructions (like LValueToInt32) modify
|
||||
// temps after calling into the VM. This is fine because no other
|
||||
// instructions (including this OsiPoint) will depend on them.
|
||||
RegisterSet liveRegs = safepoint->liveRegs();
|
||||
liveRegs = RegisterSet::Intersect(liveRegs, RegisterSet::Not(safepoint->tempRegs()));
|
||||
|
||||
VerifyOp op(masm, &failure);
|
||||
HandleRegisterDump<VerifyOp>(op, masm, liveRegs, scratch, allRegs.getAny());
|
||||
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&failure);
|
||||
masm.setupUnalignedABICall(0, scratch);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, OsiPointRegisterCheckFailed));
|
||||
masm.breakpoint();
|
||||
|
||||
masm.bind(&done);
|
||||
masm.pop(scratch);
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorShared::shouldVerifyOsiPointRegs(LSafepoint *safepoint)
|
||||
{
|
||||
if (!js_IonOptions.checkOsiPointRegisters)
|
||||
return false;
|
||||
|
||||
if (gen->info().executionMode() != SequentialExecution)
|
||||
return false;
|
||||
|
||||
if (safepoint->liveRegs().empty(true) && safepoint->liveRegs().empty(false))
|
||||
return false; // No registers to check.
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Before doing any call to Cpp, you should ensure that volatile
|
||||
// registers are evicted by the register allocator.
|
||||
bool
|
||||
@ -455,6 +608,11 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
|
||||
if (!wrapper)
|
||||
return false;
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (shouldVerifyOsiPointRegs(ins->safepoint()))
|
||||
StoreAllLiveRegs(masm, ins->safepoint()->liveRegs());
|
||||
#endif
|
||||
|
||||
// Call the wrapper function. The wrapper is in charge to unwind the stack
|
||||
// when returning from the call. Failures are handled with exceptions based
|
||||
// on the return value of the C functions. To guard the outcome of the
|
||||
|
@ -200,6 +200,11 @@ class CodeGeneratorShared : public LInstructionVisitor
|
||||
return index;
|
||||
}
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
bool shouldVerifyOsiPointRegs(LSafepoint *safepoint);
|
||||
void verifyOsiPointRegs(LSafepoint *safepoint);
|
||||
#endif
|
||||
|
||||
public:
|
||||
// This is needed by addCache to update the cache with the jump
|
||||
// informations provided by the out-of-line path.
|
||||
|
@ -1291,6 +1291,14 @@ class JitActivation : public Activation
|
||||
bool firstFrameIsConstructing_;
|
||||
bool active_;
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
protected:
|
||||
// Used to verify that live registers don't change between a VM call and
|
||||
// the OsiPoint that follows it. Protected to silence Clang warning.
|
||||
uint32_t checkRegs_;
|
||||
RegisterDump regs_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active = true);
|
||||
~JitActivation();
|
||||
@ -1309,6 +1317,18 @@ class JitActivation : public Activation
|
||||
bool firstFrameIsConstructing() const {
|
||||
return firstFrameIsConstructing_;
|
||||
}
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
void setCheckRegs(bool check) {
|
||||
checkRegs_ = check;
|
||||
}
|
||||
static size_t offsetOfCheckRegs() {
|
||||
return offsetof(JitActivation, checkRegs_);
|
||||
}
|
||||
static size_t offsetOfRegs() {
|
||||
return offsetof(JitActivation, regs_);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
// A filtering of the ActivationIterator to only stop at JitActivations.
|
||||
|
@ -6180,7 +6180,9 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||
// mouse out events at the root EventStateManager.
|
||||
if (!captureRetarget && !isWindowLevelMouseExit) {
|
||||
nsPoint eventPoint;
|
||||
uint32_t flags;
|
||||
if (aEvent->message == NS_TOUCH_START) {
|
||||
flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
|
||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||
// if this is a continuing session, ensure that all these events are
|
||||
// in the same document by taking the target of the events already in
|
||||
@ -6199,7 +6201,6 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||
int32_t id = touch->Identifier();
|
||||
if (!gCaptureTouchList.Get(id, nullptr)) {
|
||||
// find the target for this touch
|
||||
uint32_t flags = 0;
|
||||
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
|
||||
touch->mRefPoint,
|
||||
frame);
|
||||
@ -6261,7 +6262,6 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||
} else {
|
||||
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
|
||||
}
|
||||
uint32_t flags = 0;
|
||||
if (aEvent->eventStructType == NS_MOUSE_EVENT &&
|
||||
static_cast<nsMouseEvent*>(aEvent)->ignoreRootScrollFrame) {
|
||||
flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
|
||||
|
@ -119,8 +119,6 @@ using namespace mozilla::system;
|
||||
#include "nsDocument.h"
|
||||
#include "mozilla/dom/HTMLVideoElement.h"
|
||||
|
||||
extern void NS_ShutdownEventTargetChainItemRecyclePool();
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::ipc;
|
||||
@ -378,8 +376,6 @@ nsLayoutStatics::Shutdown()
|
||||
|
||||
nsRegion::ShutdownStatic();
|
||||
|
||||
NS_ShutdownEventTargetChainItemRecyclePool();
|
||||
|
||||
HTMLInputElement::DestroyUploadLastDir();
|
||||
|
||||
nsLayoutUtils::Shutdown();
|
||||
|
@ -1,6 +1,16 @@
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/* This test will test if doorhangers are displayed and dismissed
|
||||
The test will test:
|
||||
* geolocation doorhangers - sharing and not sharing the location dismisses the doorhanger
|
||||
@ -65,6 +75,45 @@ public class testDoorHanger extends BaseTest {
|
||||
// Make sure doorhanger is hidden
|
||||
mAsserter.is(mSolo.searchText(GEO_MESSAGE), false, "Geolocation doorhanger notification is hidden when opening a new tab");
|
||||
|
||||
|
||||
boolean offlineAllowedByDefault = true;
|
||||
try {
|
||||
// Save offline-allow-by-default preferences first
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put("offline-apps.allow_by_default");
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", "testDoorHanger");
|
||||
message.put("preferences", getPrefData);
|
||||
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals("testDoorHanger")) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
JSONArray preferences = data.getJSONArray("preferences");
|
||||
if (preferences.length() > 0) {
|
||||
JSONObject pref = (JSONObject) preferences.get(0);
|
||||
offlineAllowedByDefault = pref.getBoolean("value");
|
||||
}
|
||||
|
||||
// Turn off offline-allow-by-default
|
||||
JSONObject jsonPref = new JSONObject();
|
||||
jsonPref.put("name", "offline-apps.allow_by_default");
|
||||
jsonPref.put("type", "bool");
|
||||
jsonPref.put("value", false);
|
||||
mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
} catch (JSONException e) {
|
||||
mAsserter.ok(false, "exception getting preference", e.toString());
|
||||
}
|
||||
|
||||
// Load offline storage page
|
||||
loadUrl(OFFLINE_STORAGE_URL);
|
||||
waitForText(OFFLINE_MESSAGE);
|
||||
@ -84,6 +133,18 @@ public class testDoorHanger extends BaseTest {
|
||||
loadUrl(OFFLINE_STORAGE_URL);
|
||||
mAsserter.is(mSolo.searchText(OFFLINE_MESSAGE), false, "Offline storage doorhanger is no longer triggered");
|
||||
|
||||
try {
|
||||
// Revert offline setting
|
||||
JSONObject jsonPref = new JSONObject();
|
||||
jsonPref.put("name", "offline-apps.allow_by_default");
|
||||
jsonPref.put("type", "boolean");
|
||||
jsonPref.put("value", offlineAllowedByDefault);
|
||||
mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
} catch (JSONException e) {
|
||||
mAsserter.ok(false, "exception setting preference", e.toString());
|
||||
}
|
||||
|
||||
|
||||
// Load login page
|
||||
loadUrl(LOGIN_URL);
|
||||
waitForText(LOGIN_MESSAGE);
|
||||
|
@ -61,6 +61,8 @@ pref("browser.cache.disk_cache_ssl", true);
|
||||
pref("browser.cache.check_doc_frequency", 3);
|
||||
|
||||
pref("browser.cache.offline.enable", true);
|
||||
// enable offline apps by default, disable prompt
|
||||
pref("offline-apps.allow_by_default", true);
|
||||
|
||||
// offline cache capacity in kilobytes
|
||||
pref("browser.cache.offline.capacity", 512000);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -686,22 +686,14 @@ OfflineAppPermForURI(nsIURI *aURI,
|
||||
const char *permName = pinned ? "pin-app" : "offline-app";
|
||||
permissionManager->TestExactPermission(innerURI, permName, &perm);
|
||||
|
||||
if (perm == nsIPermissionManager::UNKNOWN_ACTION && !pinned) {
|
||||
static const char kPrefName[] = "offline-apps.allow_by_default";
|
||||
if (aPrefBranch) {
|
||||
aPrefBranch->GetBoolPref(kPrefName, aAllowed);
|
||||
} else {
|
||||
*aAllowed = Preferences::GetBool(kPrefName, false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (perm == nsIPermissionManager::ALLOW_ACTION ||
|
||||
perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN) {
|
||||
*aAllowed = true;
|
||||
}
|
||||
|
||||
// offline-apps.allow_by_default is now effective at the cache selection
|
||||
// algorithm code (nsContentSink).
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ CMMSRCS = \
|
||||
GfxInfo.mm \
|
||||
WidgetTraceEvent.mm \
|
||||
NativeKeyBindings.mm \
|
||||
nsColorPicker.mm \
|
||||
$(NULL)
|
||||
|
||||
ifeq (x86_64,$(TARGET_CPU))
|
||||
|
42
widget/cocoa/nsColorPicker.h
Normal file
42
widget/cocoa/nsColorPicker.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- 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 nsColorPicker_h_
|
||||
#define nsColorPicker_h_
|
||||
|
||||
#include "nsIColorPicker.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIColorPickerShownCallback;
|
||||
class nsIDOMWindow;
|
||||
@class NSColorPanelWrapper;
|
||||
@class NSColor;
|
||||
|
||||
class nsColorPicker MOZ_FINAL : public nsIColorPicker
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(nsIDOMWindow* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor);
|
||||
NS_IMETHOD Open(nsIColorPickerShownCallback* aCallback);
|
||||
|
||||
// For NSColorPanelWrapper.
|
||||
void Update(NSColor* aColor);
|
||||
void Done();
|
||||
|
||||
private:
|
||||
static NSColor* GetNSColorFromHexString(const nsAString& aColor);
|
||||
static void GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult);
|
||||
|
||||
nsString mTitle;
|
||||
nsString mColor;
|
||||
NSColorPanelWrapper* mColorPanel;
|
||||
nsCOMPtr<nsIColorPickerShownCallback> mCallback;
|
||||
};
|
||||
|
||||
#endif // nsColorPicker_h_
|
157
widget/cocoa/nsColorPicker.mm
Normal file
157
widget/cocoa/nsColorPicker.mm
Normal file
@ -0,0 +1,157 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "nsColorPicker.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static unsigned int
|
||||
HexStrToInt(NSString* str)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
|
||||
for (unsigned int i = 0; i < [str length]; ++i) {
|
||||
char c = [str characterAtIndex:i];
|
||||
result *= 16;
|
||||
if (c >= '0' && c <= '9') {
|
||||
result += c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
result += 10 + (c - 'A');
|
||||
} else {
|
||||
result += 10 + (c - 'a');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@interface NSColorPanelWrapper : NSObject <NSWindowDelegate>
|
||||
{
|
||||
NSColorPanel* mColorPanel;
|
||||
nsColorPicker* mColorPicker;
|
||||
}
|
||||
- (id)initWithPicker:(nsColorPicker*)aPicker;
|
||||
- (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle;
|
||||
- (void)colorChanged:(NSColorPanel*)aPanel;
|
||||
@end
|
||||
|
||||
@implementation NSColorPanelWrapper
|
||||
- (id)initWithPicker:(nsColorPicker*)aPicker
|
||||
{
|
||||
mColorPicker = aPicker;
|
||||
mColorPanel = [NSColorPanel sharedColorPanel];
|
||||
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle
|
||||
{
|
||||
[mColorPanel setTitle:aTitle];
|
||||
[mColorPanel setColor:aInitialColor];
|
||||
[mColorPanel setTarget:self];
|
||||
[mColorPanel setAction:@selector(colorChanged:)];
|
||||
[mColorPanel setDelegate:self];
|
||||
[mColorPanel makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (void)colorChanged:(NSColorPanel*)aPanel
|
||||
{
|
||||
mColorPicker->Update([mColorPanel color]);
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)aNotification
|
||||
{
|
||||
mColorPicker->Done();
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if ([mColorPanel delegate] == self) {
|
||||
[mColorPanel setTarget:nil];
|
||||
[mColorPanel setAction:nil];
|
||||
[mColorPanel setDelegate:nil];
|
||||
}
|
||||
|
||||
mColorPanel = nil;
|
||||
mColorPicker = nullptr;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsColorPicker, nsIColorPicker)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Init(nsIDOMWindow* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor)
|
||||
{
|
||||
mTitle = aTitle;
|
||||
mColor = aInitialColor;
|
||||
|
||||
mColorPanel = [[NSColorPanelWrapper alloc] initWithPicker:this];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ NSColor*
|
||||
nsColorPicker::GetNSColorFromHexString(const nsAString& aColor)
|
||||
{
|
||||
NSString* str = nsCocoaUtils::ToNSString(aColor);
|
||||
|
||||
double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0;
|
||||
double green = HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0;
|
||||
double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0;
|
||||
|
||||
return [NSColor colorWithDeviceRed: red green: green blue: blue alpha: 1.0];
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsColorPicker::GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult)
|
||||
{
|
||||
CGFloat redFloat, greenFloat, blueFloat;
|
||||
[aColor getRed: &redFloat green: &greenFloat blue: &blueFloat alpha: nil];
|
||||
|
||||
nsCocoaUtils::GetStringForNSString([NSString stringWithFormat:@"#%02x%02x%02x",
|
||||
(int)(redFloat * 255),
|
||||
(int)(greenFloat * 255),
|
||||
(int)(blueFloat * 255)],
|
||||
aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Open(nsIColorPickerShownCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aCallback);
|
||||
mCallback = aCallback;
|
||||
|
||||
[mColorPanel open:GetNSColorFromHexString(mColor)
|
||||
title:nsCocoaUtils::ToNSString(mTitle)];
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsColorPicker::Update(NSColor* aColor)
|
||||
{
|
||||
GetHexStringFromNSColor(aColor, mColor);
|
||||
mCallback->Update(mColor);
|
||||
}
|
||||
|
||||
void
|
||||
nsColorPicker::Done()
|
||||
{
|
||||
mCallback->Done(EmptyString());
|
||||
mCallback = nullptr;
|
||||
|
||||
[mColorPanel release];
|
||||
|
||||
NS_RELEASE_THIS();
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
#include "nsAppShell.h"
|
||||
#include "nsAppShellSingleton.h"
|
||||
#include "nsFilePicker.h"
|
||||
#include "nsColorPicker.h"
|
||||
|
||||
#include "nsClipboard.h"
|
||||
#include "nsClipboardHelper.h"
|
||||
@ -37,6 +38,7 @@
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCocoaWindow)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsChildView)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePicker)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPicker)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
|
||||
@ -133,6 +135,7 @@ NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_POPUP_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_CHILD_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_SOUND_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID);
|
||||
@ -163,6 +166,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
|
||||
{ &kNS_POPUP_CID, false, NULL, nsCocoaWindowConstructor },
|
||||
{ &kNS_CHILD_CID, false, NULL, nsChildViewConstructor },
|
||||
{ &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor },
|
||||
{ &kNS_COLORPICKER_CID, false, NULL, nsColorPickerConstructor },
|
||||
{ &kNS_APPSHELL_CID, false, NULL, nsAppShellConstructor },
|
||||
{ &kNS_SOUND_CID, false, NULL, nsSoundConstructor },
|
||||
{ &kNS_TRANSFERABLE_CID, false, NULL, nsTransferableConstructor },
|
||||
@ -197,6 +201,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
|
||||
{ "@mozilla.org/widgets/popup/mac;1", &kNS_POPUP_CID },
|
||||
{ "@mozilla.org/widgets/childwindow/mac;1", &kNS_CHILD_CID },
|
||||
{ "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID },
|
||||
{ "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID },
|
||||
{ "@mozilla.org/widget/appshell/mac;1", &kNS_APPSHELL_CID },
|
||||
{ "@mozilla.org/sound;1", &kNS_SOUND_CID },
|
||||
{ "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID },
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user