--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -250,16 +250,17 @@ nsRange::nsRange(nsINode* aNode)
, mStartOffset(0)
, mEndOffset(0)
, mIsPositioned(false)
, mMaySpanAnonymousSubtrees(false)
, mIsGenerated(false)
, mStartOffsetWasIncremented(false)
, mEndOffsetWasIncremented(false)
, mEnableGravitationOnElementRemoval(true)
+ , mCalledByJS(false)
#ifdef DEBUG
, mAssertNextInsertOrAppendIndex(-1)
, mAssertNextInsertOrAppendNode(nullptr)
#endif
{
MOZ_ASSERT(aNode, "range isn't in a document!");
mOwner = aNode->OwnerDoc();
}
@@ -962,17 +963,17 @@ nsRange::DoSetRange(nsINode* aStartN, in
// 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();
+ mSelection->NotifySelectionListeners(mCalledByJS);
}
}
static int32_t
IndexOf(nsINode* aChild)
{
nsINode* parent = aChild->GetParentNode();
@@ -1181,16 +1182,23 @@ nsRange::IsValidBoundary(nsINode* aNode)
NS_ASSERTION(!root->IsNodeOfType(nsINode::eDOCUMENT),
"GetUncomposedDoc should have returned a doc");
// We allow this because of backward compatibility.
return root;
}
void
+nsRange::SetStartJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetStart(aNode, aOffset, aErr);
+}
+
+void
nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1234,16 +1242,23 @@ nsRange::SetStart(nsINode* aParent, int3
}
DoSetRange(aParent, aOffset, mEndParent, mEndOffset, mRoot);
return NS_OK;
}
void
+nsRange::SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetStartBefore(aNode, aErr);
+}
+
+void
nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1260,16 +1275,23 @@ nsRange::SetStartBefore(nsIDOMNode* aSib
}
ErrorResult rv;
SetStartBefore(*sibling, rv);
return rv.StealNSResult();
}
void
+nsRange::SetStartAfterJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetStartAfter(aNode, aErr);
+}
+
+void
nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1286,16 +1308,23 @@ nsRange::SetStartAfter(nsIDOMNode* aSibl
}
ErrorResult rv;
SetStartAfter(*sibling, rv);
return rv.StealNSResult();
}
void
+nsRange::SetEndJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetEnd(aNode, aOffset, aErr);
+}
+
+void
nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
AutoInvalidateSelection atEndOfBlock(this);
@@ -1338,16 +1367,23 @@ nsRange::SetEnd(nsINode* aParent, int32_
}
DoSetRange(mStartParent, mStartOffset, aParent, aOffset, mRoot);
return NS_OK;
}
void
+nsRange::SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetEndBefore(aNode, aErr);
+}
+
+void
nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1364,16 +1400,23 @@ nsRange::SetEndBefore(nsIDOMNode* aSibli
}
ErrorResult rv;
SetEndBefore(*sibling, rv);
return rv.StealNSResult();
}
void
+nsRange::SetEndAfterJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SetEndAfter(aNode, aErr);
+}
+
+void
nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1404,28 +1447,42 @@ nsRange::Collapse(bool aToStart)
if (aToStart)
DoSetRange(mStartParent, mStartOffset, mStartParent, mStartOffset, mRoot);
else
DoSetRange(mEndParent, mEndOffset, mEndParent, mEndOffset, mRoot);
return NS_OK;
}
+void
+nsRange::CollapseJS(bool aToStart)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ Unused << Collapse(aToStart);
+}
+
NS_IMETHODIMP
nsRange::SelectNode(nsIDOMNode* aN)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aN);
NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
ErrorResult rv;
SelectNode(*node, rv);
return rv.StealNSResult();
}
void
+nsRange::SelectNodeJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SelectNode(aNode, aErr);
+}
+
+void
nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@@ -1453,16 +1510,23 @@ nsRange::SelectNodeContents(nsIDOMNode*
NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
ErrorResult rv;
SelectNodeContents(*node, rv);
return rv.StealNSResult();
}
void
+nsRange::SelectNodeContentsJS(nsINode& aNode, ErrorResult& aErr)
+{
+ AutoCalledByJSSetter markAsCalledByJS(*this);
+ SelectNodeContents(aNode, aErr);
+}
+
+void
nsRange::SelectNodeContents(nsINode& aNode, ErrorResult& aRv)
{
if (!nsContentUtils::LegacyIsCallerNativeCode() &&
!nsContentUtils::CanCallerAccess(&aNode)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -16,16 +16,17 @@
#include "nsINode.h"
#include "nsIDocument.h"
#include "nsIDOMNode.h"
#include "nsLayoutUtils.h"
#include "prmon.h"
#include "nsStubMutationObserver.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
+#include "mozilla/GuardObjects.h"
namespace mozilla {
class ErrorResult;
namespace dom {
struct ClientRectsAndTexts;
class DocumentFragment;
class DOMRect;
class DOMRectList;
@@ -195,32 +196,49 @@ public:
nsINode* GetCommonAncestorContainer(ErrorResult& aRv) const;
nsINode* GetStartContainer(ErrorResult& aRv) const;
uint32_t GetStartOffset(ErrorResult& aRv) const;
nsINode* GetEndContainer(ErrorResult& aRv) const;
uint32_t GetEndOffset(ErrorResult& aRv) const;
void InsertNode(nsINode& aNode, ErrorResult& aErr);
bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
bool IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr);
+
+ // *JS() methods are mapped to Range.*() of DOM.
+ // They may move focus only when the range represents normal selection.
+ // These methods shouldn't be used from internal.
+ void CollapseJS(bool aToStart);
+ void SelectNodeJS(nsINode& aNode, ErrorResult& aErr);
+ void SelectNodeContentsJS(nsINode& aNode, ErrorResult& aErr);
+ void SetEndJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
+ void SetEndAfterJS(nsINode& aNode, ErrorResult& aErr);
+ void SetEndBeforeJS(nsINode& aNode, ErrorResult& aErr);
+ void SetStartJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
+ void SetStartAfterJS(nsINode& aNode, ErrorResult& aErr);
+ void SetStartBeforeJS(nsINode& aNode, ErrorResult& aErr);
+
+ void SurroundContents(nsINode& aNode, ErrorResult& aErr);
+ already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
+ bool aFlushLayout = true);
+ already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true,
+ bool aFlushLayout = true);
+ void GetClientRectsAndTexts(
+ mozilla::dom::ClientRectsAndTexts& aResult,
+ ErrorResult& aErr);
+
+ // Following methods should be used for internal use instead of *JS().
void SelectNode(nsINode& aNode, ErrorResult& aErr);
void SelectNodeContents(nsINode& aNode, ErrorResult& aErr);
void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
void SetEndAfter(nsINode& aNode, ErrorResult& aErr);
void SetEndBefore(nsINode& aNode, ErrorResult& aErr);
void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr);
void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
- void SurroundContents(nsINode& aNode, ErrorResult& aErr);
- already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
- bool aFlushLayout = true);
- already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true,
- bool aFlushLayout = true);
- void GetClientRectsAndTexts(
- mozilla::dom::ClientRectsAndTexts& aResult,
- ErrorResult& aErr);
+
static void GetInnerTextNoFlush(mozilla::dom::DOMString& aValue,
mozilla::ErrorResult& aError,
nsIContent* aStartParent,
uint32_t aStartOffset,
nsIContent* aEndParent,
uint32_t aEndOffset);
nsINode* GetParentObject() const { return mOwner; }
@@ -318,16 +336,41 @@ protected:
// Helper to IsNodeSelected.
static bool IsNodeInSortedRanges(nsINode* aNode,
uint32_t aStartOffset,
uint32_t aEndOffset,
const nsTArray<const nsRange*>& aRanges,
size_t aRangeStart,
size_t aRangeEnd);
+ // Assume that this is guaranteed that this is held by the caller when
+ // this is used. (Note that we cannot use AutoRestore for mCalledByJS
+ // due to a bit field.)
+ class MOZ_RAII AutoCalledByJSSetter final
+ {
+ private:
+ nsRange& mRange;
+ bool mOldValue;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+ public:
+ explicit AutoCalledByJSSetter(nsRange& aRange
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : mRange(aRange)
+ , mOldValue(aRange.mCalledByJS)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ mRange.mCalledByJS = true;
+ }
+ ~AutoCalledByJSSetter()
+ {
+ mRange.mCalledByJS = mOldValue;
+ }
+ };
+
struct MOZ_STACK_CLASS AutoInvalidateSelection
{
explicit AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
{
#ifdef DEBUG
mWasInSelection = mRange->IsInSelection();
#endif
if (!mRange->IsInSelection() || mIsNested) {
@@ -354,16 +397,17 @@ protected:
int32_t mEndOffset;
bool mIsPositioned : 1;
bool mMaySpanAnonymousSubtrees : 1;
bool mIsGenerated : 1;
bool mStartOffsetWasIncremented : 1;
bool mEndOffsetWasIncremented : 1;
bool mEnableGravitationOnElementRemoval : 1;
+ bool mCalledByJS : 1;
#ifdef DEBUG
int32_t mAssertNextInsertOrAppendIndex;
nsINode* mAssertNextInsertOrAppendNode;
#endif
};
inline nsISupports*
ToCanonicalSupports(nsRange* aRange)
--- a/dom/webidl/Range.webidl
+++ b/dom/webidl/Range.webidl
@@ -21,32 +21,33 @@ interface Range {
[Throws]
readonly attribute Node endContainer;
[Throws]
readonly attribute unsigned long endOffset;
readonly attribute boolean collapsed;
[Throws]
readonly attribute Node commonAncestorContainer;
- [Throws]
+ [Throws, BinaryName="setStartJS"]
void setStart(Node refNode, unsigned long offset);
- [Throws]
+ [Throws, BinaryName="setEndJS"]
void setEnd(Node refNode, unsigned long offset);
- [Throws]
+ [Throws, BinaryName="setStartBeforeJS"]
void setStartBefore(Node refNode);
- [Throws]
+ [Throws, BinaryName="setStartAfterJS"]
void setStartAfter(Node refNode);
- [Throws]
+ [Throws, BinaryName="setEndBeforeJS"]
void setEndBefore(Node refNode);
- [Throws]
+ [Throws, BinaryName="setEndAfterJS"]
void setEndAfter(Node refNode);
+ [BinaryName="collapseJS"]
void collapse(optional boolean toStart = false);
- [Throws]
+ [Throws, BinaryName="selectNodeJS"]
void selectNode(Node refNode);
- [Throws]
+ [Throws, BinaryName="selectNodeContentsJS"]
void selectNodeContents(Node refNode);
const unsigned short START_TO_START = 0;
const unsigned short START_TO_END = 1;
const unsigned short END_TO_END = 2;
const unsigned short END_TO_START = 3;
[Throws]
short compareBoundaryPoints(unsigned short how, Range sourceRange);
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -12,45 +12,45 @@
interface Selection {
readonly attribute Node? anchorNode;
readonly attribute unsigned long anchorOffset;
readonly attribute Node? focusNode;
readonly attribute unsigned long focusOffset;
readonly attribute boolean isCollapsed;
- [Throws]
+ [Throws, BinaryName="collapseJS"]
void collapse(Node node, unsigned long offset);
- [Throws]
+ [Throws, BinaryName="collapseToStartJS"]
void collapseToStart();
- [Throws]
+ [Throws, BinaryName="collapseToEndJS"]
void collapseToEnd();
- [Throws]
+ [Throws, BinaryName="extendJS"]
void extend(Node node, unsigned long offset);
- [Throws]
+ [Throws, BinaryName="selectAllChildrenJS"]
void selectAllChildren(Node node);
[Throws]
void deleteFromDocument();
readonly attribute unsigned long rangeCount;
[Throws]
Range getRangeAt(unsigned long index);
- [Throws]
+ [Throws, BinaryName="addRangeJS"]
void addRange(Range range);
[Throws]
void removeRange(Range range);
[Throws]
void removeAllRanges();
[Throws]
boolean containsNode(Node node, boolean allowPartialContainment);
- [Throws]
+ [Throws, BinaryName="setBaseAndExtentJS"]
void setBaseAndExtent(Node anchorNode,
unsigned long anchorOffset,
Node focusNode,
unsigned long focusOffset);
stringifier;
};
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -162,31 +162,38 @@ public:
// WebIDL methods
nsINode* GetAnchorNode();
uint32_t AnchorOffset();
nsINode* GetFocusNode();
uint32_t FocusOffset();
bool IsCollapsed() const;
- void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
- void CollapseToStart(mozilla::ErrorResult& aRv);
- void CollapseToEnd(mozilla::ErrorResult& aRv);
- void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
+ // *JS() methods are mapped to Selection.*().
+ // They may move focus only when the range represents normal selection.
+ // These methods shouldn't be used by non-JS callers.
+ void CollapseJS(nsINode& aNode, uint32_t aOffset,
+ mozilla::ErrorResult& aRv);
+ void CollapseToStartJS(mozilla::ErrorResult& aRv);
+ void CollapseToEndJS(mozilla::ErrorResult& aRv);
- void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
+ void ExtendJS(nsINode& aNode, uint32_t aOffset,
+ mozilla::ErrorResult& aRv);
+
+ void SelectAllChildrenJS(nsINode& aNode, mozilla::ErrorResult& aRv);
+
void DeleteFromDocument(mozilla::ErrorResult& aRv);
uint32_t RangeCount() const
{
return mRanges.Length();
}
nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv);
- void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv);
+ void AddRangeJS(nsRange& aRange, mozilla::ErrorResult& aRv);
void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv);
void RemoveAllRanges(mozilla::ErrorResult& aRv);
void Stringify(nsAString& aResult);
bool ContainsNode(nsINode& aNode, bool aPartlyContained, mozilla::ErrorResult& aRv);
/**
@@ -196,19 +203,19 @@ public:
* in any one of them.
* @param aPoint The point to check, relative to the root frame.
*/
bool ContainsPoint(const nsPoint& aPoint);
void Modify(const nsAString& aAlter, const nsAString& aDirection,
const nsAString& aGranularity, mozilla::ErrorResult& aRv);
- void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
- nsINode& aFocusNode, uint32_t aFocusOffset,
- mozilla::ErrorResult& aRv);
+ void SetBaseAndExtentJS(nsINode& aAnchorNode, uint32_t aAnchorOffset,
+ nsINode& aFocusNode, uint32_t aFocusOffset,
+ mozilla::ErrorResult& aRv);
bool GetInterlinePosition(mozilla::ErrorResult& aRv);
void SetInterlinePosition(bool aValue, mozilla::ErrorResult& aRv);
Nullable<int16_t> GetCaretBidiLevel(mozilla::ErrorResult& aRv) const;
void SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv);
void ToStringWithFormat(const nsAString& aFormatType,
@@ -232,16 +239,27 @@ public:
bool aAllowAdjacent,
nsTArray<RefPtr<nsRange>>& aReturn,
mozilla::ErrorResult& aRv);
void ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
int16_t aVPercent, int16_t aHPercent,
mozilla::ErrorResult& aRv);
+ // Non-JS callers should use the following methods.
+ void Collapse(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
+ void CollapseToStart(mozilla::ErrorResult& aRv);
+ void CollapseToEnd(mozilla::ErrorResult& aRv);
+ void Extend(nsINode& aNode, uint32_t aOffset, mozilla::ErrorResult& aRv);
+ void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv);
+ void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
+ void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
+ nsINode& aFocusNode, uint32_t aFocusOffset,
+ mozilla::ErrorResult& aRv);
+
void AddSelectionChangeBlocker();
void RemoveSelectionChangeBlocker();
bool IsBlockingSelectionChangeEvents() const;
private:
friend class ::nsAutoScrollTimer;
// Note: DoAutoScroll might destroy arbitrary frames etc.
nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint);
@@ -254,17 +272,18 @@ private:
public:
SelectionType GetType() const { return mSelectionType; }
void SetType(SelectionType aSelectionType)
{
mSelectionType = aSelectionType;
}
- nsresult NotifySelectionListeners();
+ nsresult NotifySelectionListeners(bool aCalledByJS);
+ nsresult NotifySelectionListeners();
friend struct AutoUserInitiated;
struct MOZ_RAII AutoUserInitiated
{
explicit AutoUserInitiated(Selection* aSelection
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mSavedValue(aSelection->mUserInitiated)
{
@@ -360,16 +379,22 @@ private:
SelectionType mSelectionType;
/**
* True if the current selection operation was initiated by user action.
* It determines whether we exclude -moz-user-select:none nodes or not,
* as well as whether selectstart events will be fired.
*/
bool mUserInitiated;
+ /**
+ * When the selection change is caused by a call of Selection API,
+ * mCalledByJS is true. Otherwise, false.
+ */
+ bool mCalledByJS;
+
// 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.
class MOZ_STACK_CLASS SelectionBatcher final
{
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -6,16 +6,17 @@
/*
* Implementation of selection: nsISelection,nsISelectionPrivate and nsFrameSelection
*/
#include "mozilla/dom/Selection.h"
#include "mozilla/Attributes.h"
+#include "mozilla/AutoRestore.h"
#include "mozilla/EventStates.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsFrameSelection.h"
#include "nsISelectionListener.h"
#include "nsContentCID.h"
#include "nsDeviceContext.h"
@@ -3474,26 +3475,28 @@ nsFrameSelection::DisconnectFromPresShel
// note: this can return a nil anchor node
Selection::Selection()
: mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mSelectionType(SelectionType::eNormal)
, mUserInitiated(false)
+ , mCalledByJS(false)
, mSelectionChangeBlockerCount(0)
{
}
Selection::Selection(nsFrameSelection* aList)
: mFrameSelection(aList)
, mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mSelectionType(SelectionType::eNormal)
, mUserInitiated(false)
+ , mCalledByJS(false)
, mSelectionChangeBlockerCount(0)
{
}
Selection::~Selection()
{
setAnchorFocusRange(-1);
@@ -4957,16 +4960,24 @@ Selection::AddRange(nsIDOMRange* aDOMRan
}
nsRange* range = static_cast<nsRange*>(aDOMRange);
ErrorResult result;
AddRange(*range, result);
return result.StealNSResult();
}
void
+Selection::AddRangeJS(nsRange& aRange, ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ AddRange(aRange, aRv);
+}
+
+void
Selection::AddRange(nsRange& aRange, ErrorResult& aRv)
{
return AddRangeInternal(aRange, GetParentObject(), aRv);
}
void
Selection::AddRangeInternal(nsRange& aRange, nsIDocument* aDocument,
ErrorResult& aRv)
@@ -5128,16 +5139,24 @@ Selection::Collapse(nsIDOMNode* aParentN
}
NS_IMETHODIMP
Selection::CollapseNative(nsINode* aParentNode, int32_t aOffset)
{
return Collapse(aParentNode, aOffset);
}
+void
+Selection::CollapseJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ Collapse(aNode, aOffset, aRv);
+}
+
nsresult
Selection::Collapse(nsINode* aParentNode, int32_t aOffset)
{
if (!aParentNode)
return NS_ERROR_INVALID_ARG;
ErrorResult result;
Collapse(*aParentNode, static_cast<uint32_t>(aOffset), result);
@@ -5233,16 +5252,24 @@ NS_IMETHODIMP
Selection::CollapseToStart()
{
ErrorResult result;
CollapseToStart(result);
return result.StealNSResult();
}
void
+Selection::CollapseToStartJS(ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ CollapseToStart(aRv);
+}
+
+void
Selection::CollapseToStart(ErrorResult& aRv)
{
int32_t cnt;
nsresult rv = GetRangeCount(&cnt);
if (NS_FAILED(rv) || cnt <= 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@@ -5274,16 +5301,24 @@ NS_IMETHODIMP
Selection::CollapseToEnd()
{
ErrorResult result;
CollapseToEnd(result);
return result.StealNSResult();
}
void
+Selection::CollapseToEndJS(ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ CollapseToEnd(aRv);
+}
+
+void
Selection::CollapseToEnd(ErrorResult& aRv)
{
int32_t cnt;
nsresult rv = GetRangeCount(&cnt);
if (NS_FAILED(rv) || cnt <= 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
@@ -5475,16 +5510,24 @@ Selection::Extend(nsIDOMNode* aParentNod
}
NS_IMETHODIMP
Selection::ExtendNative(nsINode* aParentNode, int32_t aOffset)
{
return Extend(aParentNode, aOffset);
}
+void
+Selection::ExtendJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ Extend(aNode, aOffset, aRv);
+}
+
nsresult
Selection::Extend(nsINode* aParentNode, int32_t aOffset)
{
if (!aParentNode)
return NS_ERROR_INVALID_ARG;
ErrorResult result;
Extend(*aParentNode, static_cast<uint32_t>(aOffset), result);
@@ -5787,16 +5830,24 @@ Selection::SelectAllChildren(nsIDOMNode*
ErrorResult result;
nsCOMPtr<nsINode> node = do_QueryInterface(aParentNode);
NS_ENSURE_TRUE(node, NS_ERROR_INVALID_ARG);
SelectAllChildren(*node, result);
return result.StealNSResult();
}
void
+Selection::SelectAllChildrenJS(nsINode& aNode, ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ SelectAllChildren(aNode, aRv);
+}
+
+void
Selection::SelectAllChildren(nsINode& aNode, ErrorResult& aRv)
{
if (mFrameSelection) {
mFrameSelection->PostReason(nsISelectionListener::SELECTALL_REASON);
}
SelectionBatcher batch(this);
Collapse(aNode, 0, aRv);
@@ -6239,16 +6290,24 @@ Selection::RemoveSelectionListener(nsISe
{
bool result = mSelectionListeners.RemoveObject(aListenerToRemove); // Releases
if (!result) {
aRv.Throw(NS_ERROR_FAILURE);
}
}
nsresult
+Selection::NotifySelectionListeners(bool aCalledByJS)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = aCalledByJS;
+ return NotifySelectionListeners();
+}
+
+nsresult
Selection::NotifySelectionListeners()
{
if (!mFrameSelection)
return NS_OK;//nothing to do
if (mFrameSelection->GetBatching()) {
mFrameSelection->SetDirty();
return NS_OK;
@@ -6449,16 +6508,29 @@ Selection::Modify(const nsAString& aAlte
do_QueryInterface(mFrameSelection->GetShell());
if (!shell)
return;
shell->CompleteMove(forward, extend);
}
}
void
+Selection::SetBaseAndExtentJS(nsINode& aAnchorNode,
+ uint32_t aAnchorOffset,
+ nsINode& aFocusNode,
+ uint32_t aFocusOffset,
+ ErrorResult& aRv)
+{
+ AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
+ mCalledByJS = true;
+ SetBaseAndExtent(aAnchorNode, aAnchorOffset,
+ aFocusNode, aFocusOffset, aRv);
+}
+
+void
Selection::SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
nsINode& aFocusNode, uint32_t aFocusOffset,
ErrorResult& aRv)
{
if (!mFrameSelection) {
return;
}