mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-i to m-c, a=merge
This commit is contained in:
commit
3cfa3e89c4
@ -32,7 +32,7 @@
|
||||
@APPNAME@/Contents/Info.plist
|
||||
@APPNAME@/Contents/PkgInfo
|
||||
@APPNAME@/Contents/Plug-Ins/
|
||||
@RESPATH@/b2g.icns
|
||||
@RESPATH@/@MOZ_APP_NAME@.icns
|
||||
@RESPATH@/@LPROJ_ROOT@.lproj/*
|
||||
#endif
|
||||
|
||||
|
@ -1747,6 +1747,9 @@ pref("security.mixed_content.block_active_content", true);
|
||||
// 1 = allow MITM for certificate pinning checks.
|
||||
pref("security.cert_pinning.enforcement_level", 1);
|
||||
|
||||
// 2 = allow SHA-1 only before 2016-01-01
|
||||
pref("security.pki.sha1_enforcement_level", 2);
|
||||
|
||||
// Required blocklist freshness for OneCRL OCSP bypass
|
||||
// (default is 1.25x extensions.blocklist.interval, or 30 hours)
|
||||
pref("security.onecrl.maximum_staleness_in_seconds", 108000);
|
||||
|
@ -52,12 +52,15 @@ add_task(function* test() {
|
||||
}
|
||||
|
||||
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield new Promise(resolve => waitForFocus(resolve, win1));
|
||||
yield new Promise(resolve => testPopupBlockerMenuItem(false, win1, resolve));
|
||||
|
||||
let win2 = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield new Promise(resolve => waitForFocus(resolve, win2));
|
||||
yield new Promise(resolve => testPopupBlockerMenuItem(true, win2, resolve));
|
||||
|
||||
let win3 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield new Promise(resolve => waitForFocus(resolve, win3));
|
||||
yield new Promise(resolve => testPopupBlockerMenuItem(false, win3, resolve));
|
||||
|
||||
// Cleanup
|
||||
|
@ -57,7 +57,9 @@ function test() {
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
let win = whenNewWindowLoaded({ private: aIsPrivate }, aCallback);
|
||||
let win = whenNewWindowLoaded({ private: aIsPrivate }, function() {
|
||||
waitForFocus(aCallback, win);
|
||||
});
|
||||
windowsToClose.push(win);
|
||||
}
|
||||
|
||||
|
@ -284,6 +284,8 @@ static CustomTypeAnnotation NonHeapClass =
|
||||
CustomTypeAnnotation("moz_nonheap_class", "non-heap");
|
||||
static CustomTypeAnnotation HeapClass =
|
||||
CustomTypeAnnotation("moz_heap_class", "heap");
|
||||
static CustomTypeAnnotation NonTemporaryClass =
|
||||
CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
|
||||
static CustomTypeAnnotation MustUse =
|
||||
CustomTypeAnnotation("moz_must_use", "must-use");
|
||||
static CustomTypeAnnotation NonMemMovable =
|
||||
@ -845,6 +847,7 @@ DiagnosticsMatcher::DiagnosticsMatcher() {
|
||||
astMatcher.addMatcher(
|
||||
callExpr(callee(functionDecl(heapAllocator()))).bind("node"),
|
||||
&scopeChecker);
|
||||
astMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &scopeChecker);
|
||||
|
||||
astMatcher.addMatcher(
|
||||
callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
|
||||
@ -973,6 +976,12 @@ enum AllocationVariety {
|
||||
AV_Heap,
|
||||
};
|
||||
|
||||
// XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
|
||||
// probably will be used at some point in the future, in order to produce better
|
||||
// error messages.
|
||||
typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *> AutomaticTemporaryMap;
|
||||
AutomaticTemporaryMap AutomaticTemporaries;
|
||||
|
||||
void DiagnosticsMatcher::ScopeChecker::run(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
|
||||
@ -982,6 +991,20 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
|
||||
if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("parm_vardecl")) {
|
||||
if (const Expr *Default = D->getDefaultArg()) {
|
||||
if (const MaterializeTemporaryExpr *E = dyn_cast<MaterializeTemporaryExpr>(Default)) {
|
||||
// We have just found a ParmVarDecl which has, as its default argument,
|
||||
// a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
|
||||
// automatic, by adding it to the AutomaticTemporaryMap.
|
||||
// Reporting on this type will occur when the MaterializeTemporaryExpr
|
||||
// is matched against.
|
||||
AutomaticTemporaries[E] = D;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the type of allocation which we detected
|
||||
if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
|
||||
if (D->hasGlobalStorage()) {
|
||||
@ -1000,9 +1023,39 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
T = E->getAllocatedType();
|
||||
Loc = E->getLocStart();
|
||||
}
|
||||
} else if (const Expr *E =
|
||||
} else if (const MaterializeTemporaryExpr *E =
|
||||
Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
|
||||
Variety = AV_Temporary;
|
||||
// Temporaries can actually have varying storage durations, due to temporary
|
||||
// lifetime extension. We consider the allocation variety of this temporary
|
||||
// to be the same as the allocation variety of its lifetime.
|
||||
|
||||
// XXX We maybe should mark these lifetimes as being due to a temporary
|
||||
// which has had its lifetime extended, to improve the error messages.
|
||||
switch (E->getStorageDuration()) {
|
||||
case SD_FullExpression:
|
||||
{
|
||||
// Check if this temporary is allocated as a default argument!
|
||||
// if it is, we want to pretend that it is automatic.
|
||||
AutomaticTemporaryMap::iterator AutomaticTemporary = AutomaticTemporaries.find(E);
|
||||
if (AutomaticTemporary != AutomaticTemporaries.end()) {
|
||||
Variety = AV_Automatic;
|
||||
} else {
|
||||
Variety = AV_Temporary;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SD_Automatic:
|
||||
Variety = AV_Automatic;
|
||||
break;
|
||||
case SD_Thread:
|
||||
case SD_Static:
|
||||
Variety = AV_Global;
|
||||
break;
|
||||
case SD_Dynamic:
|
||||
assert(false && "I don't think that this ever should occur...");
|
||||
Variety = AV_Heap;
|
||||
break;
|
||||
}
|
||||
T = E->getType().getUnqualifiedType();
|
||||
Loc = E->getLocStart();
|
||||
} else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
|
||||
@ -1024,6 +1077,8 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
DiagnosticIDs::Error, "variable of type %0 only valid on the heap");
|
||||
unsigned NonHeapID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
|
||||
unsigned NonTemporaryID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Error, "variable of type %0 is not valid in a temporary");
|
||||
|
||||
unsigned StackNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Note,
|
||||
@ -1053,6 +1108,8 @@ void DiagnosticsMatcher::ScopeChecker::run(
|
||||
case AV_Temporary:
|
||||
GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID);
|
||||
HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID);
|
||||
NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc,
|
||||
NonTemporaryID, TemporaryNoteID);
|
||||
break;
|
||||
|
||||
case AV_Heap:
|
||||
|
70
build/clang-plugin/tests/TestNonTemporaryClass.cpp
Normal file
70
build/clang-plugin/tests/TestNonTemporaryClass.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class")))
|
||||
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct MOZ_NON_TEMPORARY_CLASS NonTemporary {
|
||||
int i;
|
||||
NonTemporary() {}
|
||||
MOZ_IMPLICIT NonTemporary(int i) {}
|
||||
NonTemporary(int i, int j) {}
|
||||
void *operator new(size_t x) throw() { return 0; }
|
||||
void *operator new(size_t blah, char *buffer) { return buffer; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MOZ_NON_TEMPORARY_CLASS TemplateClass {
|
||||
T i;
|
||||
};
|
||||
|
||||
void gobble(void *) { }
|
||||
|
||||
void gobbleref(const NonTemporary&) { }
|
||||
|
||||
template <class T>
|
||||
void gobbleanyref(const T&) { }
|
||||
|
||||
void misuseNonTemporaryClass(int len) {
|
||||
NonTemporary invalid;
|
||||
NonTemporary alsoInvalid[2];
|
||||
static NonTemporary invalidStatic;
|
||||
static NonTemporary alsoInvalidStatic[2];
|
||||
|
||||
gobble(&invalid);
|
||||
gobble(&invalidStatic);
|
||||
gobble(&alsoInvalid[0]);
|
||||
|
||||
gobbleref(NonTemporary()); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
gobbleref(NonTemporary(10, 20)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
gobbleref(NonTemporary(10)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
gobbleref(10); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
gobbleanyref(TemplateClass<int>()); // expected-error {{variable of type 'TemplateClass<int>' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
|
||||
gobble(new NonTemporary);
|
||||
gobble(new NonTemporary[10]);
|
||||
gobble(new TemplateClass<int>);
|
||||
gobble(len <= 5 ? &invalid : new NonTemporary);
|
||||
|
||||
char buffer[sizeof(NonTemporary)];
|
||||
gobble(new (buffer) NonTemporary);
|
||||
}
|
||||
|
||||
void defaultArg(const NonTemporary& arg = NonTemporary()) {
|
||||
}
|
||||
|
||||
NonTemporary invalidStatic;
|
||||
struct RandomClass {
|
||||
NonTemporary nonstaticMember; // expected-note {{'RandomClass' is a non-temporary type because member 'nonstaticMember' is a non-temporary type 'NonTemporary'}}
|
||||
static NonTemporary staticMember;
|
||||
};
|
||||
struct MOZ_NON_TEMPORARY_CLASS RandomNonTemporaryClass {
|
||||
NonTemporary nonstaticMember;
|
||||
static NonTemporary staticMember;
|
||||
};
|
||||
|
||||
struct BadInherit : NonTemporary {}; // expected-note {{'BadInherit' is a non-temporary type because it inherits from a non-temporary type 'NonTemporary'}}
|
||||
|
||||
void useStuffWrongly() {
|
||||
gobbleanyref(BadInherit()); // expected-error {{variable of type 'BadInherit' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
gobbleanyref(RandomClass()); // expected-error {{variable of type 'RandomClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}}
|
||||
}
|
@ -24,6 +24,7 @@ SOURCES += [
|
||||
'TestNoExplicitMoveConstructor.cpp',
|
||||
'TestNonHeapClass.cpp',
|
||||
'TestNonMemMovable.cpp',
|
||||
'TestNonTemporaryClass.cpp',
|
||||
'TestNoRefcountedInsideLambdas.cpp',
|
||||
'TestStackClass.cpp',
|
||||
'TestTrivialCtorDtor.cpp',
|
||||
|
@ -29,7 +29,7 @@ namespace mozilla {
|
||||
// cc->Collect();
|
||||
// ...
|
||||
// }
|
||||
class MOZ_STACK_CLASS AutoGlobalTimelineMarker
|
||||
class MOZ_RAII AutoGlobalTimelineMarker
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace mozilla {
|
||||
// nsresult rv = ParseTheCSSFile(mFile);
|
||||
// ...
|
||||
// }
|
||||
class MOZ_STACK_CLASS AutoTimelineMarker
|
||||
class MOZ_RAII AutoTimelineMarker
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsCORSListenerProxy.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsError.h"
|
||||
|
@ -814,6 +814,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
case eFormReset:
|
||||
case eResize:
|
||||
case eScroll:
|
||||
case NS_SELECT_START:
|
||||
stopEvent = true;
|
||||
break;
|
||||
case eUnidentifiedEvent:
|
||||
@ -827,8 +828,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
eventType.EqualsLiteral("load") ||
|
||||
eventType.EqualsLiteral("reset") ||
|
||||
eventType.EqualsLiteral("resize") ||
|
||||
eventType.EqualsLiteral("scroll") ||
|
||||
eventType.EqualsLiteral("selectstart")) {
|
||||
eventType.EqualsLiteral("scroll")) {
|
||||
stopEvent = true;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "HTMLLinkElement.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCORSListenerProxy.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
@ -68,6 +68,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "TimeManager.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "nsIDOMNavigatorSystemMessages.h"
|
||||
@ -1322,18 +1323,24 @@ Navigator::SendBeacon(const nsAString& aUrl,
|
||||
nsCOMPtr<nsIInterfaceRequestor> soc = nsContentUtils::SameOriginChecker();
|
||||
channel->SetNotificationCallbacks(soc);
|
||||
|
||||
nsCOMPtr<nsIChannel> preflightChannel;
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel =
|
||||
do_QueryInterface(channel);
|
||||
if (!internalChannel) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
nsTArray<nsCString> unsafeHeaders;
|
||||
unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
|
||||
rv = NS_StartCORSPreflight(channel,
|
||||
beaconListener,
|
||||
doc->NodePrincipal(),
|
||||
true,
|
||||
unsafeHeaders,
|
||||
getter_AddRefs(preflightChannel));
|
||||
} else {
|
||||
rv = channel->AsyncOpen2(beaconListener);
|
||||
rv = internalChannel->SetCorsPreflightParameters(unsafeHeaders,
|
||||
true,
|
||||
doc->NodePrincipal());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rv = channel->AsyncOpen2(beaconListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
|
@ -412,7 +412,7 @@ private:
|
||||
* passed as a parameter. AutoJSContext will take care of finding the most
|
||||
* appropriate JS context and release it when leaving the stack.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoJSContext {
|
||||
class MOZ_RAII AutoJSContext {
|
||||
public:
|
||||
explicit AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*() const;
|
||||
@ -434,7 +434,7 @@ protected:
|
||||
* Use ThreadsafeAutoJSContext when you want an AutoJSContext but might be
|
||||
* running on a worker thread.
|
||||
*/
|
||||
class MOZ_STACK_CLASS ThreadsafeAutoJSContext {
|
||||
class MOZ_RAII ThreadsafeAutoJSContext {
|
||||
public:
|
||||
explicit ThreadsafeAutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*() const;
|
||||
@ -452,7 +452,7 @@ private:
|
||||
*
|
||||
* Note - This is deprecated. Please use AutoJSAPI instead.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoSafeJSContext : public AutoJSContext {
|
||||
class MOZ_RAII AutoSafeJSContext : public AutoJSContext {
|
||||
public:
|
||||
explicit AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
private:
|
||||
@ -462,7 +462,7 @@ private:
|
||||
/**
|
||||
* Like AutoSafeJSContext but can be used safely on worker threads.
|
||||
*/
|
||||
class MOZ_STACK_CLASS ThreadsafeAutoSafeJSContext {
|
||||
class MOZ_RAII ThreadsafeAutoSafeJSContext {
|
||||
public:
|
||||
explicit ThreadsafeAutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*() const;
|
||||
|
@ -2651,7 +2651,7 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS nsAutoScriptBlocker {
|
||||
class MOZ_RAII nsAutoScriptBlocker {
|
||||
public:
|
||||
explicit nsAutoScriptBlocker(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
@ -634,7 +634,7 @@ AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType)
|
||||
* A class that automatically sets mInShow to false when it goes
|
||||
* out of scope.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoResetInShow {
|
||||
class MOZ_RAII AutoResetInShow {
|
||||
private:
|
||||
nsFrameLoader* mFrameLoader;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -989,7 +989,7 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoResetInFrameSwap final
|
||||
class MOZ_RAII AutoResetInFrameSwap final
|
||||
{
|
||||
public:
|
||||
AutoResetInFrameSwap(nsFrameLoader* aThisFrameLoader,
|
||||
|
@ -882,6 +882,8 @@ GK_ATOM(onscanningstatechanged, "onscanningstatechanged")
|
||||
GK_ATOM(onscostatuschanged, "onscostatuschanged")
|
||||
GK_ATOM(onscroll, "onscroll")
|
||||
GK_ATOM(onselect, "onselect")
|
||||
GK_ATOM(onselectionchange, "onselectionchange")
|
||||
GK_ATOM(onselectstart, "onselectstart")
|
||||
GK_ATOM(onsending, "onsending")
|
||||
GK_ATOM(onsent, "onsent")
|
||||
GK_ATOM(onset, "onset")
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "mozilla/dom/RangeBinding.h"
|
||||
#include "mozilla/dom/DOMRect.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
@ -194,6 +195,26 @@ nsRange::~nsRange()
|
||||
DoSetRange(nullptr, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
nsRange::nsRange(nsINode* aNode)
|
||||
: mRoot(nullptr)
|
||||
, mStartOffset(0)
|
||||
, mEndOffset(0)
|
||||
, mIsPositioned(false)
|
||||
, mIsDetached(false)
|
||||
, mMaySpanAnonymousSubtrees(false)
|
||||
, mIsGenerated(false)
|
||||
, mStartOffsetWasIncremented(false)
|
||||
, mEndOffsetWasIncremented(false)
|
||||
, mEnableGravitationOnElementRemoval(true)
|
||||
#ifdef DEBUG
|
||||
, mAssertNextInsertOrAppendIndex(-1)
|
||||
, mAssertNextInsertOrAppendNode(nullptr)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aNode, "range isn't in a document!");
|
||||
mOwner = aNode->OwnerDoc();
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
||||
@ -269,6 +290,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsRange)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
|
||||
tmp->Reset();
|
||||
|
||||
// This needs to be unlinked after Reset() is called, as it controls
|
||||
// the result of IsInSelection() which is used by tmp->Reset().
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
|
||||
@ -276,6 +301,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@ -879,14 +905,20 @@ nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
|
||||
RegisterCommonAncestor(newCommonAncestor);
|
||||
} else {
|
||||
NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
|
||||
mInSelection = false;
|
||||
mSelection = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This needs to be the last thing this function does. See comment
|
||||
// in ParentChainChanged.
|
||||
// This needs to be the last thing this function does, other than notifying
|
||||
// selection listeners. See comment in ParentChainChanged.
|
||||
mRoot = aRoot;
|
||||
|
||||
// Notify any selection listeners. This has to occur last because otherwise the world
|
||||
// could be observed by a selection listener while the range was in an invalid state.
|
||||
if (mSelection) {
|
||||
mSelection->NotifySelectionListeners();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
@ -897,6 +929,28 @@ IndexOf(nsINode* aChild)
|
||||
return parent ? parent->IndexOf(aChild) : -1;
|
||||
}
|
||||
|
||||
void
|
||||
nsRange::SetSelection(mozilla::dom::Selection* aSelection)
|
||||
{
|
||||
if (mSelection == aSelection) {
|
||||
return;
|
||||
}
|
||||
// At least one of aSelection and mSelection must be null
|
||||
// aSelection will be null when we are removing from a selection
|
||||
// and a range can't be in more than one selection at a time,
|
||||
// thus mSelection must be null too.
|
||||
MOZ_ASSERT(!aSelection || !mSelection);
|
||||
|
||||
mSelection = aSelection;
|
||||
nsINode* commonAncestor = GetCommonAncestor();
|
||||
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
||||
if (mSelection) {
|
||||
RegisterCommonAncestor(commonAncestor);
|
||||
} else {
|
||||
UnregisterCommonAncestor(commonAncestor);
|
||||
}
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsRange::GetCommonAncestor() const
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ namespace dom {
|
||||
class DocumentFragment;
|
||||
class DOMRect;
|
||||
class DOMRectList;
|
||||
class Selection;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@ -42,26 +43,7 @@ class nsRange final : public nsIDOMRange,
|
||||
virtual ~nsRange();
|
||||
|
||||
public:
|
||||
explicit nsRange(nsINode* aNode)
|
||||
: mRoot(nullptr)
|
||||
, mStartOffset(0)
|
||||
, mEndOffset(0)
|
||||
, mIsPositioned(false)
|
||||
, mIsDetached(false)
|
||||
, mMaySpanAnonymousSubtrees(false)
|
||||
, mInSelection(false)
|
||||
, mIsGenerated(false)
|
||||
, mStartOffsetWasIncremented(false)
|
||||
, mEndOffsetWasIncremented(false)
|
||||
, mEnableGravitationOnElementRemoval(true)
|
||||
#ifdef DEBUG
|
||||
, mAssertNextInsertOrAppendIndex(-1)
|
||||
, mAssertNextInsertOrAppendNode(nullptr)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aNode, "range isn't in a document!");
|
||||
mOwner = aNode->OwnerDoc();
|
||||
}
|
||||
explicit nsRange(nsINode* aNode);
|
||||
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
@ -129,31 +111,18 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff this range is part of at least one Selection object
|
||||
* Return true iff this range is part of a Selection object
|
||||
* and isn't detached.
|
||||
*/
|
||||
bool IsInSelection() const
|
||||
{
|
||||
return mInSelection;
|
||||
return !!mSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the range is added/removed from a Selection.
|
||||
*/
|
||||
void SetInSelection(bool aInSelection)
|
||||
{
|
||||
if (mInSelection == aInSelection) {
|
||||
return;
|
||||
}
|
||||
mInSelection = aInSelection;
|
||||
nsINode* commonAncestor = GetCommonAncestor();
|
||||
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
||||
if (mInSelection) {
|
||||
RegisterCommonAncestor(commonAncestor);
|
||||
} else {
|
||||
UnregisterCommonAncestor(commonAncestor);
|
||||
}
|
||||
}
|
||||
void SetSelection(mozilla::dom::Selection* aSelection);
|
||||
|
||||
/**
|
||||
* Return true if this range was generated.
|
||||
@ -349,13 +318,13 @@ protected:
|
||||
nsCOMPtr<nsINode> mRoot;
|
||||
nsCOMPtr<nsINode> mStartParent;
|
||||
nsCOMPtr<nsINode> mEndParent;
|
||||
nsRefPtr<mozilla::dom::Selection> mSelection;
|
||||
int32_t mStartOffset;
|
||||
int32_t mEndOffset;
|
||||
|
||||
bool mIsPositioned : 1;
|
||||
bool mIsDetached : 1;
|
||||
bool mMaySpanAnonymousSubtrees : 1;
|
||||
bool mInSelection : 1;
|
||||
bool mIsGenerated : 1;
|
||||
bool mStartOffsetWasIncremented : 1;
|
||||
bool mEndOffsetWasIncremented : 1;
|
||||
|
@ -486,7 +486,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseXML)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCORSPreflightChannel)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)
|
||||
|
||||
@ -508,7 +507,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseXML)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCORSPreflightChannel)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)
|
||||
|
||||
@ -1210,9 +1208,6 @@ nsXMLHttpRequest::CloseRequestWithError(const nsAString& aType,
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
if (mCORSPreflightChannel) {
|
||||
mCORSPreflightChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
@ -2347,7 +2342,6 @@ nsXMLHttpRequest::ChangeStateToDone()
|
||||
// methods/members will not throw.
|
||||
// This matches what IE does.
|
||||
mChannel = nullptr;
|
||||
mCORSPreflightChannel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2891,36 +2885,33 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
|
||||
// Check to see if this initial OPTIONS request has already been cached
|
||||
// in our special Access Control Cache.
|
||||
|
||||
rv = NS_StartCORSPreflight(mChannel, listener,
|
||||
mPrincipal, withCredentials,
|
||||
mCORSUnsafeHeaders,
|
||||
getter_AddRefs(mCORSPreflightChannel));
|
||||
rv = internalHttpChannel->SetCorsPreflightParameters(mCORSUnsafeHeaders,
|
||||
withCredentials, mPrincipal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
mIsMappedArrayBuffer = false;
|
||||
if (mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
|
||||
Preferences::GetBool("dom.mapped_arraybuffer.enabled", false)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsAutoCString scheme;
|
||||
|
||||
rv = mChannel->GetURI(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uri->GetScheme(scheme);
|
||||
if (scheme.LowerCaseEqualsLiteral("app") ||
|
||||
scheme.LowerCaseEqualsLiteral("jar")) {
|
||||
mIsMappedArrayBuffer = true;
|
||||
}
|
||||
mIsMappedArrayBuffer = false;
|
||||
if (mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
|
||||
Preferences::GetBool("dom.mapped_arraybuffer.enabled", false)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsAutoCString scheme;
|
||||
|
||||
rv = mChannel->GetURI(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uri->GetScheme(scheme);
|
||||
if (scheme.LowerCaseEqualsLiteral("app") ||
|
||||
scheme.LowerCaseEqualsLiteral("jar")) {
|
||||
mIsMappedArrayBuffer = true;
|
||||
}
|
||||
}
|
||||
// Start reading from the channel
|
||||
rv = mChannel->AsyncOpen(listener, nullptr);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Start reading from the channel
|
||||
rv = mChannel->AsyncOpen(listener, nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Drop our ref to the channel to avoid cycles
|
||||
mChannel = nullptr;
|
||||
mCORSPreflightChannel = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -3013,19 +3004,6 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
// Check that we haven't already opened the channel. We can't rely on
|
||||
// the channel throwing from mChannel->SetRequestHeader since we might
|
||||
// still be waiting for mCORSPreflightChannel to actually open mChannel
|
||||
if (mCORSPreflightChannel) {
|
||||
bool pending;
|
||||
nsresult rv = mCORSPreflightChannel->IsPending(&pending);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (pending) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mChannel) // open() initializes mChannel, and open()
|
||||
return NS_ERROR_FAILURE; // must be called before first setRequestHeader()
|
||||
|
||||
|
@ -643,7 +643,6 @@ protected:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIDocument> mResponseXML;
|
||||
nsCOMPtr<nsIChannel> mCORSPreflightChannel;
|
||||
nsTArray<nsCString> mCORSUnsafeHeaders;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
|
||||
|
@ -2266,7 +2266,7 @@ void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
|
||||
|
||||
// Rooter class for sequences; this is what we mostly use in the codegen
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
|
||||
class MOZ_RAII SequenceRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
|
||||
@ -2325,7 +2325,7 @@ public:
|
||||
|
||||
// Rooter class for MozMap; this is what we mostly use in the codegen.
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS MozMapRooter : private JS::CustomAutoRooter
|
||||
class MOZ_RAII MozMapRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
|
||||
@ -2371,8 +2371,8 @@ private:
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS RootedUnion : public T,
|
||||
private JS::CustomAutoRooter
|
||||
class MOZ_RAII RootedUnion : public T,
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
|
@ -15,7 +15,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS RootedDictionary : public T,
|
||||
class MOZ_RAII RootedDictionary : public T,
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
@ -32,7 +32,7 @@ public:
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS NullableRootedDictionary : public Nullable<T>,
|
||||
class MOZ_RAII NullableRootedDictionary : public Nullable<T>,
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
|
@ -327,7 +327,7 @@ class TypedArrayCreator
|
||||
|
||||
// A class for rooting an existing TypedArray struct
|
||||
template<typename ArrayType>
|
||||
class MOZ_STACK_CLASS TypedArrayRooter : private JS::CustomAutoRooter
|
||||
class MOZ_RAII TypedArrayRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
TypedArrayRooter(JSContext* cx,
|
||||
@ -349,7 +349,7 @@ private:
|
||||
// And a specialization for dealing with nullable typed arrays
|
||||
template<typename Inner> struct Nullable;
|
||||
template<typename ArrayType>
|
||||
class MOZ_STACK_CLASS TypedArrayRooter<Nullable<ArrayType> > :
|
||||
class MOZ_RAII TypedArrayRooter<Nullable<ArrayType> > :
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
@ -373,8 +373,8 @@ private:
|
||||
|
||||
// Class for easily setting up a rooted typed array object on the stack
|
||||
template<typename ArrayType>
|
||||
class MOZ_STACK_CLASS RootedTypedArray : public ArrayType,
|
||||
private TypedArrayRooter<ArrayType>
|
||||
class MOZ_RAII RootedTypedArray : public ArrayType,
|
||||
private TypedArrayRooter<ArrayType>
|
||||
{
|
||||
public:
|
||||
explicit RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
|
@ -350,6 +350,10 @@ EVENT(lostpointercapture,
|
||||
ePointerLostCapture,
|
||||
EventNameType_All,
|
||||
ePointerEventClass)
|
||||
EVENT(selectstart,
|
||||
NS_SELECT_START,
|
||||
EventNameType_HTMLXUL,
|
||||
eBasicEventClass)
|
||||
|
||||
// Not supported yet; probably never because "wheel" is a better idea.
|
||||
// EVENT(mousewheel)
|
||||
@ -584,6 +588,10 @@ DOCUMENT_ONLY_EVENT(readystatechange,
|
||||
eReadyStateChange,
|
||||
EventNameType_HTMLXUL,
|
||||
eBasicEventClass)
|
||||
DOCUMENT_ONLY_EVENT(selectionchange,
|
||||
NS_SELECTION_CHANGE,
|
||||
EventNameType_HTMLXUL,
|
||||
eBasicEventClass)
|
||||
|
||||
NON_IDL_EVENT(MozMouseHittest,
|
||||
eMouseHitTest,
|
||||
|
@ -618,18 +618,19 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
|
||||
if (aCORSPreflightFlag) {
|
||||
MOZ_ASSERT(mRequest->Mode() != RequestMode::No_cors,
|
||||
"FetchDriver::ContinueFetch() should ensure that the request is not no-cors");
|
||||
nsCOMPtr<nsIChannel> preflightChannel;
|
||||
MOZ_ASSERT(httpChan, "CORS preflight can only be used with HTTP channels");
|
||||
nsAutoTArray<nsCString, 5> unsafeHeaders;
|
||||
mRequest->Headers()->GetUnsafeHeaders(unsafeHeaders);
|
||||
|
||||
rv = NS_StartCORSPreflight(chan, listener, mPrincipal,
|
||||
useCredentials,
|
||||
unsafeHeaders,
|
||||
getter_AddRefs(preflightChannel));
|
||||
} else {
|
||||
rv = chan->AsyncOpen(listener, nullptr);
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
|
||||
rv = internalChan->SetCorsPreflightParameters(unsafeHeaders, useCredentials, mPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return FailWithNetworkError();
|
||||
}
|
||||
}
|
||||
|
||||
rv = chan->AsyncOpen(listener, nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return FailWithNetworkError();
|
||||
}
|
||||
|
@ -53,7 +53,6 @@
|
||||
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsCORSListenerProxy.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsICachingChannel.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -93,6 +93,9 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoHideSelectionChanges hideSelectionChanges
|
||||
(mFrame->GetConstFrameSelection());
|
||||
|
||||
if (mFrame) {
|
||||
// SetSelectionRange leads to Selection::AddRange which flushes Layout -
|
||||
// need to block script to avoid nested PrepareEditor calls (bug 642800).
|
||||
@ -1248,6 +1251,8 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoHideSelectionChanges hideSelectionChanges(GetConstFrameSelection());
|
||||
|
||||
// Don't attempt to initialize recursively!
|
||||
InitializationGuard guard(*this);
|
||||
if (guard.IsInitializingRecursively()) {
|
||||
|
@ -562,37 +562,16 @@ nsresult ChannelMediaResource::OpenChannel(nsIStreamListener** aStreamListener)
|
||||
nsresult rv = mChannel->SetNotificationCallbacks(mListener.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = mListener.get();
|
||||
|
||||
// Ensure that if we're loading cross domain, that the server is sending
|
||||
// an authorizing Access-Control header.
|
||||
MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
||||
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
|
||||
if (element->ShouldCheckAllowOrigin()) {
|
||||
nsRefPtr<nsCORSListenerProxy> crossSiteListener =
|
||||
new nsCORSListenerProxy(mListener,
|
||||
element->NodePrincipal(),
|
||||
false);
|
||||
NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
|
||||
rv = crossSiteListener->Init(mChannel, DataURIHandling::Allow);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
listener = crossSiteListener;
|
||||
} else {
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
CheckLoadURIWithPrincipal(element->NodePrincipal(),
|
||||
mURI,
|
||||
nsIScriptSecurityManager::STANDARD);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = SetupChannelHeaders();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mChannel->AsyncOpen(listener, nullptr);
|
||||
rv = mChannel->AsyncOpen2(mListener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Tell the media element that we are fetching data from a channel.
|
||||
MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
||||
element->DownloadResumed(true);
|
||||
}
|
||||
|
||||
@ -869,14 +848,9 @@ ChannelMediaResource::RecreateChannel()
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
|
||||
NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
|
||||
if (nsContentUtils::ChannelShouldInheritPrincipal(element->NodePrincipal(),
|
||||
mURI,
|
||||
false, // aInheritForAboutBlank
|
||||
false // aForceInherit
|
||||
)) {
|
||||
securityFlags = nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
|
||||
}
|
||||
nsSecurityFlags securityFlags = element->ShouldCheckAllowOrigin()
|
||||
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
|
||||
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
|
||||
|
||||
MOZ_ASSERT(element->IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
|
||||
nsContentPolicyType contentPolicyType = element->IsHTMLElement(nsGkAtoms::audio) ?
|
||||
@ -1374,20 +1348,16 @@ nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener)
|
||||
rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput));
|
||||
}
|
||||
} else {
|
||||
// Ensure that we never load a local file from some page on a
|
||||
// web server.
|
||||
MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
dom::HTMLMediaElement* element = owner->GetMediaElement();
|
||||
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
|
||||
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
CheckLoadURIWithPrincipal(element->NodePrincipal(),
|
||||
mURI,
|
||||
nsIScriptSecurityManager::STANDARD);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mChannel->Open(getter_AddRefs(mInput));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
|
||||
MOZ_ASSERT((loadInfo->GetSecurityMode() &
|
||||
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) == 0,
|
||||
"can not enforce CORS when calling Open2()");
|
||||
}
|
||||
#endif
|
||||
rv = mChannel->Open2(getter_AddRefs(mInput));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -1451,14 +1421,9 @@ already_AddRefed<MediaResource> FileMediaResource::CloneData(MediaDecoder* aDeco
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = element->GetDocumentLoadGroup();
|
||||
NS_ENSURE_TRUE(loadGroup, nullptr);
|
||||
|
||||
nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
|
||||
if (nsContentUtils::ChannelShouldInheritPrincipal(element->NodePrincipal(),
|
||||
mURI,
|
||||
false, // aInheritForAboutBlank
|
||||
false // aForceInherit
|
||||
)) {
|
||||
securityFlags = nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
|
||||
}
|
||||
nsSecurityFlags securityFlags = element->ShouldCheckAllowOrigin()
|
||||
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
|
||||
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
|
||||
|
||||
MOZ_ASSERT(element->IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
|
||||
nsContentPolicyType contentPolicyType = element->IsHTMLElement(nsGkAtoms::audio) ?
|
||||
|
@ -794,7 +794,7 @@ protected:
|
||||
* us.
|
||||
*/
|
||||
template<class T>
|
||||
class MOZ_STACK_CLASS AutoPinned {
|
||||
class MOZ_RAII AutoPinned {
|
||||
public:
|
||||
explicit AutoPinned(T* aResource MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mResource(aResource) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
@ -306,7 +306,7 @@ public:
|
||||
return sIsLoadModuleOnStack;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS NotifyLoadingModule
|
||||
class MOZ_RAII NotifyLoadingModule
|
||||
{
|
||||
public:
|
||||
explicit NotifyLoadingModule(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
|
||||
|
@ -18,12 +18,10 @@ EXPORTS.mozilla.dom += [
|
||||
|
||||
EXPORTS += [
|
||||
'nsContentSecurityManager.h',
|
||||
'nsCORSListenerProxy.h'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsContentSecurityManager.cpp',
|
||||
'nsCORSListenerProxy.cpp',
|
||||
'nsCSPContext.cpp',
|
||||
'nsCSPParser.cpp',
|
||||
'nsCSPService.cpp',
|
||||
|
@ -29,12 +29,14 @@
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsSupportsPrimitives.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/CSPReportBinding.h"
|
||||
#include "mozilla/dom/CSPDictionariesBinding.h"
|
||||
|
@ -66,7 +66,7 @@ NS_INTERFACE_MAP_END
|
||||
// Helper class: AutoChangeLengthNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeLengthList and
|
||||
// DidChangeLengthList.
|
||||
class MOZ_STACK_CLASS AutoChangeLengthNotifier
|
||||
class MOZ_RAII AutoChangeLengthNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeLengthNotifier(DOMSVGLength* aLength MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -79,7 +79,7 @@ DOMSVGLengthList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
// Helper class: AutoChangeLengthListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeLengthList and
|
||||
// DidChangeLengthList.
|
||||
class MOZ_STACK_CLASS AutoChangeLengthListNotifier
|
||||
class MOZ_RAII AutoChangeLengthListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeLengthListNotifier(DOMSVGLengthList* aLengthList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -53,7 +53,7 @@ NS_INTERFACE_MAP_END
|
||||
// Helper class: AutoChangeNumberNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeNumberList and
|
||||
// DidChangeNumberList.
|
||||
class MOZ_STACK_CLASS AutoChangeNumberNotifier
|
||||
class MOZ_RAII AutoChangeNumberNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeNumberNotifier(DOMSVGNumber* aNumber MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -80,7 +80,7 @@ DOMSVGNumberList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
// Helper class: AutoChangeNumberListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeNumberList and
|
||||
// DidChangeNumberList.
|
||||
class MOZ_STACK_CLASS AutoChangeNumberListNotifier
|
||||
class MOZ_RAII AutoChangeNumberListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeNumberListNotifier(DOMSVGNumberList* aNumberList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -45,7 +45,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPathSeg, Release)
|
||||
// Helper class: AutoChangePathSegNotifier
|
||||
// Stack-based helper class to pair calls to WillChangePathSegList
|
||||
// and DidChangePathSegList.
|
||||
class MOZ_STACK_CLASS AutoChangePathSegNotifier
|
||||
class MOZ_RAII AutoChangePathSegNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangePathSegNotifier(DOMSVGPathSeg* aPathSeg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -55,7 +55,7 @@ NS_INTERFACE_MAP_END
|
||||
// Helper class: AutoChangePathSegListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangePathSegList and
|
||||
// DidChangePathSegList.
|
||||
class MOZ_STACK_CLASS AutoChangePathSegListNotifier
|
||||
class MOZ_RAII AutoChangePathSegListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangePathSegListNotifier(DOMSVGPathSegList* aPathSegList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -23,7 +23,7 @@ namespace mozilla {
|
||||
// Helper class: AutoChangePointNotifier
|
||||
// Stack-based helper class to pair calls to WillChangePointList and
|
||||
// DidChangePointList.
|
||||
class MOZ_STACK_CLASS AutoChangePointNotifier
|
||||
class MOZ_RAII AutoChangePointNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangePointNotifier(DOMSVGPoint* aPoint MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -73,7 +73,7 @@ NS_INTERFACE_MAP_END
|
||||
// Helper class: AutoChangePointListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangePointList and
|
||||
// DidChangePointList.
|
||||
class MOZ_STACK_CLASS AutoChangePointListNotifier
|
||||
class MOZ_RAII AutoChangePointListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangePointListNotifier(DOMSVGPointList* aPointList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -43,7 +43,7 @@ NS_INTERFACE_MAP_END
|
||||
// Helper class: AutoChangeStringListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeStringListList and
|
||||
// DidChangeStringListList.
|
||||
class MOZ_STACK_CLASS AutoChangeStringListNotifier
|
||||
class MOZ_RAII AutoChangeStringListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeStringListNotifier(DOMSVGStringList* aStringList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -81,7 +81,7 @@ DOMSVGTransformList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto
|
||||
// Helper class: AutoChangeTransformListNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeTransformList and
|
||||
// DidChangeTransformList.
|
||||
class MOZ_STACK_CLASS AutoChangeTransformListNotifier
|
||||
class MOZ_RAII AutoChangeTransformListNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeTransformListNotifier(DOMSVGTransformList* aTransformList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -407,7 +407,7 @@ private:
|
||||
|
||||
// Helper class to automatically manage temporary changes to an SVG document's
|
||||
// state for rendering purposes.
|
||||
class MOZ_STACK_CLASS AutoSVGRenderingState
|
||||
class MOZ_RAII AutoSVGRenderingState
|
||||
{
|
||||
public:
|
||||
AutoSVGRenderingState(const Maybe<SVGImageContext>& aSVGContext,
|
||||
|
@ -71,7 +71,7 @@ SVGTransform::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
// Helper class: AutoChangeTransformNotifier
|
||||
// Stack-based helper class to pair calls to WillChangeTransformList
|
||||
// and DidChangeTransformList.
|
||||
class MOZ_STACK_CLASS AutoChangeTransformNotifier
|
||||
class MOZ_RAII AutoChangeTransformNotifier
|
||||
{
|
||||
public:
|
||||
explicit AutoChangeTransformNotifier(SVGTransform* aTransform MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
414
dom/tests/mochitest/general/frameSelectEvents.html
Normal file
414
dom/tests/mochitest/general/frameSelectEvents.html
Normal file
@ -0,0 +1,414 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Testing Selection Events</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="normal">
|
||||
<span id="inner">A bunch of text in a span inside of a div which should be selected</span>
|
||||
</div>
|
||||
|
||||
<div id="ce" contenteditable>
|
||||
This is a random block of text
|
||||
</div>
|
||||
|
||||
<input type="text" id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"> <br>
|
||||
|
||||
<textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
|
||||
|
||||
<script>
|
||||
// Call the testing methods from the parent window
|
||||
var is = parent.is;
|
||||
var ok = parent.ok;
|
||||
|
||||
// spin() spins the event loop for two cycles, giving time for
|
||||
// selectionchange events to be fired, and handled by our listeners.
|
||||
function spin() {
|
||||
return new Promise(function(a) {
|
||||
parent.SimpleTest.executeSoon(function() {
|
||||
parent.SimpleTest.executeSoon(a)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// The main test
|
||||
parent.add_task(function *() {
|
||||
yield spin();
|
||||
|
||||
var selectstart = 0;
|
||||
var selectionchange = 0;
|
||||
var inputSelectionchange = 0;
|
||||
var textareaSelectionchange = 0;
|
||||
|
||||
var cancel = false;
|
||||
var selectstartTarget = null;
|
||||
|
||||
document.addEventListener('selectstart', function(aEvent) {
|
||||
console.log("originaltarget", aEvent.originalTarget, "new", selectstartTarget);
|
||||
is(aEvent.originalTarget, selectstartTarget,
|
||||
"The original target of selectstart");
|
||||
selectstartTarget = null;
|
||||
|
||||
console.log(selectstart);
|
||||
selectstart++;
|
||||
|
||||
if (cancel) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
});
|
||||
document.addEventListener('selectionchange', function(aEvent) {
|
||||
is(aEvent.originalTarget, document,
|
||||
"The original target of selectionchange should be the document");
|
||||
console.log(selectionchange);
|
||||
selectionchange++;
|
||||
});
|
||||
|
||||
function elt(aId) { return document.getElementById(aId); }
|
||||
function reset() {
|
||||
selectstart = 0;
|
||||
selectionchange = 0;
|
||||
inputSelectionchange = 0;
|
||||
textareaSelectionchange = 0;
|
||||
cancel = false;
|
||||
}
|
||||
|
||||
elt("input").addEventListener('selectionchange', function(aEvent) {
|
||||
is (aEvent.originalTarget, elt("input"),
|
||||
"The original target of selectionchange should be the input");
|
||||
console.log(inputSelectionchange);
|
||||
inputSelectionchange++;
|
||||
});
|
||||
elt("textarea").addEventListener('selectionchange', function(aEvent) {
|
||||
is (aEvent.originalTarget, elt("textarea"),
|
||||
"The original target of selectionchange should be the textarea");
|
||||
console.log(textareaSelectionchange);
|
||||
textareaSelectionchange++;
|
||||
});
|
||||
function* mouseAction(aElement, aOffset, aType,
|
||||
aSelStart, aSelChng, aISelChng, aTSelChng,
|
||||
aYOffset)
|
||||
{
|
||||
if (aType == "click") { // You can simulate a click event by sending undefined
|
||||
aType = undefined;
|
||||
}
|
||||
if (!aYOffset) {
|
||||
aYOffset = 10;
|
||||
}
|
||||
synthesizeMouse(aElement, aOffset, aYOffset, { type: aType });
|
||||
yield spin();
|
||||
|
||||
is(selectstart, aSelStart,
|
||||
"SelStart Mouse Action (" + aOffset + " - " + aType + ")");
|
||||
is(selectionchange, aSelChng,
|
||||
"SelChng Mouse Action (" + aOffset + " - " + aType + ")");
|
||||
is(inputSelectionchange, aISelChng || 0,
|
||||
"ISelChng Mouse Action (" + aOffset + " - " + aType + ")");
|
||||
is(textareaSelectionchange, aTSelChng || 0,
|
||||
"TSelChng Mouse Action (" + aOffset + " - " + aType + ")");
|
||||
reset();
|
||||
}
|
||||
|
||||
function* keyAction(aKey, aShift, aAccel,
|
||||
aSelStart, aSelChng, aISelChng, aTSelChng)
|
||||
{
|
||||
synthesizeKey(aKey, { shiftKey: aShift, accelKey: aAccel });
|
||||
yield spin();
|
||||
is(selectstart, aSelStart,
|
||||
"SelStart Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
|
||||
is(selectionchange, aSelChng,
|
||||
"SelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
|
||||
is(inputSelectionchange, aISelChng || 0,
|
||||
"ISelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
|
||||
is(textareaSelectionchange, aTSelChng || 0,
|
||||
"TSelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
|
||||
reset();
|
||||
}
|
||||
|
||||
var selection = document.getSelection();
|
||||
function isCollapsed() {
|
||||
is(selection.isCollapsed, true, "Selection is collapsed");
|
||||
}
|
||||
function isNotCollapsed() {
|
||||
is(selection.isCollapsed, false, "Selection is not collapsed");
|
||||
}
|
||||
|
||||
// Focus the contenteditable text
|
||||
yield* mouseAction(elt("ce"), 100, "click", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Move the selection to the right, this should only fire selectstart once
|
||||
selectstartTarget = elt("ce").firstChild;
|
||||
yield* keyAction("VK_RIGHT", true, false, 1, 1);
|
||||
isNotCollapsed();
|
||||
yield* keyAction("VK_RIGHT", true, false, 0, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
// Move it back so that the selection is empty again
|
||||
yield* keyAction("VK_LEFT", true, false, 0, 1);
|
||||
isNotCollapsed();
|
||||
yield* keyAction("VK_LEFT", true, false, 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Going from empty to non-empty should fire selectstart again
|
||||
selectstartTarget = elt("ce").firstChild;
|
||||
yield* keyAction("VK_LEFT", true, false, 1, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
function* mouseMoves(aElement, aTarget) {
|
||||
// Select a region
|
||||
yield* mouseAction(aElement, 50, "mousedown", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
selectstartTarget = aTarget;
|
||||
yield* mouseAction(aElement, 100, "mousemove", 1, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
// Moving it more shouldn't trigger a start (move back to empty)
|
||||
yield* mouseAction(aElement, 75, "mousemove", 0, 1);
|
||||
isNotCollapsed();
|
||||
yield* mouseAction(aElement, 50, "mousemove", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Wiggling the mouse a little such that it doesn't select any
|
||||
// characters shouldn't trigger a selection
|
||||
yield* mouseAction(aElement, 50, "mousemove", 0, 0, 0, 0, 11);
|
||||
isCollapsed();
|
||||
|
||||
// Moving the mouse again from an empty selection should trigger a
|
||||
// selectstart
|
||||
selectstartTarget = aTarget;
|
||||
yield* mouseAction(aElement, 25, "mousemove", 1, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
// Releasing the mouse shouldn't do anything
|
||||
yield* mouseAction(aElement, 25, "mouseup", 0, 0);
|
||||
isNotCollapsed();
|
||||
|
||||
// And neither should moving your mouse around when the mouse
|
||||
// button isn't pressed
|
||||
yield* mouseAction(aElement, 50, "mousemove", 0, 0);
|
||||
isNotCollapsed();
|
||||
|
||||
// Clicking in an random location should move the selection, but not perform a
|
||||
// selectstart
|
||||
yield* mouseAction(aElement, 50, "click", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Clicking there again should do nothing
|
||||
yield* mouseAction(aElement, 50, "click", 0, 0);
|
||||
isCollapsed();
|
||||
|
||||
// Selecting a region, and canceling the selectstart should mean that the
|
||||
// selection remains collapsed
|
||||
yield* mouseAction(aElement, 75, "mousedown", 0, 1);
|
||||
isCollapsed();
|
||||
cancel = true;
|
||||
selectstartTarget = aTarget;
|
||||
yield* mouseAction(aElement, 100, "mousemove", 1, 1);
|
||||
isCollapsed();
|
||||
yield* mouseAction(aElement, 100, "mouseup", 0, 0);
|
||||
isCollapsed();
|
||||
}
|
||||
|
||||
// Should work both on normal
|
||||
yield* mouseMoves(elt("inner"), elt("inner").firstChild);
|
||||
// and contenteditable fields
|
||||
yield* mouseMoves(elt("ce"), elt("ce").firstChild);
|
||||
// and fields with elements in them
|
||||
yield* mouseMoves(elt("normal"), elt("inner").firstChild);
|
||||
|
||||
yield* mouseAction(elt("inner"), 50, "click", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
reset();
|
||||
// Select all should fire both selectstart and change
|
||||
selectstartTarget = document.body;
|
||||
yield* keyAction("A", false, true, 1, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
// Clear the selection
|
||||
yield* mouseAction(elt("inner"), 50, "click", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Even if we already have a selection
|
||||
yield* mouseAction(elt("inner"), 75, "mousedown", 0, 1);
|
||||
isCollapsed();
|
||||
selectstartTarget = elt("inner").firstChild;
|
||||
yield* mouseAction(elt("inner"), 100, "mousemove", 1, 1);
|
||||
isNotCollapsed();
|
||||
yield* mouseAction(elt("inner"), 100, "mouseup", 0, 0);
|
||||
isNotCollapsed();
|
||||
|
||||
selectstartTarget = document.body;
|
||||
yield* keyAction("A", false, true, 1, 1);
|
||||
isNotCollapsed();
|
||||
|
||||
// Clear the selection
|
||||
yield* mouseAction(elt("inner"), 50, "click", 0, 1);
|
||||
isCollapsed();
|
||||
|
||||
// Make sure that a synthesized selection change doesn't fire selectstart
|
||||
var s = document.getSelection();
|
||||
s.removeAllRanges();
|
||||
yield spin();
|
||||
is(selectstart, 0, "Synthesized range removals shouldn't fire selectstart");
|
||||
is(selectionchange, 1, "Synthesized range removals should change selectionchange");
|
||||
reset();
|
||||
isCollapsed();
|
||||
|
||||
var range = document.createRange();
|
||||
range.selectNode(elt("inner"));
|
||||
s.addRange(range);
|
||||
yield spin();
|
||||
is(selectstart, 0, "Synthesized range additions shouldn't fire selectstart");
|
||||
is(selectionchange, 1, "Synthesized range additions should change selectionchange");
|
||||
reset();
|
||||
isNotCollapsed();
|
||||
|
||||
// Change the range, without replacing
|
||||
range.selectNode(elt("ce"));
|
||||
yield spin();
|
||||
is(selectstart, 0, "Synthesized range mutations shouldn't fire selectstart");
|
||||
is(selectionchange, 1, "Synthesized range mutations should change selectionchange");
|
||||
reset();
|
||||
isNotCollapsed();
|
||||
|
||||
// Remove the range
|
||||
s.removeAllRanges();
|
||||
yield spin();
|
||||
is(selectstart, 0, "Synthesized range removal");
|
||||
is(selectionchange, 1, "Synthesized range removal");
|
||||
reset();
|
||||
isCollapsed();
|
||||
|
||||
|
||||
/*
|
||||
Selection events mouse move on input type=text
|
||||
*/
|
||||
|
||||
// Select a region
|
||||
|
||||
yield* mouseAction(elt("input"), 50, "mousedown", 0, 1, 1, 0);
|
||||
|
||||
selectstartTarget = elt("input");
|
||||
yield* mouseAction(elt("input"), 100, "mousemove", 1, 0, 1, 0);
|
||||
|
||||
// Moving it more shouldn't trigger a start (move back to empty)
|
||||
yield* mouseAction(elt("input"), 75, "mousemove", 0, 0, 1, 0);
|
||||
yield* mouseAction(elt("input"), 50, "mousemove", 0, 0, 1, 0);
|
||||
|
||||
// Wiggling the mouse a little such that it doesn't select any
|
||||
// characters shouldn't trigger a selection
|
||||
yield* mouseAction(elt("input"), 50, "mousemove", 0, 0, 0, 0, 11);
|
||||
|
||||
// Moving the mouse again from an empty selection should trigger a
|
||||
// selectstart
|
||||
selectstartTarget = elt("input");
|
||||
yield* mouseAction(elt("input"), 25, "mousemove", 1, 0, 1, 0);
|
||||
|
||||
// Releasing the mouse shouldn't do anything
|
||||
yield* mouseAction(elt("input"), 25, "mouseup", 0, 0, 0, 0);
|
||||
|
||||
// And neither should moving your mouse around when the mouse
|
||||
// button isn't pressed
|
||||
yield* mouseAction(elt("input"), 50, "mousemove", 0, 0, 0, 0);
|
||||
|
||||
// Clicking in an random location should move the selection, but
|
||||
// not perform a selectstart
|
||||
yield* mouseAction(elt("input"), 50, "click", 0, 0, 1, 0);
|
||||
|
||||
// Clicking there again should do nothing
|
||||
yield* mouseAction(elt("input"), 50, "click", 0, 0, 0, 0);
|
||||
|
||||
// Selecting a region, and canceling the selectstart should mean that the
|
||||
// selection remains collapsed
|
||||
yield* mouseAction(elt("input"), 75, "mousedown", 0, 0, 1, 0);
|
||||
cancel = true;
|
||||
selectstartTarget = elt("input");
|
||||
yield* mouseAction(elt("input"), 100, "mousemove", 1, 0, 1, 0);
|
||||
yield* mouseAction(elt("input"), 100, "mouseup", 0, 0, 0, 0);
|
||||
|
||||
|
||||
// Select a region
|
||||
// XXX For some reason we fire 2 selectchange events on the body
|
||||
// when switching from the input to the text area.
|
||||
yield* mouseAction(elt("textarea"), 50, "mousedown", 0, 2, 0, 1);
|
||||
|
||||
selectstartTarget = elt("textarea");
|
||||
yield* mouseAction(elt("textarea"), 100, "mousemove", 1, 0, 0, 1);
|
||||
|
||||
// Moving it more shouldn't trigger a start (move back to empty)
|
||||
yield* mouseAction(elt("textarea"), 75, "mousemove", 0, 0, 0, 1);
|
||||
yield* mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 1);
|
||||
|
||||
// Wiggling the mouse a little such that it doesn't select any
|
||||
// characters shouldn't trigger a selection
|
||||
yield* mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 0, 11);
|
||||
|
||||
// Moving the mouse again from an empty selection should trigger a
|
||||
// selectstart
|
||||
selectstartTarget = elt("textarea");
|
||||
yield* mouseAction(elt("textarea"), 25, "mousemove", 1, 0, 0, 1);
|
||||
|
||||
// Releasing the mouse shouldn't do anything
|
||||
yield* mouseAction(elt("textarea"), 25, "mouseup", 0, 0, 0, 0);
|
||||
|
||||
// And neither should moving your mouse around when the mouse
|
||||
// button isn't pressed
|
||||
yield* mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 0);
|
||||
|
||||
// Clicking in an random location should move the selection, but not perform a
|
||||
// selectstart
|
||||
yield* mouseAction(elt("textarea"), 50, "click", 0, 0, 0, 1);
|
||||
|
||||
// Clicking there again should do nothing
|
||||
yield* mouseAction(elt("textarea"), 50, "click", 0, 0, 0, 0);
|
||||
|
||||
// Selecting a region, and canceling the selectstart should mean that the
|
||||
// selection remains collapsed
|
||||
yield* mouseAction(elt("textarea"), 75, "mousedown", 0, 0, 0, 1);
|
||||
cancel = true;
|
||||
selectstartTarget = elt("textarea");
|
||||
yield* mouseAction(elt("textarea"), 100, "mousemove", 1, 0, 0, 1);
|
||||
yield* mouseAction(elt("textarea"), 100, "mouseup", 0, 0, 0, 0);
|
||||
|
||||
// Marking the input and textarea as display: none and then as visible again
|
||||
// shouldn't trigger any changes, although the nodes will be re-framed
|
||||
elt("input").setAttribute("style", "display: none;");
|
||||
yield spin();
|
||||
is(selectstart, 0, "idn - ss 1");
|
||||
is(selectionchange, 0, "idn - sc 1");
|
||||
is(inputSelectionchange, 0, "idn - isc 1");
|
||||
is(textareaSelectionchange, 0, "idn - tsc 1");
|
||||
reset();
|
||||
|
||||
elt("input").setAttribute("style", "");
|
||||
yield spin();
|
||||
is(selectstart, 0, "idn - ss 2");
|
||||
is(selectionchange, 0, "idn - sc 2");
|
||||
is(inputSelectionchange, 0, "idn - isc 2");
|
||||
is(textareaSelectionchange, 0, "idn - tsc 2");
|
||||
reset();
|
||||
|
||||
elt("textarea").setAttribute("style", "display: none;");
|
||||
yield spin();
|
||||
is(selectstart, 0, "tdn - ss 1");
|
||||
is(selectionchange, 0, "tdn - sc 1");
|
||||
is(inputSelectionchange, 0, "tdn - isc 1");
|
||||
is(textareaSelectionchange, 0, "tdn - tsc 1");
|
||||
reset();
|
||||
|
||||
elt("textarea").setAttribute("style", "");
|
||||
yield spin();
|
||||
is(selectstart, 0, "tdn - ss 2");
|
||||
is(selectionchange, 0, "tdn - sc 2");
|
||||
is(inputSelectionchange, 0, "tdn - isc 2");
|
||||
is(textareaSelectionchange, 0, "tdn - tsc 2");
|
||||
reset();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -44,6 +44,7 @@ support-files =
|
||||
workerStorageAllowed.js
|
||||
workerStoragePrevented.js
|
||||
storagePermissionsUtils.js
|
||||
frameSelectEvents.html
|
||||
|
||||
[test_497898.html]
|
||||
skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #Bug 931116, b2g desktop specific, initial triage
|
||||
@ -120,3 +121,5 @@ skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
|
||||
skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
|
||||
[test_storagePermissionsLimitForeign.html]
|
||||
skip-if = buildapp == 'b2g' # Bug 1184427 - no SSL certs on b2g
|
||||
[test_selectevents.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' # Mouse doesn't select in the same way on b2g
|
||||
|
32
dom/tests/mochitest/general/test_selectevents.html
Normal file
32
dom/tests/mochitest/general/test_selectevents.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Testing Selection Events</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe width="500"></iframe>
|
||||
<script>
|
||||
add_task(function* () {
|
||||
// Push the correct preferences for the test
|
||||
yield new Promise((done) => {
|
||||
SpecialPowers.pushPrefEnv({'set': [['dom.select_events.enabled', true]]}, done);
|
||||
});
|
||||
|
||||
// Start the actual test
|
||||
yield new Promise((done) => {
|
||||
var iframe = document.querySelector('iframe');
|
||||
iframe.addEventListener('load', done);
|
||||
iframe.setAttribute('src', 'frameSelectEvents.html');
|
||||
});
|
||||
|
||||
// The child iframe will call add_task before we reach this point,
|
||||
// and will handle the rest of the test.
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -151,6 +151,7 @@ partial interface Document {
|
||||
attribute EventHandler onpaste;
|
||||
attribute EventHandler onbeforescriptexecute;
|
||||
attribute EventHandler onafterscriptexecute;
|
||||
|
||||
/**
|
||||
* True if this document is synthetic : stand alone image, video, audio file,
|
||||
* etc.
|
||||
|
@ -89,6 +89,9 @@ interface GlobalEventHandlers {
|
||||
attribute EventHandler onvolumechange;
|
||||
attribute EventHandler onwaiting;
|
||||
|
||||
[Pref="dom.select_events.enabled"]
|
||||
attribute EventHandler onselectstart;
|
||||
|
||||
// Pointer events handlers
|
||||
[Pref="dom.w3c_pointer_events.enabled"]
|
||||
attribute EventHandler onpointercancel;
|
||||
|
@ -543,7 +543,7 @@ class EventRunnable final : public MainThreadProxyRunnable
|
||||
nsresult mResponseResult;
|
||||
|
||||
public:
|
||||
class StateDataAutoRooter : private JS::CustomAutoRooter
|
||||
class MOZ_RAII StateDataAutoRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
XMLHttpRequest::StateData* mStateData;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
@ -31,7 +31,7 @@ class Selection;
|
||||
* stack based helper class for batching a collection of txns inside a
|
||||
* placeholder txn.
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoPlaceHolderBatch
|
||||
class MOZ_RAII nsAutoPlaceHolderBatch
|
||||
{
|
||||
private:
|
||||
nsCOMPtr<nsIEditor> mEd;
|
||||
@ -58,7 +58,7 @@ class MOZ_STACK_CLASS nsAutoPlaceHolderBatch
|
||||
* Note: I changed this to use placeholder batching so that we get
|
||||
* proper selection save/restore across undo/redo.
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoEditBatch : public nsAutoPlaceHolderBatch
|
||||
class MOZ_RAII nsAutoEditBatch : public nsAutoPlaceHolderBatch
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
public:
|
||||
@ -74,7 +74,7 @@ class MOZ_STACK_CLASS nsAutoEditBatch : public nsAutoPlaceHolderBatch
|
||||
* stack based helper class for saving/restoring selection. Note that this
|
||||
* assumes that the nodes involved are still around afterwards!
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoSelectionReset
|
||||
class MOZ_RAII nsAutoSelectionReset
|
||||
{
|
||||
private:
|
||||
/** ref-counted reference to the selection that we are supposed to restore */
|
||||
@ -96,7 +96,7 @@ class MOZ_STACK_CLASS nsAutoSelectionReset
|
||||
/***************************************************************************
|
||||
* stack based helper class for StartOperation()/EndOperation() sandwich
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoRules
|
||||
class MOZ_RAII nsAutoRules
|
||||
{
|
||||
public:
|
||||
|
||||
@ -131,7 +131,7 @@ class MOZ_STACK_CLASS nsAutoRules
|
||||
* stack based helper class for turning off active selection adjustment
|
||||
* by low level transactions
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoTxnsConserveSelection
|
||||
class MOZ_RAII nsAutoTxnsConserveSelection
|
||||
{
|
||||
public:
|
||||
|
||||
@ -163,7 +163,7 @@ class MOZ_STACK_CLASS nsAutoTxnsConserveSelection
|
||||
/***************************************************************************
|
||||
* stack based helper class for batching reflow and paint requests.
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoUpdateViewBatch
|
||||
class MOZ_RAII nsAutoUpdateViewBatch
|
||||
{
|
||||
public:
|
||||
|
||||
@ -197,7 +197,7 @@ class nsBoolDomIterFunctor
|
||||
virtual bool operator()(nsINode* aNode) const = 0;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS nsDOMIterator
|
||||
class MOZ_RAII nsDOMIterator
|
||||
{
|
||||
public:
|
||||
explicit nsDOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
@ -214,7 +214,7 @@ class MOZ_STACK_CLASS nsDOMIterator
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS nsDOMSubtreeIterator : public nsDOMIterator
|
||||
class MOZ_RAII nsDOMSubtreeIterator : public nsDOMIterator
|
||||
{
|
||||
public:
|
||||
explicit nsDOMSubtreeIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
|
@ -831,6 +831,14 @@ nsTextEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
}
|
||||
|
||||
nsresult res = NS_OK;
|
||||
// If the current selection is empty (e.g the user presses backspace with
|
||||
// a collapsed selection), then we want to avoid sending the selectstart
|
||||
// event to the user, so we hide selection changes. However, we still
|
||||
// want to send a single selectionchange event to the document, so we
|
||||
// batch the selectionchange events, such that a single event fires after
|
||||
// the AutoHideSelectionChanges destructor has been run.
|
||||
SelectionBatcher selectionBatcher(aSelection);
|
||||
AutoHideSelectionChanges hideSelection(aSelection);
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
if (IsPasswordEditor())
|
||||
|
@ -946,13 +946,20 @@ mozInlineSpellChecker::ReplaceWord(nsIDOMNode *aNode, int32_t aOffset,
|
||||
|
||||
if (range)
|
||||
{
|
||||
// This range was retrieved from the spellchecker selection. As
|
||||
// ranges cannot be shared between selections, we must clone it
|
||||
// before adding it to the editor's selection.
|
||||
nsCOMPtr<nsIDOMRange> editorRange;
|
||||
res = range->CloneRange(getter_AddRefs(editorRange));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
nsAutoPlaceHolderBatch phb(editor, nullptr);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
res = editor->GetSelection(getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
selection->RemoveAllRanges();
|
||||
selection->AddRange(range);
|
||||
selection->AddRange(editorRange);
|
||||
editor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
|
||||
|
||||
nsCOMPtr<nsIPlaintextEditor> textEditor(do_QueryReferent(mEditor));
|
||||
|
@ -277,7 +277,7 @@ private:
|
||||
|
||||
namespace {
|
||||
|
||||
class MOZ_STACK_CLASS MaybeScriptBlocker {
|
||||
class MOZ_RAII MaybeScriptBlocker {
|
||||
public:
|
||||
explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -23,7 +23,7 @@ namespace ipc {
|
||||
* current thread will be neutered. It is safe to nest multiple instances of
|
||||
* this class.
|
||||
*/
|
||||
class MOZ_STACK_CLASS NeuteredWindowRegion
|
||||
class MOZ_RAII NeuteredWindowRegion
|
||||
{
|
||||
public:
|
||||
explicit NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
@ -46,7 +46,7 @@ private:
|
||||
* disabling neutering for the remainder of its enclosing block.
|
||||
* @see NeuteredWindowRegion
|
||||
*/
|
||||
class MOZ_STACK_CLASS DeneuteredWindowRegion
|
||||
class MOZ_RAII DeneuteredWindowRegion
|
||||
{
|
||||
public:
|
||||
DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
|
@ -20,7 +20,7 @@
|
||||
* This stopwatch is active iff JSRuntime::stopwatch.isActive is set.
|
||||
* Upon destruction, update JSRuntime::stopwatch.data.totalCPOWTime.
|
||||
*/
|
||||
class MOZ_STACK_CLASS CPOWTimer final {
|
||||
class MOZ_RAII CPOWTimer final {
|
||||
public:
|
||||
explicit inline CPOWTimer(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~CPOWTimer();
|
||||
|
@ -654,7 +654,7 @@ namespace JS {
|
||||
* specialization, define a RootedBase<T> specialization containing them.
|
||||
*/
|
||||
template <typename T>
|
||||
class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
class MOZ_RAII Rooted : public js::RootedBase<T>
|
||||
{
|
||||
static_assert(!mozilla::IsConvertible<T, Traceable*>::value,
|
||||
"Rooted takes pointer or Traceable types but not Traceable* type");
|
||||
@ -777,7 +777,7 @@ class HandleBase<JSObject*>
|
||||
|
||||
/* Interface substitute for Rooted<T> which does not root the variable's memory. */
|
||||
template <typename T>
|
||||
class FakeRooted : public RootedBase<T>
|
||||
class MOZ_RAII FakeRooted : public RootedBase<T>
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
|
@ -482,7 +482,7 @@ class LifoAlloc
|
||||
};
|
||||
};
|
||||
|
||||
class LifoAllocScope
|
||||
class MOZ_NON_TEMPORARY_CLASS LifoAllocScope
|
||||
{
|
||||
LifoAlloc* lifoAlloc;
|
||||
LifoAlloc::Mark mark;
|
||||
|
@ -92,7 +92,7 @@ IsIncrementalGCSafe(JSRuntime* rt);
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
|
||||
class AutoStopVerifyingBarriers
|
||||
class MOZ_RAII AutoStopVerifyingBarriers
|
||||
{
|
||||
GCRuntime* gc;
|
||||
bool restartPreVerifier;
|
||||
@ -152,7 +152,7 @@ struct MovingTracer : JS::CallbackTracer
|
||||
#endif
|
||||
};
|
||||
|
||||
class AutoMaybeStartBackgroundAllocation
|
||||
class MOZ_RAII AutoMaybeStartBackgroundAllocation
|
||||
{
|
||||
private:
|
||||
JSRuntime* runtime;
|
||||
@ -176,7 +176,7 @@ class AutoMaybeStartBackgroundAllocation
|
||||
};
|
||||
|
||||
// In debug builds, set/unset the GC sweeping flag for the current thread.
|
||||
struct AutoSetThreadIsSweeping
|
||||
struct MOZ_RAII AutoSetThreadIsSweeping
|
||||
{
|
||||
#ifdef DEBUG
|
||||
explicit AutoSetThreadIsSweeping(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
|
||||
|
@ -331,7 +331,7 @@ struct Statistics
|
||||
double computeMMU(int64_t resolution) const;
|
||||
};
|
||||
|
||||
struct AutoGCSlice
|
||||
struct MOZ_RAII AutoGCSlice
|
||||
{
|
||||
AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
|
||||
SliceBudget budget, JS::gcreason::Reason reason
|
||||
@ -347,7 +347,7 @@ struct AutoGCSlice
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoPhase
|
||||
struct MOZ_RAII AutoPhase
|
||||
{
|
||||
AutoPhase(Statistics& stats, Phase phase
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
@ -391,7 +391,7 @@ struct AutoPhase
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoSCC
|
||||
struct MOZ_RAII AutoSCC
|
||||
{
|
||||
AutoSCC(Statistics& stats, unsigned scc
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -518,7 +518,7 @@ FinishAllOffThreadCompilations(JSCompartment* comp)
|
||||
}
|
||||
}
|
||||
|
||||
class AutoLazyLinkExitFrame
|
||||
class MOZ_RAII AutoLazyLinkExitFrame
|
||||
{
|
||||
JitActivation* jitActivation_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
@ -75,7 +75,7 @@ class IonSpewer
|
||||
}
|
||||
};
|
||||
|
||||
class AutoLockIonSpewerOutput
|
||||
class MOZ_RAII AutoLockIonSpewerOutput
|
||||
{
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
@ -505,7 +505,7 @@ CodeGeneratorMIPS::visitMulI(LMulI* ins)
|
||||
// Result is -0 if lhs or rhs is negative.
|
||||
// In that case result must be double value so bailout
|
||||
Register scratch = SecondScratchReg;
|
||||
masm.ma_or(scratch, ToRegister(lhs), ToRegister(rhs));
|
||||
masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs));
|
||||
bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot());
|
||||
|
||||
masm.bind(&done);
|
||||
@ -796,19 +796,19 @@ CodeGeneratorMIPS::visitBitOpI(LBitOpI* ins)
|
||||
if (rhs->isConstant())
|
||||
masm.ma_or(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
||||
else
|
||||
masm.ma_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
masm.as_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
break;
|
||||
case JSOP_BITXOR:
|
||||
if (rhs->isConstant())
|
||||
masm.ma_xor(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
||||
else
|
||||
masm.ma_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
masm.as_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
break;
|
||||
case JSOP_BITAND:
|
||||
if (rhs->isConstant())
|
||||
masm.ma_and(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
||||
else
|
||||
masm.ma_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
masm.as_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected binary opcode");
|
||||
@ -1647,7 +1647,7 @@ CodeGeneratorMIPS::visitBitAndAndBranch(LBitAndAndBranch* lir)
|
||||
if (lir->right()->isConstant())
|
||||
masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right())));
|
||||
else
|
||||
masm.ma_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right()));
|
||||
masm.as_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right()));
|
||||
emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(),
|
||||
lir->ifFalse());
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ MacroAssembler::not32(Register reg)
|
||||
void
|
||||
MacroAssembler::and32(Register src, Register dest)
|
||||
{
|
||||
ma_and(dest, dest, src);
|
||||
as_and(dest, dest, src);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -393,12 +393,6 @@ MacroAssemblerMIPS::ma_and(Register rd, Register rs)
|
||||
as_and(rd, rd, rs);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_and(Register rd, Register rs, Register rt)
|
||||
{
|
||||
as_and(rd, rs, rt);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_and(Register rd, Imm32 imm)
|
||||
{
|
||||
@ -423,12 +417,6 @@ MacroAssemblerMIPS::ma_or(Register rd, Register rs)
|
||||
as_or(rd, rd, rs);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_or(Register rd, Register rs, Register rt)
|
||||
{
|
||||
as_or(rd, rs, rt);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_or(Register rd, Imm32 imm)
|
||||
{
|
||||
@ -453,12 +441,6 @@ MacroAssemblerMIPS::ma_xor(Register rd, Register rs)
|
||||
as_xor(rd, rd, rs);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_xor(Register rd, Register rs, Register rt)
|
||||
{
|
||||
as_xor(rd, rs, rt);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_xor(Register rd, Imm32 imm)
|
||||
{
|
||||
@ -490,12 +472,6 @@ MacroAssemblerMIPS::ma_addu(Register rd, Register rs, Imm32 imm)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_addu(Register rd, Register rs, Register rt)
|
||||
{
|
||||
as_addu(rd, rs, rt);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_addu(Register rd, Register rs)
|
||||
{
|
||||
@ -549,12 +525,6 @@ MacroAssemblerMIPS::ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Labe
|
||||
}
|
||||
|
||||
// Subtract.
|
||||
void
|
||||
MacroAssemblerMIPS::ma_subu(Register rd, Register rs, Register rt)
|
||||
{
|
||||
as_subu(rd, rs, rt);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPS::ma_subu(Register rd, Register rs, Imm32 imm)
|
||||
{
|
||||
@ -578,7 +548,7 @@ MacroAssemblerMIPS::ma_subTestOverflow(Register rd, Register rs, Register rt, La
|
||||
Label goodSubtraction;
|
||||
// Use second scratch. The instructions generated by ma_b don't use the
|
||||
// second scratch register.
|
||||
ma_subu(rd, rs, rt);
|
||||
as_subu(rd, rs, rt);
|
||||
|
||||
as_xor(ScratchRegister, rs, rt); // If same sign, no overflow
|
||||
ma_b(ScratchRegister, Imm32(0), &goodSubtraction, Assembler::GreaterThanOrEqual, ShortJump);
|
||||
@ -1544,7 +1514,7 @@ MacroAssemblerMIPSCompat::sub32(Imm32 imm, Register dest)
|
||||
void
|
||||
MacroAssemblerMIPSCompat::sub32(Register src, Register dest)
|
||||
{
|
||||
ma_subu(dest, dest, src);
|
||||
as_subu(dest, dest, src);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1563,7 +1533,7 @@ MacroAssemblerMIPSCompat::addPtr(const Address& src, Register dest)
|
||||
void
|
||||
MacroAssemblerMIPSCompat::subPtr(Register src, Register dest)
|
||||
{
|
||||
ma_subu(dest, dest, src);
|
||||
as_subu(dest, dest, src);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2544,7 +2514,7 @@ MacroAssemblerMIPSCompat::loadConstantDouble(double dp, FloatRegister dest)
|
||||
void
|
||||
MacroAssemblerMIPSCompat::branchTestInt32Truthy(bool b, const ValueOperand& value, Label* label)
|
||||
{
|
||||
ma_and(ScratchRegister, value.payloadReg(), value.payloadReg());
|
||||
as_and(ScratchRegister, value.payloadReg(), value.payloadReg());
|
||||
ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero);
|
||||
}
|
||||
|
||||
|
@ -110,19 +110,16 @@ class MacroAssemblerMIPS : public Assembler
|
||||
|
||||
// and
|
||||
void ma_and(Register rd, Register rs);
|
||||
void ma_and(Register rd, Register rs, Register rt);
|
||||
void ma_and(Register rd, Imm32 imm);
|
||||
void ma_and(Register rd, Register rs, Imm32 imm);
|
||||
|
||||
// or
|
||||
void ma_or(Register rd, Register rs);
|
||||
void ma_or(Register rd, Register rs, Register rt);
|
||||
void ma_or(Register rd, Imm32 imm);
|
||||
void ma_or(Register rd, Register rs, Imm32 imm);
|
||||
|
||||
// xor
|
||||
void ma_xor(Register rd, Register rs);
|
||||
void ma_xor(Register rd, Register rs, Register rt);
|
||||
void ma_xor(Register rd, Imm32 imm);
|
||||
void ma_xor(Register rd, Register rs, Imm32 imm);
|
||||
|
||||
@ -143,14 +140,12 @@ class MacroAssemblerMIPS : public Assembler
|
||||
// arithmetic based ops
|
||||
// add
|
||||
void ma_addu(Register rd, Register rs, Imm32 imm);
|
||||
void ma_addu(Register rd, Register rs, Register rt);
|
||||
void ma_addu(Register rd, Register rs);
|
||||
void ma_addu(Register rd, Imm32 imm);
|
||||
void ma_addTestOverflow(Register rd, Register rs, Register rt, Label* overflow);
|
||||
void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label* overflow);
|
||||
|
||||
// subtract
|
||||
void ma_subu(Register rd, Register rs, Register rt);
|
||||
void ma_subu(Register rd, Register rs, Imm32 imm);
|
||||
void ma_subu(Register rd, Imm32 imm);
|
||||
void ma_subTestOverflow(Register rd, Register rs, Register rt, Label* overflow);
|
||||
|
@ -97,13 +97,13 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
break;
|
||||
}
|
||||
case JSOP_BITOR:
|
||||
masm.ma_or(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
masm.as_or(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
break;
|
||||
case JSOP_BITXOR:
|
||||
masm.ma_xor(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
masm.as_xor(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
break;
|
||||
case JSOP_BITAND:
|
||||
masm.ma_and(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
masm.as_and(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
|
||||
break;
|
||||
case JSOP_LSH:
|
||||
// MIPS will only use 5 lowest bits in R1 as shift offset.
|
||||
|
@ -441,7 +441,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
|
||||
masm.andPtr(Imm32(CalleeTokenMask), numArgsReg);
|
||||
masm.load16ZeroExtend(Address(numArgsReg, JSFunction::offsetOfNargs()), numArgsReg);
|
||||
|
||||
masm.ma_subu(t1, numArgsReg, s3);
|
||||
masm.as_subu(t1, numArgsReg, s3);
|
||||
|
||||
// Get the topmost argument.
|
||||
masm.ma_sll(t0, s3, Imm32(3)); // t0 <- nargs * 8
|
||||
@ -1191,7 +1191,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
|
||||
// Store return frame in lastProfilingFrame.
|
||||
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||
masm.ma_addu(scratch2, StackPointer, scratch1);
|
||||
masm.as_addu(scratch2, StackPointer, scratch1);
|
||||
masm.ma_addu(scratch2, scratch2, Imm32(JitFrameLayout::Size()));
|
||||
masm.storePtr(scratch2, lastProfilingFrame);
|
||||
masm.ret();
|
||||
@ -1225,7 +1225,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
//
|
||||
masm.bind(&handle_BaselineStub);
|
||||
{
|
||||
masm.ma_addu(scratch3, StackPointer, scratch1);
|
||||
masm.as_addu(scratch3, StackPointer, scratch1);
|
||||
Address stubFrameReturnAddr(scratch3,
|
||||
JitFrameLayout::Size() +
|
||||
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||
@ -1282,7 +1282,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
masm.bind(&handle_Rectifier);
|
||||
{
|
||||
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||
masm.ma_addu(scratch2, StackPointer, scratch1);
|
||||
masm.as_addu(scratch2, StackPointer, scratch1);
|
||||
masm.add32(Imm32(JitFrameLayout::Size()), scratch2);
|
||||
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3);
|
||||
masm.ma_srl(scratch1, scratch3, Imm32(FRAMESIZE_SHIFT));
|
||||
@ -1303,7 +1303,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||
|
||||
// scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size()
|
||||
masm.ma_addu(scratch3, scratch2, scratch1);
|
||||
masm.as_addu(scratch3, scratch2, scratch1);
|
||||
masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3);
|
||||
masm.storePtr(scratch3, lastProfilingFrame);
|
||||
masm.ret();
|
||||
@ -1318,7 +1318,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
masm.bind(&checkOk);
|
||||
}
|
||||
#endif
|
||||
masm.ma_addu(scratch3, scratch2, scratch1);
|
||||
masm.as_addu(scratch3, scratch2, scratch1);
|
||||
Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() +
|
||||
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||
@ -1350,7 +1350,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
masm.bind(&handle_IonAccessorIC);
|
||||
{
|
||||
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
|
||||
masm.ma_addu(scratch2, StackPointer, scratch1);
|
||||
masm.as_addu(scratch2, StackPointer, scratch1);
|
||||
masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2);
|
||||
|
||||
// scratch3 := AccFrame-Descriptor.Size
|
||||
@ -1374,7 +1374,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext* cx)
|
||||
|
||||
// lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size +
|
||||
// IonAccessorICFrameLayout::Size()
|
||||
masm.ma_addu(scratch1, scratch2, scratch3);
|
||||
masm.as_addu(scratch1, scratch2, scratch3);
|
||||
masm.addPtr(Imm32(IonAccessorICFrameLayout::Size()), scratch1);
|
||||
masm.storePtr(scratch1, lastProfilingFrame);
|
||||
masm.ret();
|
||||
|
@ -67,7 +67,7 @@ class JS_PUBLIC_API(AutoCheckRequestDepth)
|
||||
|
||||
/* AutoValueArray roots an internal fixed-size array of Values. */
|
||||
template <size_t N>
|
||||
class AutoValueArray : public AutoGCRooter
|
||||
class MOZ_RAII AutoValueArray : public AutoGCRooter
|
||||
{
|
||||
const size_t length_;
|
||||
Value elements_[N];
|
||||
@ -99,7 +99,7 @@ class AutoValueArray : public AutoGCRooter
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class AutoVectorRooterBase : protected AutoGCRooter
|
||||
class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter
|
||||
{
|
||||
typedef js::Vector<T, 8> VectorImpl;
|
||||
VectorImpl vector;
|
||||
@ -196,7 +196,7 @@ class AutoVectorRooterBase : protected AutoGCRooter
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MOZ_STACK_CLASS AutoVectorRooter : public AutoVectorRooterBase<T>
|
||||
class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase<T>
|
||||
{
|
||||
public:
|
||||
explicit AutoVectorRooter(JSContext* cx
|
||||
@ -225,7 +225,7 @@ using IdVector = js::TraceableVector<jsid>;
|
||||
using ScriptVector = js::TraceableVector<JSScript*>;
|
||||
|
||||
template<class Key, class Value>
|
||||
class AutoHashMapRooter : protected AutoGCRooter
|
||||
class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter
|
||||
{
|
||||
private:
|
||||
typedef js::HashMap<Key, Value> HashMapImpl;
|
||||
@ -349,7 +349,7 @@ class AutoHashMapRooter : protected AutoGCRooter
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class AutoHashSetRooter : protected AutoGCRooter
|
||||
class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter
|
||||
{
|
||||
private:
|
||||
typedef js::HashSet<T> HashSetImpl;
|
||||
@ -460,7 +460,7 @@ class AutoHashSetRooter : protected AutoGCRooter
|
||||
/*
|
||||
* Custom rooting behavior for internal and external clients.
|
||||
*/
|
||||
class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
|
||||
class MOZ_RAII JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
@ -1070,7 +1070,7 @@ AssertHeapIsIdle(JSContext* cx);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
class JSAutoRequest
|
||||
class MOZ_RAII JSAutoRequest
|
||||
{
|
||||
public:
|
||||
explicit JSAutoRequest(JSContext* cx
|
||||
@ -1409,7 +1409,7 @@ JS_RefreshCrossCompartmentWrappers(JSContext* cx, JS::Handle<JSObject*> obj);
|
||||
* the corresponding JS_LeaveCompartment call.
|
||||
*/
|
||||
|
||||
class JS_PUBLIC_API(JSAutoCompartment)
|
||||
class MOZ_RAII JS_PUBLIC_API(JSAutoCompartment)
|
||||
{
|
||||
JSContext* cx_;
|
||||
JSCompartment* oldCompartment_;
|
||||
@ -1423,7 +1423,7 @@ class JS_PUBLIC_API(JSAutoCompartment)
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API(JSAutoNullableCompartment)
|
||||
class MOZ_RAII JS_PUBLIC_API(JSAutoNullableCompartment)
|
||||
{
|
||||
JSContext* cx_;
|
||||
JSCompartment* oldCompartment_;
|
||||
@ -4227,7 +4227,7 @@ JS_GetStringEncodingLength(JSContext* cx, JSString* str);
|
||||
JS_PUBLIC_API(size_t)
|
||||
JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length);
|
||||
|
||||
class JSAutoByteString
|
||||
class MOZ_RAII JSAutoByteString
|
||||
{
|
||||
public:
|
||||
JSAutoByteString(JSContext* cx, JSString* str
|
||||
@ -5039,7 +5039,7 @@ HideScriptedCaller(JSContext* cx);
|
||||
extern JS_PUBLIC_API(void)
|
||||
UnhideScriptedCaller(JSContext* cx);
|
||||
|
||||
class AutoHideScriptedCaller
|
||||
class MOZ_RAII AutoHideScriptedCaller
|
||||
{
|
||||
public:
|
||||
explicit AutoHideScriptedCaller(JSContext* cx
|
||||
|
@ -33,7 +33,7 @@ typedef HashSet<JSObject*> ObjectSet;
|
||||
typedef HashSet<Shape*> ShapeSet;
|
||||
|
||||
/* Detects cycles when traversing an object graph. */
|
||||
class AutoCycleDetector
|
||||
class MOZ_RAII AutoCycleDetector
|
||||
{
|
||||
JSContext* cx;
|
||||
RootedObject obj;
|
||||
@ -466,7 +466,7 @@ struct JSContext : public js::ExclusiveContext,
|
||||
|
||||
namespace js {
|
||||
|
||||
struct AutoResolving {
|
||||
struct MOZ_RAII AutoResolving {
|
||||
public:
|
||||
enum Kind {
|
||||
LOOKUP,
|
||||
@ -670,7 +670,7 @@ using ShapeVector = js::TraceableVector<Shape*>;
|
||||
using StringVector = js::TraceableVector<JSString*>;
|
||||
|
||||
/* AutoArrayRooter roots an external array of Values. */
|
||||
class AutoArrayRooter : private JS::AutoGCRooter
|
||||
class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter
|
||||
{
|
||||
public:
|
||||
AutoArrayRooter(JSContext* cx, size_t len, Value* vec
|
||||
@ -749,7 +749,7 @@ class AutoAssertNoException
|
||||
/* Exposed intrinsics for the JITs. */
|
||||
bool intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
class AutoLockForExclusiveAccess
|
||||
class MOZ_RAII AutoLockForExclusiveAccess
|
||||
{
|
||||
JSRuntime* runtime;
|
||||
|
||||
|
@ -185,7 +185,7 @@ using NewObjectMetadataState = mozilla::Variant<ImmediateMetadata,
|
||||
DelayMetadata,
|
||||
PendingMetadata>;
|
||||
|
||||
class MOZ_STACK_CLASS AutoSetNewObjectMetadata : private JS::CustomAutoRooter
|
||||
class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
|
||||
@ -764,7 +764,7 @@ ExclusiveContext::global() const
|
||||
return Handle<GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
|
||||
}
|
||||
|
||||
class AssertCompartmentUnchanged
|
||||
class MOZ_RAII AssertCompartmentUnchanged
|
||||
{
|
||||
public:
|
||||
explicit AssertCompartmentUnchanged(JSContext* cx
|
||||
@ -862,7 +862,7 @@ struct WrapperValue
|
||||
Value value;
|
||||
};
|
||||
|
||||
class AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
|
||||
class MOZ_RAII AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
|
||||
{
|
||||
public:
|
||||
explicit AutoWrapperVector(JSContext* cx
|
||||
@ -875,7 +875,7 @@ class AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class AutoWrapperRooter : private JS::AutoGCRooter {
|
||||
class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter {
|
||||
public:
|
||||
AutoWrapperRooter(JSContext* cx, WrapperValue v
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -2694,7 +2694,7 @@ typedef void
|
||||
JS_FRIEND_API(void)
|
||||
SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb);
|
||||
|
||||
class JS_FRIEND_API(AutoCTypesActivityCallback) {
|
||||
class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) {
|
||||
private:
|
||||
JSContext* cx;
|
||||
CTypesActivityCallback callback;
|
||||
|
@ -1374,7 +1374,7 @@ NewMemoryStatisticsObject(JSContext* cx);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Use this to avoid assertions when manipulating the wrapper map. */
|
||||
class AutoDisableProxyCheck
|
||||
class MOZ_RAII AutoDisableProxyCheck
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
gc::GCRuntime& gc;
|
||||
|
@ -168,7 +168,7 @@ ImplicitCast(U& u)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class AutoScopedAssign
|
||||
class MOZ_RAII AutoScopedAssign
|
||||
{
|
||||
public:
|
||||
AutoScopedAssign(T* addr, const T& value
|
||||
|
@ -3400,7 +3400,7 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp)
|
||||
return JS_ExecuteScript(cx, script, args.rval());
|
||||
}
|
||||
|
||||
struct FreeOnReturn
|
||||
struct MOZ_RAII FreeOnReturn
|
||||
{
|
||||
JSContext* cx;
|
||||
const char* ptr;
|
||||
|
@ -1824,7 +1824,7 @@ Debugger::slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise)
|
||||
|
||||
/*** Debugger code invalidation for observing execution ******************************************/
|
||||
|
||||
class MOZ_STACK_CLASS ExecutionObservableCompartments : public Debugger::ExecutionObservableSet
|
||||
class MOZ_RAII ExecutionObservableCompartments : public Debugger::ExecutionObservableSet
|
||||
{
|
||||
HashSet<JSCompartment*> compartments_;
|
||||
HashSet<Zone*> zones_;
|
||||
@ -1858,7 +1858,7 @@ class MOZ_STACK_CLASS ExecutionObservableCompartments : public Debugger::Executi
|
||||
// represents the stack frames that need to be bailed out or marked as
|
||||
// debuggees, and the scripts that need to be recompiled, taking inlining into
|
||||
// account.
|
||||
class MOZ_STACK_CLASS ExecutionObservableFrame : public Debugger::ExecutionObservableSet
|
||||
class MOZ_RAII ExecutionObservableFrame : public Debugger::ExecutionObservableSet
|
||||
{
|
||||
AbstractFramePtr frame_;
|
||||
|
||||
@ -1919,7 +1919,7 @@ class MOZ_STACK_CLASS ExecutionObservableFrame : public Debugger::ExecutionObser
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS ExecutionObservableScript : public Debugger::ExecutionObservableSet
|
||||
class MOZ_RAII ExecutionObservableScript : public Debugger::ExecutionObservableSet
|
||||
{
|
||||
RootedScript script_;
|
||||
|
||||
|
@ -412,7 +412,7 @@ struct AutoEnqueuePendingParseTasksAfterGC {
|
||||
bool
|
||||
StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task);
|
||||
|
||||
class AutoLockHelperThreadState
|
||||
class MOZ_RAII AutoLockHelperThreadState
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
@ -428,7 +428,7 @@ class AutoLockHelperThreadState
|
||||
}
|
||||
};
|
||||
|
||||
class AutoUnlockHelperThreadState
|
||||
class MOZ_RAII AutoUnlockHelperThreadState
|
||||
{
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
|
@ -375,7 +375,7 @@ namespace js {
|
||||
// All mutable state is stored in `Runtime::stopwatch` (per-process
|
||||
// performance stats and logistics) and in `PerformanceGroup` (per
|
||||
// group performance stats).
|
||||
class AutoStopwatch final
|
||||
class MOZ_RAII AutoStopwatch final
|
||||
{
|
||||
// The context with which this object was initialized.
|
||||
// Non-null.
|
||||
|
@ -186,7 +186,7 @@ class RegExpStatics
|
||||
}
|
||||
};
|
||||
|
||||
class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
|
||||
class MOZ_RAII AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
explicit AutoRegExpStaticsBuffer(JSContext* cx
|
||||
|
@ -1864,7 +1864,7 @@ FreeOp::freeLater(void* p)
|
||||
* Note that the lock may be temporarily released by use of AutoUnlockGC when
|
||||
* passed a non-const reference to this class.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoLockGC
|
||||
class MOZ_RAII AutoLockGC
|
||||
{
|
||||
public:
|
||||
explicit AutoLockGC(JSRuntime* rt
|
||||
@ -1903,7 +1903,7 @@ class MOZ_STACK_CLASS AutoLockGC
|
||||
AutoLockGC& operator=(const AutoLockGC&) = delete;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoUnlockGC
|
||||
class MOZ_RAII AutoUnlockGC
|
||||
{
|
||||
public:
|
||||
explicit AutoUnlockGC(AutoLockGC& lock
|
||||
@ -1926,7 +1926,7 @@ class MOZ_STACK_CLASS AutoUnlockGC
|
||||
AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoKeepAtoms
|
||||
class MOZ_RAII AutoKeepAtoms
|
||||
{
|
||||
PerThreadData* pt;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -2095,7 +2095,7 @@ extern const JSSecurityCallbacks NullSecurityCallbacks;
|
||||
|
||||
// Debugging RAII class which marks the current thread as performing an Ion
|
||||
// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
|
||||
class AutoEnterIonCompilation
|
||||
class MOZ_RAII AutoEnterIonCompilation
|
||||
{
|
||||
public:
|
||||
explicit AutoEnterIonCompilation(bool safeForMinorGC
|
||||
|
@ -227,7 +227,7 @@ class AutoSPSLock
|
||||
* This class is used to suppress profiler sampling during
|
||||
* critical sections where stack state is not valid.
|
||||
*/
|
||||
class AutoSuppressProfilerSampling
|
||||
class MOZ_RAII AutoSuppressProfilerSampling
|
||||
{
|
||||
public:
|
||||
explicit AutoSuppressProfilerSampling(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
@ -260,7 +260,7 @@ SPSProfiler::stringsReset()
|
||||
* that we're about to enter JS function calls. This is the only time in which a
|
||||
* valid stack pointer is pushed to the sampling stack.
|
||||
*/
|
||||
class SPSEntryMarker
|
||||
class MOZ_RAII SPSEntryMarker
|
||||
{
|
||||
public:
|
||||
explicit SPSEntryMarker(JSRuntime* rt,
|
||||
@ -279,7 +279,7 @@ class SPSEntryMarker
|
||||
* being entered via OSR. It marks the current top pseudostack entry as
|
||||
* OSR-ed
|
||||
*/
|
||||
class SPSBaselineOSRMarker
|
||||
class MOZ_RAII SPSBaselineOSRMarker
|
||||
{
|
||||
public:
|
||||
explicit SPSBaselineOSRMarker(JSRuntime* rt, bool hasSPSFrame
|
||||
|
@ -181,7 +181,7 @@ class SavedStacks {
|
||||
// Similar to mozilla::ReentrancyGuard, but instead of asserting against
|
||||
// reentrancy, just change the behavior of SavedStacks::saveCurrentStack to
|
||||
// return a nullptr SavedFrame.
|
||||
struct MOZ_STACK_CLASS AutoReentrancyGuard {
|
||||
struct MOZ_RAII AutoReentrancyGuard {
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
|
||||
SavedStacks& stacks;
|
||||
|
||||
|
@ -825,7 +825,7 @@ CloneNestedScopeObject(JSContext* cx, HandleObject enclosingScope, Handle<Nested
|
||||
// whether the current scope is within the extent of this initial frame.
|
||||
// Here, "frame" means a single activation of: a function, eval, or global
|
||||
// code.
|
||||
class ScopeIter
|
||||
class MOZ_RAII ScopeIter
|
||||
{
|
||||
StaticScopeIter<CanGC> ssi_;
|
||||
RootedObject scope_;
|
||||
|
@ -982,7 +982,7 @@ StackBaseShape::StackBaseShape(Shape* shape)
|
||||
compartment(shape->compartment())
|
||||
{}
|
||||
|
||||
class AutoRooterGetterSetter
|
||||
class MOZ_RAII AutoRooterGetterSetter
|
||||
{
|
||||
class Inner : private JS::CustomAutoRooter
|
||||
{
|
||||
|
@ -439,7 +439,7 @@ inline void TraceLogStopEventPrivate(TraceLoggerThread* logger, uint32_t id) {
|
||||
}
|
||||
|
||||
// Automatic logging at the start and end of function call.
|
||||
class AutoTraceLog
|
||||
class MOZ_RAII AutoTraceLog
|
||||
{
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread* logger;
|
||||
|
@ -24,7 +24,7 @@ using mozilla::NativeEndian;
|
||||
|
||||
TraceLoggerGraphState* traceLoggerGraphState = nullptr;
|
||||
|
||||
class AutoTraceLoggerGraphStateLock
|
||||
class MOZ_RAII AutoTraceLoggerGraphStateLock
|
||||
{
|
||||
TraceLoggerGraphState* graph;
|
||||
|
||||
|
@ -3040,7 +3040,7 @@ private:
|
||||
/******************************************************************************
|
||||
* Handles pre/post script processing.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoScriptEvaluate
|
||||
class MOZ_RAII AutoScriptEvaluate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@ -3077,7 +3077,7 @@ private:
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
class MOZ_STACK_CLASS AutoResolveName
|
||||
class MOZ_RAII AutoResolveName
|
||||
{
|
||||
public:
|
||||
AutoResolveName(XPCCallContext& ccx, JS::HandleId name
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsStyleSet.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "nsFrameSelection.h"
|
||||
|
||||
#define DEFAULT_COLUMN_WIDTH 20
|
||||
|
||||
@ -259,6 +260,13 @@ nsTextControlFrame::EnsureEditorInitialized()
|
||||
// Make sure that editor init doesn't do things that would kill us off
|
||||
// (especially off the script blockers it'll create for its DOM mutations).
|
||||
{
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
|
||||
MOZ_ASSERT(txtCtrl, "Content not a text control element");
|
||||
|
||||
// Hide selection changes during the initialization, as webpages should not
|
||||
// be aware of these initializations
|
||||
AutoHideSelectionChanges hideSelectionChanges(txtCtrl->GetConstFrameSelection());
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
// Time to mess with our security context... See comments in GetValue()
|
||||
@ -288,8 +296,6 @@ nsTextControlFrame::EnsureEditorInitialized()
|
||||
#endif
|
||||
|
||||
// Create an editor for the frame, if one doesn't already exist
|
||||
nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
|
||||
NS_ASSERTION(txtCtrl, "Content not a text control element");
|
||||
nsresult rv = txtCtrl->CreateEditor();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(weakFrame.IsAlive());
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
* into multiple ranges to exclude those before adding the resulting ranges
|
||||
* to this Selection.
|
||||
*/
|
||||
nsresult AddItem(nsRange* aRange, int32_t* aOutIndex);
|
||||
nsresult AddItem(nsRange* aRange, int32_t* aOutIndex, bool aNoStartSelect = false);
|
||||
nsresult RemoveItem(nsRange* aRange);
|
||||
nsresult RemoveCollapsedRanges();
|
||||
nsresult Clear(nsPresContext* aPresContext);
|
||||
@ -204,6 +204,9 @@ public:
|
||||
int16_t aVPercent, int16_t aHPercent,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
void AddSelectionChangeBlocker();
|
||||
void RemoveSelectionChangeBlocker();
|
||||
bool IsBlockingSelectionChangeEvents() const;
|
||||
private:
|
||||
friend class ::nsAutoScrollTimer;
|
||||
|
||||
@ -217,7 +220,7 @@ public:
|
||||
nsresult NotifySelectionListeners();
|
||||
|
||||
friend struct AutoApplyUserSelectStyle;
|
||||
struct MOZ_STACK_CLASS AutoApplyUserSelectStyle
|
||||
struct MOZ_RAII AutoApplyUserSelectStyle
|
||||
{
|
||||
explicit AutoApplyUserSelectStyle(Selection* aSelection
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
@ -229,6 +232,7 @@ public:
|
||||
AutoRestore<bool> mSavedValue;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
private:
|
||||
friend struct mozilla::AutoPrepareFocusRange;
|
||||
class ScrollSelectionIntoViewEvent;
|
||||
@ -282,6 +286,8 @@ private:
|
||||
int32_t* aStartIndex, int32_t* aEndIndex);
|
||||
RangeData* FindRangeData(nsIDOMRange* aRange);
|
||||
|
||||
void UserSelectRangesToAdd(nsRange* aItem, nsTArray<nsRefPtr<nsRange> >& rangesToAdd);
|
||||
|
||||
/**
|
||||
* Helper method for AddItem.
|
||||
*/
|
||||
@ -312,9 +318,14 @@ private:
|
||||
SelectionType mType;
|
||||
/**
|
||||
* True if the current selection operation was initiated by user action.
|
||||
* It determines whether we exclude -moz-user-select:none nodes or not.
|
||||
* It determines whether we exclude -moz-user-select:none nodes or not,
|
||||
* as well as whether selectstart events will be fired.
|
||||
*/
|
||||
bool mApplyUserSelectStyle;
|
||||
|
||||
// Non-zero if we don't want any changes we make to the selection to be
|
||||
// visible to content. If non-zero, content won't be notified about changes.
|
||||
uint32_t mSelectionChangeBlockerCount;
|
||||
};
|
||||
|
||||
// Stack-class to turn on/off selection batching.
|
||||
@ -339,6 +350,33 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoHideSelectionChanges final
|
||||
{
|
||||
private:
|
||||
nsRefPtr<Selection> mSelection;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
public:
|
||||
explicit AutoHideSelectionChanges(const nsFrameSelection* aFrame);
|
||||
|
||||
explicit AutoHideSelectionChanges(Selection* aSelection
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mSelection(aSelection)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
mSelection = aSelection;
|
||||
if (mSelection) {
|
||||
mSelection->AddSelectionChangeBlocker();
|
||||
}
|
||||
}
|
||||
|
||||
~AutoHideSelectionChanges()
|
||||
{
|
||||
if (mSelection) {
|
||||
mSelection->RemoveSelectionChangeBlocker();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
57
layout/generic/SelectionChangeListener.h
Normal file
57
layout/generic/SelectionChangeListener.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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 mozilla_SelectionChangeListener_h_
|
||||
#define mozilla_SelectionChangeListener_h_
|
||||
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SelectionChangeListener final : public nsISelectionListener
|
||||
{
|
||||
public:
|
||||
// SelectionChangeListener has to participate in cycle collection because
|
||||
// it holds strong references to nsINodes in its mOldRanges array.
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(SelectionChangeListener)
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
// This field is used to keep track of the ranges which were present in the
|
||||
// selection when the selectionchange event was previously fired. This allows
|
||||
// for the selectionchange event to only be fired when a selection is actually
|
||||
// changed.
|
||||
struct RawRangeData
|
||||
{
|
||||
// These properties are not void*s to avoid the potential situation where the
|
||||
// nsINode is freed, and a new nsINode is allocated with the same address, which
|
||||
// could potentially break the comparison logic. In reality, this is extremely
|
||||
// unlikely to occur (potentially impossible), but these nsCOMPtrs are safer.
|
||||
// They are never dereferenced.
|
||||
nsCOMPtr<nsINode> mStartParent;
|
||||
nsCOMPtr<nsINode> mEndParent;
|
||||
|
||||
// XXX These are int32_ts on nsRange, but uint32_ts in the return value
|
||||
// of GetStart_, so I use uint32_ts here. See bug 1194256.
|
||||
uint32_t mStartOffset;
|
||||
uint32_t mEndOffset;
|
||||
|
||||
explicit RawRangeData(const nsRange* aRange);
|
||||
bool Equals(const nsRange* aRange);
|
||||
};
|
||||
|
||||
private:
|
||||
nsTArray<RawRangeData> mOldRanges;
|
||||
|
||||
~SelectionChangeListener() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SelectionChangeListener_h_
|
@ -3623,7 +3623,7 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
// RAII class to clean up a list of FlexLines.
|
||||
// Specifically, this removes each line from the list, deletes all the
|
||||
// FlexItems in its list, and deletes the FlexLine.
|
||||
class MOZ_STACK_CLASS AutoFlexLineListClearer
|
||||
class MOZ_RAII AutoFlexLineListClearer
|
||||
{
|
||||
public:
|
||||
explicit AutoFlexLineListClearer(LinkedList<FlexLine>& aLines
|
||||
|
@ -752,6 +752,8 @@ private:
|
||||
bool mDesiredPosSet;
|
||||
|
||||
int8_t mCaretMovementStyle;
|
||||
|
||||
static bool sSelectionEventsEnabled;
|
||||
};
|
||||
|
||||
#endif /* nsFrameSelection_h___ */
|
||||
|
@ -68,6 +68,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
||||
|
||||
#include "nsISelectionController.h"//for the enums
|
||||
#include "nsAutoCopyListener.h"
|
||||
#include "SelectionChangeListener.h"
|
||||
#include "nsCopySupport.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
@ -79,6 +80,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/SelectionBinding.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -332,7 +334,7 @@ IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode)
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
struct MOZ_STACK_CLASS AutoPrepareFocusRange
|
||||
struct MOZ_RAII AutoPrepareFocusRange
|
||||
{
|
||||
AutoPrepareFocusRange(Selection* aSelection,
|
||||
bool aContinueSelection,
|
||||
@ -412,7 +414,7 @@ struct MOZ_STACK_CLASS AutoPrepareFocusRange
|
||||
while (i--) {
|
||||
range = aSelection->mRanges[i].mRange;
|
||||
if (range->IsGenerated()) {
|
||||
range->SetInSelection(false);
|
||||
range->SetSelection(nullptr);
|
||||
aSelection->selectFrames(presContext, range, false);
|
||||
aSelection->mRanges.RemoveElementAt(i);
|
||||
}
|
||||
@ -814,6 +816,16 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
|
||||
mLimiter = aLimiter;
|
||||
mCaretMovementStyle =
|
||||
Preferences::GetInt("bidi.edit.caret_movement_style", 2);
|
||||
|
||||
// This should only ever be initialized on the main thread, so we are OK here.
|
||||
static bool prefCachesInitialized = false;
|
||||
if (!prefCachesInitialized) {
|
||||
prefCachesInitialized = true;
|
||||
|
||||
Preferences::AddBoolVarCache(&sSelectionEventsEnabled,
|
||||
"dom.select_events.enabled", false);
|
||||
}
|
||||
|
||||
// Set touch caret as selection listener
|
||||
nsRefPtr<TouchCaret> touchCaret = mShell->GetTouchCaret();
|
||||
if (touchCaret) {
|
||||
@ -839,8 +851,21 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
|
||||
mDomSelections[index]->AddSelectionListener(eventHub);
|
||||
}
|
||||
}
|
||||
|
||||
if (sSelectionEventsEnabled) {
|
||||
int8_t index =
|
||||
GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
if (mDomSelections[index]) {
|
||||
// The Selection instance will hold a strong reference to its selectionchangelistener
|
||||
// so we don't have to worry about that!
|
||||
nsRefPtr<SelectionChangeListener> listener = new SelectionChangeListener;
|
||||
mDomSelections[index]->AddSelectionListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nsFrameSelection::sSelectionEventsEnabled = false;
|
||||
|
||||
nsresult
|
||||
nsFrameSelection::MoveCaret(nsDirection aDirection,
|
||||
bool aContinueSelection,
|
||||
@ -3307,6 +3332,7 @@ Selection::Selection()
|
||||
, mDirection(eDirNext)
|
||||
, mType(nsISelectionController::SELECTION_NORMAL)
|
||||
, mApplyUserSelectStyle(false)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -3316,6 +3342,7 @@ Selection::Selection(nsFrameSelection* aList)
|
||||
, mDirection(eDirNext)
|
||||
, mType(nsISelectionController::SELECTION_NORMAL)
|
||||
, mApplyUserSelectStyle(false)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -3325,7 +3352,7 @@ Selection::~Selection()
|
||||
|
||||
uint32_t count = mRanges.Length();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
mRanges[i].mRange->SetInSelection(false);
|
||||
mRanges[i].mRange->SetSelection(nullptr);
|
||||
}
|
||||
|
||||
if (mAutoScrollTimer) {
|
||||
@ -3647,8 +3674,24 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Selection::UserSelectRangesToAdd(nsRange* aItem, nsTArray<nsRefPtr<nsRange>>& aRangesToAdd)
|
||||
{
|
||||
aItem->ExcludeNonSelectableNodes(&aRangesToAdd);
|
||||
if (aRangesToAdd.IsEmpty()) {
|
||||
ErrorResult err;
|
||||
nsINode* node = aItem->GetStartContainer(err);
|
||||
if (node && node->IsContent() && node->AsContent()->GetEditingHost()) {
|
||||
// A contenteditable node with user-select:none, for example.
|
||||
// Allow it to have a collapsed selection (for the caret).
|
||||
aItem->Collapse(GetDirection() == eDirPrevious);
|
||||
aRangesToAdd.AppendElement(aItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
Selection::AddItem(nsRange* aItem, int32_t* aOutIndex)
|
||||
Selection::AddItem(nsRange* aItem, int32_t* aOutIndex, bool aNoStartSelect)
|
||||
{
|
||||
if (!aItem)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
@ -3657,20 +3700,60 @@ Selection::AddItem(nsRange* aItem, int32_t* aOutIndex)
|
||||
|
||||
NS_ASSERTION(aOutIndex, "aOutIndex can't be null");
|
||||
|
||||
// XXX Rename mApplyUserSelectStyle? Not the best name (as it is also being
|
||||
// used to detect here whether the event is user initiated for the purposes of
|
||||
// dispatching the selectstart event).
|
||||
if (mApplyUserSelectStyle) {
|
||||
nsAutoTArray<nsRefPtr<nsRange>, 4> rangesToAdd;
|
||||
aItem->ExcludeNonSelectableNodes(&rangesToAdd);
|
||||
if (rangesToAdd.IsEmpty()) {
|
||||
ErrorResult err;
|
||||
nsINode* node = aItem->GetStartContainer(err);
|
||||
if (node && node->IsContent() && node->AsContent()->GetEditingHost()) {
|
||||
// A contenteditable node with user-select:none, for example.
|
||||
// Allow it to have a collapsed selection (for the caret).
|
||||
aItem->Collapse(GetDirection() == eDirPrevious);
|
||||
rangesToAdd.AppendElement(aItem);
|
||||
}
|
||||
}
|
||||
*aOutIndex = -1;
|
||||
|
||||
if (!aNoStartSelect && mType == nsISelectionController::SELECTION_NORMAL &&
|
||||
nsFrameSelection::sSelectionEventsEnabled && Collapsed() &&
|
||||
!IsBlockingSelectionChangeEvents()) {
|
||||
// First, we generate the ranges to add with a scratch range, which is a
|
||||
// clone of the original range passed in. We do this seperately, because the
|
||||
// selectstart event could have caused the world to change, and required
|
||||
// ranges to be re-generated
|
||||
nsRefPtr<nsRange> scratchRange = aItem->CloneRange();
|
||||
UserSelectRangesToAdd(scratchRange, rangesToAdd);
|
||||
bool newRangesNonEmpty = rangesToAdd.Length() > 1 ||
|
||||
(rangesToAdd.Length() == 1 && !rangesToAdd[0]->Collapsed());
|
||||
|
||||
MOZ_ASSERT(!newRangesNonEmpty || nsContentUtils::IsSafeToRunScript());
|
||||
if (newRangesNonEmpty && nsContentUtils::IsSafeToRunScript()) {
|
||||
// We consider a selection to be starting if we are currently collapsed,
|
||||
// and the selection is becoming uncollapsed, and this is caused by a user
|
||||
// initiated event.
|
||||
bool defaultAction = true;
|
||||
|
||||
// Get the first element which isn't in a native anonymous subtree
|
||||
nsCOMPtr<nsINode> target = aItem->GetStartParent();
|
||||
while (target && target->IsInNativeAnonymousSubtree()) {
|
||||
target = target->GetParent();
|
||||
}
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(GetParentObject(), target,
|
||||
NS_LITERAL_STRING("selectstart"),
|
||||
true, true, &defaultAction);
|
||||
|
||||
if (!defaultAction) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// As we just dispatched an event to the DOM, something could have
|
||||
// changed under our feet. Re-generate the rangesToAdd array, and ensure
|
||||
// that the range we are about to add is still valid.
|
||||
if (!aItem->IsPositioned()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
// The scratch ranges we generated may be invalid now, throw them out
|
||||
rangesToAdd.ClearAndRetainStorage();
|
||||
}
|
||||
|
||||
// Generate the ranges to add
|
||||
UserSelectRangesToAdd(aItem, rangesToAdd);
|
||||
size_t newAnchorFocusIndex =
|
||||
GetDirection() == eDirPrevious ? 0 : rangesToAdd.Length() - 1;
|
||||
for (size_t i = 0; i < rangesToAdd.Length(); ++i) {
|
||||
@ -3702,7 +3785,7 @@ Selection::AddItemInternal(nsRange* aItem, int32_t* aOutIndex)
|
||||
if (mRanges.Length() == 0) {
|
||||
if (!mRanges.AppendElement(RangeData(aItem)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
aItem->SetInSelection(true);
|
||||
aItem->SetSelection(this);
|
||||
|
||||
*aOutIndex = 0;
|
||||
return NS_OK;
|
||||
@ -3742,7 +3825,7 @@ Selection::AddItemInternal(nsRange* aItem, int32_t* aOutIndex)
|
||||
// The new range doesn't overlap any existing ranges
|
||||
if (!mRanges.InsertElementAt(startIndex, RangeData(aItem)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
aItem->SetInSelection(true);
|
||||
aItem->SetSelection(this);
|
||||
*aOutIndex = startIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -3764,7 +3847,7 @@ Selection::AddItemInternal(nsRange* aItem, int32_t* aOutIndex)
|
||||
|
||||
// Remove all the overlapping ranges
|
||||
for (int32_t i = startIndex; i < endIndex; ++i) {
|
||||
mRanges[i].mRange->SetInSelection(false);
|
||||
mRanges[i].mRange->SetSelection(nullptr);
|
||||
}
|
||||
mRanges.RemoveElementsAt(startIndex, endIndex - startIndex);
|
||||
|
||||
@ -3789,7 +3872,7 @@ Selection::AddItemInternal(nsRange* aItem, int32_t* aOutIndex)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (uint32_t i = 0; i < temp.Length(); ++i) {
|
||||
temp[i].mRange->SetInSelection(true);
|
||||
temp[i].mRange->SetSelection(this);
|
||||
}
|
||||
|
||||
*aOutIndex = startIndex + insertionPoint;
|
||||
@ -3818,7 +3901,7 @@ Selection::RemoveItem(nsRange* aItem)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
mRanges.RemoveElementAt(idx);
|
||||
aItem->SetInSelection(false);
|
||||
aItem->SetSelection(nullptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3843,7 +3926,7 @@ Selection::Clear(nsPresContext* aPresContext)
|
||||
setAnchorFocusRange(-1);
|
||||
|
||||
for (uint32_t i = 0; i < mRanges.Length(); ++i) {
|
||||
mRanges[i].mRange->SetInSelection(false);
|
||||
mRanges[i].mRange->SetSelection(nullptr);
|
||||
selectFrames(aPresContext, mRanges[i].mRange, false);
|
||||
}
|
||||
mRanges.Clear();
|
||||
@ -5064,12 +5147,14 @@ Selection::SetAnchorFocusToRange(nsRange* aRange)
|
||||
{
|
||||
NS_ENSURE_STATE(mAnchorFocusRange);
|
||||
|
||||
bool collapsed = Collapsed();
|
||||
|
||||
nsresult res = RemoveItem(mAnchorFocusRange);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
|
||||
int32_t aOutIndex = -1;
|
||||
res = AddItem(aRange, &aOutIndex);
|
||||
res = AddItem(aRange, &aOutIndex, !collapsed);
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
setAnchorFocusRange(aOutIndex);
|
||||
@ -5471,19 +5556,16 @@ Selection::SelectAllChildren(nsIDOMNode* aParentNode)
|
||||
void
|
||||
Selection::SelectAllChildren(nsINode& aNode, ErrorResult& aRv)
|
||||
{
|
||||
if (mFrameSelection)
|
||||
{
|
||||
if (mFrameSelection) {
|
||||
mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
|
||||
}
|
||||
SelectionBatcher batch(this);
|
||||
|
||||
Collapse(aNode, 0, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFrameSelection)
|
||||
{
|
||||
mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
|
||||
}
|
||||
Extend(aNode, aNode.GetChildCount(), aRv);
|
||||
}
|
||||
|
||||
@ -5926,7 +6008,26 @@ Selection::EndBatchChanges()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Selection::AddSelectionChangeBlocker()
|
||||
{
|
||||
mSelectionChangeBlockerCount++;
|
||||
}
|
||||
|
||||
void
|
||||
Selection::RemoveSelectionChangeBlocker()
|
||||
{
|
||||
MOZ_ASSERT(mSelectionChangeBlockerCount > 0,
|
||||
"mSelectionChangeBlockerCount has an invalid value - "
|
||||
"maybe you have a mismatched RemoveSelectionChangeBlocker?");
|
||||
mSelectionChangeBlockerCount--;
|
||||
}
|
||||
|
||||
bool
|
||||
Selection::IsBlockingSelectionChangeEvents() const
|
||||
{
|
||||
return mSelectionChangeBlockerCount > 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Selection::DeleteFromDocument()
|
||||
@ -6159,6 +6260,13 @@ Selection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
return mozilla::dom::SelectionBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
// AutoHideSelectionChanges
|
||||
AutoHideSelectionChanges::AutoHideSelectionChanges(const nsFrameSelection* aFrame)
|
||||
: AutoHideSelectionChanges(aFrame ?
|
||||
aFrame->GetSelection(nsISelectionController::SELECTION_NORMAL) :
|
||||
nullptr)
|
||||
{}
|
||||
|
||||
// nsAutoCopyListener
|
||||
|
||||
nsAutoCopyListener* nsAutoCopyListener::sInstance = nullptr;
|
||||
@ -6218,3 +6326,131 @@ nsAutoCopyListener::NotifySelectionChanged(nsIDOMDocument *aDoc,
|
||||
return nsCopySupport::HTMLCopy(aSel, doc,
|
||||
nsIClipboard::kSelectionClipboard, false);
|
||||
}
|
||||
|
||||
// SelectionChangeListener
|
||||
|
||||
SelectionChangeListener::RawRangeData::RawRangeData(const nsRange* aRange)
|
||||
{
|
||||
mozilla::ErrorResult rv;
|
||||
mStartParent = aRange->GetStartContainer(rv);
|
||||
rv.SuppressException();
|
||||
mEndParent = aRange->GetEndContainer(rv);
|
||||
rv.SuppressException();
|
||||
mStartOffset = aRange->GetStartOffset(rv);
|
||||
rv.SuppressException();
|
||||
mEndOffset = aRange->GetEndOffset(rv);
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
bool
|
||||
SelectionChangeListener::RawRangeData::Equals(const nsRange* aRange)
|
||||
{
|
||||
mozilla::ErrorResult rv;
|
||||
bool eq = mStartParent == aRange->GetStartContainer(rv);
|
||||
rv.SuppressException();
|
||||
eq = eq && mEndParent == aRange->GetEndContainer(rv);
|
||||
rv.SuppressException();
|
||||
eq = eq && mStartOffset == aRange->GetStartOffset(rv);
|
||||
rv.SuppressException();
|
||||
eq = eq && mEndOffset == aRange->GetEndOffset(rv);
|
||||
rv.SuppressException();
|
||||
return eq;
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
SelectionChangeListener::RawRangeData& aField,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
ImplCycleCollectionTraverse(aCallback, aField.mStartParent, "mStartParent", aFlags);
|
||||
ImplCycleCollectionTraverse(aCallback, aField.mEndParent, "mEndParent", aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(SelectionChangeListener)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SelectionChangeListener)
|
||||
tmp->mOldRanges.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SelectionChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOldRanges);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SelectionChangeListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SelectionChangeListener)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SelectionChangeListener)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SelectionChangeListener::NotifySelectionChanged(nsIDOMDocument* aDoc,
|
||||
nsISelection* aSel, int16_t aReason)
|
||||
{
|
||||
// This cast is valid as nsISelection is a builtinclass which is only
|
||||
// implemented by Selection.
|
||||
nsRefPtr<Selection> sel = static_cast<Selection*>(aSel);
|
||||
|
||||
// Check if the ranges have actually changed
|
||||
// Don't bother checking this if we are hiding changes.
|
||||
if (mOldRanges.Length() == sel->RangeCount() && !sel->IsBlockingSelectionChangeEvents()) {
|
||||
bool changed = false;
|
||||
|
||||
for (size_t i = 0; i < mOldRanges.Length(); i++) {
|
||||
if (!mOldRanges[i].Equals(sel->GetRangeAt(i))) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// The ranges have actually changed, update the mOldRanges array
|
||||
mOldRanges.ClearAndRetainStorage();
|
||||
for (size_t i = 0; i < sel->RangeCount(); i++) {
|
||||
mOldRanges.AppendElement(RawRangeData(sel->GetRangeAt(i)));
|
||||
}
|
||||
|
||||
// If we are hiding changes, then don't do anything else. We do this after we
|
||||
// update mOldRanges so that changes after the changes stop being hidden don't
|
||||
// incorrectly trigger a change, even though they didn't change anything
|
||||
if (sel->IsBlockingSelectionChangeEvents()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> target;
|
||||
|
||||
// Check if we should be firing this event to a different node than the
|
||||
// document. The limiter of the nsFrameSelection will be within the native
|
||||
// anonymous subtree of the node we want to fire the event on. We need to
|
||||
// climb up the parent chain to escape the native anonymous subtree, and then
|
||||
// fire the event.
|
||||
if (nsFrameSelection* fs = sel->GetFrameSelection()) {
|
||||
if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
|
||||
while (root && root->IsInNativeAnonymousSubtree()) {
|
||||
root = root->GetParent();
|
||||
}
|
||||
|
||||
target = root.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't get a target before, we can instead fire the event at the document.
|
||||
if (!target) {
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
|
||||
target = doc.forget();
|
||||
}
|
||||
|
||||
if (target) {
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(target, NS_LITERAL_STRING("selectionchange"), false);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -428,7 +428,7 @@ protected:
|
||||
* state (in a CSSParserInputState object), and it restores the parser to
|
||||
* that state when destructed, unless "DoNotRestore()" has been called.
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoCSSParserInputStateRestorer {
|
||||
class MOZ_RAII nsAutoCSSParserInputStateRestorer {
|
||||
public:
|
||||
explicit nsAutoCSSParserInputStateRestorer(CSSParserImpl* aParser
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
@ -476,7 +476,7 @@ protected:
|
||||
* XXXdholbert we could also change this & report errors, if needed. Might
|
||||
* want to customize the error reporting somehow though.
|
||||
*/
|
||||
class MOZ_STACK_CLASS nsAutoScannerChanger {
|
||||
class MOZ_RAII nsAutoScannerChanger {
|
||||
public:
|
||||
nsAutoScannerChanger(CSSParserImpl* aParser,
|
||||
const nsAString& aStringToScan
|
||||
|
@ -225,7 +225,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
||||
}
|
||||
|
||||
/* Helper class for maintaining the ancestor state */
|
||||
class MOZ_STACK_CLASS AutoAncestorPusher {
|
||||
class MOZ_RAII AutoAncestorPusher {
|
||||
public:
|
||||
explicit AutoAncestorPusher(TreeMatchContext& aTreeMatchContext
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
@ -295,7 +295,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
||||
* in cases where we may or may not want to be skipping flex/grid-item
|
||||
* style fixup for a particular chunk of code).
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoParentDisplayBasedStyleFixupSkipper {
|
||||
class MOZ_RAII AutoParentDisplayBasedStyleFixupSkipper {
|
||||
public:
|
||||
explicit AutoParentDisplayBasedStyleFixupSkipper(TreeMatchContext& aTreeMatchContext,
|
||||
bool aSkipParentDisplayBasedStyleFixup = true
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
// automatically sets and clears the mInUse flag on the clip path frame
|
||||
// (to prevent nasty reference loops). It's easy to mess this up
|
||||
// and break things, so this helper makes the code far more robust.
|
||||
class MOZ_STACK_CLASS AutoClipPathReferencer
|
||||
class MOZ_RAII AutoClipPathReferencer
|
||||
{
|
||||
public:
|
||||
explicit AutoClipPathReferencer(nsSVGClipPathFrame *aFrame
|
||||
|
@ -27,7 +27,7 @@ NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame)
|
||||
|
||||
class MOZ_STACK_CLASS nsSVGFilterFrame::AutoFilterReferencer
|
||||
class MOZ_RAII nsSVGFilterFrame::AutoFilterReferencer
|
||||
{
|
||||
public:
|
||||
explicit AutoFilterReferencer(nsSVGFilterFrame *aFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -24,7 +24,7 @@ using namespace mozilla::dom;
|
||||
//----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
|
||||
class MOZ_STACK_CLASS nsSVGGradientFrame::AutoGradientReferencer
|
||||
class MOZ_RAII nsSVGGradientFrame::AutoGradientReferencer
|
||||
{
|
||||
public:
|
||||
explicit AutoGradientReferencer(nsSVGGradientFrame *aFrame
|
||||
|
@ -110,7 +110,7 @@ private:
|
||||
// prevent nasty reference loops) as well as the reference to the marked
|
||||
// frame and its coordinate context. It's easy to mess this up
|
||||
// and break things, so this helper makes the code far more robust.
|
||||
class MOZ_STACK_CLASS AutoMarkerReferencer
|
||||
class MOZ_RAII AutoMarkerReferencer
|
||||
{
|
||||
public:
|
||||
AutoMarkerReferencer(nsSVGMarkerFrame *aFrame,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user