2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* 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/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Implementation of the DOM nsIDOMRange object.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef nsRange_h___
|
|
|
|
#define nsRange_h___
|
|
|
|
|
|
|
|
#include "nsIDOMRange.h"
|
|
|
|
#include "nsCOMPtr.h"
|
2012-07-01 16:45:59 -07:00
|
|
|
#include "nsINode.h"
|
2013-02-07 04:09:41 -08:00
|
|
|
#include "nsIDocument.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
#include "prmon.h"
|
|
|
|
#include "nsStubMutationObserver.h"
|
2013-02-07 04:09:41 -08:00
|
|
|
#include "nsWrapperCache.h"
|
|
|
|
#include "mozilla/Attributes.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-03-17 00:55:17 -07:00
|
|
|
class nsClientRect;
|
2013-02-07 04:09:41 -08:00
|
|
|
class nsClientRectList;
|
|
|
|
class nsIDOMDocumentFragment;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
class ErrorResult;
|
|
|
|
namespace dom {
|
|
|
|
class DocumentFragment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class nsRange MOZ_FINAL : public nsIDOMRange,
|
|
|
|
public nsStubMutationObserver,
|
|
|
|
public nsWrapperCache
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-02-07 04:09:41 -08:00
|
|
|
typedef mozilla::ErrorResult ErrorResult;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
public:
|
2013-02-07 04:09:41 -08:00
|
|
|
nsRange(nsINode* aNode)
|
2012-07-30 07:20:58 -07:00
|
|
|
: mRoot(nullptr)
|
2012-01-10 06:19:54 -08:00
|
|
|
, mStartOffset(0)
|
|
|
|
, mEndOffset(0)
|
|
|
|
, mIsPositioned(false)
|
|
|
|
, mIsDetached(false)
|
|
|
|
, mMaySpanAnonymousSubtrees(false)
|
|
|
|
, mInSelection(false)
|
2012-11-20 12:14:15 -08:00
|
|
|
, mStartOffsetWasIncremented(false)
|
|
|
|
, mEndOffsetWasIncremented(false)
|
|
|
|
#ifdef DEBUG
|
|
|
|
, mAssertNextInsertOrAppendIndex(-1)
|
|
|
|
, mAssertNextInsertOrAppendNode(nullptr)
|
|
|
|
#endif
|
2013-02-07 04:09:41 -08:00
|
|
|
{
|
|
|
|
SetIsDOMBinding();
|
|
|
|
MOZ_ASSERT(aNode, "range isn't in a document!");
|
|
|
|
mOwner = aNode->OwnerDoc();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
virtual ~nsRange();
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
|
|
|
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
2012-01-15 00:13:12 -08:00
|
|
|
nsRange** aRange);
|
2012-08-22 08:56:38 -07:00
|
|
|
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
|
|
|
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
2012-01-15 00:13:12 -08:00
|
|
|
nsIDOMRange** aRange);
|
2013-04-16 14:12:03 -07:00
|
|
|
static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
|
|
|
nsINode* aEndParent, int32_t aEndOffset,
|
|
|
|
nsRange** aRange);
|
2012-01-15 00:13:12 -08:00
|
|
|
|
2008-12-03 02:03:10 -08:00
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
2013-02-07 04:09:41 -08:00
|
|
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// nsIDOMRange interface
|
|
|
|
NS_DECL_NSIDOMRANGE
|
|
|
|
|
2012-01-10 06:19:54 -08:00
|
|
|
nsINode* GetRoot() const
|
|
|
|
{
|
|
|
|
return mRoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINode* GetStartParent() const
|
|
|
|
{
|
|
|
|
return mStartParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINode* GetEndParent() const
|
|
|
|
{
|
|
|
|
return mEndParent;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t StartOffset() const
|
2012-01-10 06:19:54 -08:00
|
|
|
{
|
|
|
|
return mStartOffset;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t EndOffset() const
|
2012-01-10 06:19:54 -08:00
|
|
|
{
|
|
|
|
return mEndOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsPositioned() const
|
|
|
|
{
|
|
|
|
return mIsPositioned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees)
|
|
|
|
{
|
|
|
|
mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true iff this range is part of at least one Selection object
|
|
|
|
* and isn't detached.
|
|
|
|
*/
|
|
|
|
bool IsInSelection() const
|
|
|
|
{
|
|
|
|
return mInSelection;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the range is added/removed from a Selection.
|
|
|
|
*/
|
|
|
|
void SetInSelection(bool aInSelection)
|
|
|
|
{
|
2012-04-25 05:03:48 -07:00
|
|
|
if (mInSelection == aInSelection) {
|
2012-01-10 06:19:54 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
mInSelection = aInSelection;
|
|
|
|
nsINode* commonAncestor = GetCommonAncestor();
|
|
|
|
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
|
|
|
|
if (mInSelection) {
|
|
|
|
RegisterCommonAncestor(commonAncestor);
|
|
|
|
} else {
|
|
|
|
UnregisterCommonAncestor(commonAncestor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsINode* GetCommonAncestor() const;
|
|
|
|
void Reset();
|
2012-08-22 08:56:38 -07:00
|
|
|
nsresult SetStart(nsINode* aParent, int32_t aOffset);
|
|
|
|
nsresult SetEnd(nsINode* aParent, int32_t aOffset);
|
2012-06-25 04:44:11 -07:00
|
|
|
already_AddRefed<nsRange> CloneRange() const;
|
2010-07-21 15:05:17 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
|
|
|
|
nsINode* aEndParent, int32_t aEndOffset)
|
2011-11-03 22:32:09 -07:00
|
|
|
{
|
|
|
|
// If this starts being hot, we may be able to optimize this a bit,
|
|
|
|
// but for now just set start and end separately.
|
|
|
|
nsresult rv = SetStart(aStartParent, aStartOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return SetEnd(aEndParent, aEndOffset);
|
|
|
|
}
|
|
|
|
|
2011-06-15 23:31:36 -07:00
|
|
|
NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// nsIMutationObserver methods
|
2010-07-21 15:05:17 -07:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
|
2011-12-20 01:15:41 -08:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-02-07 04:09:41 -08:00
|
|
|
// WebIDL
|
2013-05-21 11:33:28 -07:00
|
|
|
static already_AddRefed<nsRange>
|
|
|
|
Constructor(const mozilla::dom::GlobalObject& global,
|
|
|
|
mozilla::ErrorResult& aRv);
|
|
|
|
|
2013-02-07 04:09:41 -08:00
|
|
|
bool Collapsed() const
|
|
|
|
{
|
|
|
|
return mIsPositioned && mStartParent == mEndParent &&
|
|
|
|
mStartOffset == mEndOffset;
|
|
|
|
}
|
|
|
|
already_AddRefed<mozilla::dom::DocumentFragment>
|
|
|
|
CreateContextualFragment(const nsAString& aString, ErrorResult& aError);
|
|
|
|
already_AddRefed<mozilla::dom::DocumentFragment>
|
|
|
|
CloneContents(ErrorResult& aErr);
|
|
|
|
int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther,
|
|
|
|
ErrorResult& aErr);
|
|
|
|
int16_t ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr);
|
|
|
|
void DeleteContents(ErrorResult& aRv);
|
|
|
|
already_AddRefed<mozilla::dom::DocumentFragment>
|
|
|
|
ExtractContents(ErrorResult& aErr);
|
|
|
|
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);
|
|
|
|
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);
|
2013-03-17 00:55:17 -07:00
|
|
|
already_AddRefed<nsClientRect> GetBoundingClientRect();
|
2013-03-17 00:55:16 -07:00
|
|
|
already_AddRefed<nsClientRectList> GetClientRects();
|
2013-02-07 04:09:41 -08:00
|
|
|
|
|
|
|
nsINode* GetParentObject() const { return mOwner; }
|
2013-04-25 09:29:54 -07:00
|
|
|
virtual JSObject* WrapObject(JSContext* cx,
|
|
|
|
JS::Handle<JSObject*> scope) MOZ_OVERRIDE MOZ_FINAL;
|
2013-02-07 04:09:41 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
private:
|
|
|
|
// no copy's or assigns
|
|
|
|
nsRange(const nsRange&);
|
|
|
|
nsRange& operator=(const nsRange&);
|
2007-06-18 20:01:03 -07:00
|
|
|
|
2008-07-25 03:37:37 -07:00
|
|
|
/**
|
|
|
|
* Cut or delete the range's contents.
|
|
|
|
*
|
|
|
|
* @param aFragment nsIDOMDocumentFragment containing the nodes.
|
|
|
|
* May be null to indicate the caller doesn't want a fragment.
|
|
|
|
*/
|
2013-02-07 04:09:41 -08:00
|
|
|
nsresult CutContents(mozilla::dom::DocumentFragment** frag);
|
2008-07-25 03:37:37 -07:00
|
|
|
|
2008-10-11 12:46:05 -07:00
|
|
|
static nsresult CloneParentsBetween(nsIDOMNode *aAncestor,
|
|
|
|
nsIDOMNode *aNode,
|
|
|
|
nsIDOMNode **aClosestAncestor,
|
|
|
|
nsIDOMNode **aFarthestAncestor);
|
2008-07-25 03:37:37 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
public:
|
|
|
|
/******************************************************************************
|
|
|
|
* Utility routine to detect if a content node starts before a range and/or
|
|
|
|
* ends after a range. If neither it is contained inside the range.
|
|
|
|
*
|
|
|
|
* XXX - callers responsibility to ensure node in same doc as range!
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
2012-01-10 06:19:54 -08:00
|
|
|
static nsresult CompareNodeToRange(nsINode* aNode, nsRange* aRange,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool *outNodeBefore,
|
|
|
|
bool *outNodeAfter);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
|
|
|
|
uint32_t aEndOffset);
|
2011-12-20 01:15:41 -08:00
|
|
|
|
2012-01-10 06:19:54 -08:00
|
|
|
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
|
2007-03-22 10:30:00 -07:00
|
|
|
protected:
|
2012-01-10 06:19:54 -08:00
|
|
|
void RegisterCommonAncestor(nsINode* aNode);
|
|
|
|
void UnregisterCommonAncestor(nsINode* aNode);
|
|
|
|
nsINode* IsValidBoundary(nsINode* aNode);
|
|
|
|
|
2011-12-20 01:15:41 -08:00
|
|
|
// CharacterDataChanged set aNotInsertedYet to true to disable an assertion
|
|
|
|
// and suppress re-registering a range common ancestor node since
|
|
|
|
// the new text node of a splitText hasn't been inserted yet.
|
|
|
|
// CharacterDataChanged does the re-registering when needed.
|
2012-08-22 08:56:38 -07:00
|
|
|
void DoSetRange(nsINode* aStartN, int32_t aStartOffset,
|
|
|
|
nsINode* aEndN, int32_t aEndOffset,
|
2011-12-20 01:15:41 -08:00
|
|
|
nsINode* aRoot, bool aNotInsertedYet = false);
|
2011-12-24 05:26:03 -08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* For a range for which IsInSelection() is true, return the common
|
|
|
|
* ancestor for the range. This method uses the selection bits and
|
|
|
|
* nsGkAtoms::range property on the nodes to quickly find the ancestor.
|
|
|
|
* That is, it's a faster version of GetCommonAncestor that only works
|
|
|
|
* for ranges in a Selection. The method will assert and the behavior
|
|
|
|
* is undefined if called on a range where IsInSelection() is false.
|
|
|
|
*/
|
|
|
|
nsINode* GetRegisteredCommonAncestor();
|
|
|
|
|
2013-04-11 20:20:09 -07:00
|
|
|
struct MOZ_STACK_CLASS AutoInvalidateSelection
|
2011-12-24 05:26:03 -08:00
|
|
|
{
|
|
|
|
AutoInvalidateSelection(nsRange* aRange) : mRange(aRange)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
mWasInSelection = mRange->IsInSelection();
|
|
|
|
#endif
|
|
|
|
if (!mRange->IsInSelection() || mIsNested) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mIsNested = true;
|
|
|
|
mCommonAncestor = mRange->GetRegisteredCommonAncestor();
|
|
|
|
}
|
|
|
|
~AutoInvalidateSelection();
|
|
|
|
nsRange* mRange;
|
|
|
|
nsRefPtr<nsINode> mCommonAncestor;
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool mWasInSelection;
|
|
|
|
#endif
|
|
|
|
static bool mIsNested;
|
|
|
|
};
|
2013-02-07 04:09:41 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> mOwner;
|
2012-01-10 06:19:54 -08:00
|
|
|
nsCOMPtr<nsINode> mRoot;
|
|
|
|
nsCOMPtr<nsINode> mStartParent;
|
|
|
|
nsCOMPtr<nsINode> mEndParent;
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t mStartOffset;
|
|
|
|
int32_t mEndOffset;
|
2012-01-10 06:19:54 -08:00
|
|
|
|
|
|
|
bool mIsPositioned;
|
|
|
|
bool mIsDetached;
|
|
|
|
bool mMaySpanAnonymousSubtrees;
|
|
|
|
bool mInSelection;
|
2012-11-20 12:14:15 -08:00
|
|
|
bool mStartOffsetWasIncremented;
|
|
|
|
bool mEndOffsetWasIncremented;
|
|
|
|
#ifdef DEBUG
|
|
|
|
int32_t mAssertNextInsertOrAppendIndex;
|
|
|
|
nsINode* mAssertNextInsertOrAppendNode;
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
2012-12-22 00:27:27 -08:00
|
|
|
inline nsISupports*
|
|
|
|
ToCanonicalSupports(nsRange* aRange)
|
|
|
|
{
|
|
|
|
return static_cast<nsIDOMRange*>(aRange);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline nsISupports*
|
|
|
|
ToSupports(nsRange* aRange)
|
|
|
|
{
|
|
|
|
return static_cast<nsIDOMRange*>(aRange);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif /* nsRange_h___ */
|