зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1375502 - part2: Add nsIContentIterator::Init(nsINode*, uint32_t, nsINode*, uint32_t) r=mats
nsIContentIterator::Init() takes nsRange but it's too expensive for some users. So, there should be another Init() which can be specified a range in DOM tree with 2 pairs of nsINode* and uint32_t. MozReview-Commit-ID: 6JXic0KOM2d --HG-- extra : rebase_source : 28ff355a2aa0dcb5d65495806ef8c67f1da642ea
This commit is contained in:
Родитель
acde25fb18
Коммит
e3529fd155
|
@ -113,6 +113,9 @@ public:
|
|||
|
||||
virtual nsresult Init(nsIDOMRange* aRange) override;
|
||||
|
||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset) override;
|
||||
|
||||
virtual void First() override;
|
||||
|
||||
virtual void Last() override;
|
||||
|
@ -130,6 +133,15 @@ public:
|
|||
protected:
|
||||
virtual ~nsContentIterator();
|
||||
|
||||
/**
|
||||
* Callers must guarantee that:
|
||||
* - Neither aStartContainer nor aEndContainer is nullptr.
|
||||
* - aStartOffset and aEndOffset are valid for its container.
|
||||
* - The start point and the end point are in document order.
|
||||
*/
|
||||
nsresult InitInternal(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset);
|
||||
|
||||
// Recursively get the deepest first/last child of aRoot. This will return
|
||||
// aRoot itself if it has no children.
|
||||
nsINode* GetDeepFirstChild(nsINode* aRoot,
|
||||
|
@ -300,35 +312,48 @@ nsContentIterator::Init(nsINode* aRoot)
|
|||
nsresult
|
||||
nsContentIterator::Init(nsIDOMRange* aDOMRange)
|
||||
{
|
||||
mIsDone = false;
|
||||
|
||||
if (NS_WARN_IF(!aDOMRange)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsRange* range = static_cast<nsRange*>(aDOMRange);
|
||||
|
||||
nsRange* range = static_cast<nsRange*>(aDOMRange);
|
||||
if (NS_WARN_IF(!range->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return InitInternal(range->GetStartContainer(), range->StartOffset(),
|
||||
range->GetEndContainer(), range->EndOffset());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentIterator::Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset)
|
||||
{
|
||||
mIsDone = false;
|
||||
|
||||
if (NS_WARN_IF(!nsRange::IsValidPoints(aStartContainer, aStartOffset,
|
||||
aEndContainer, aEndOffset))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return InitInternal(aStartContainer, aStartOffset,
|
||||
aEndContainer, aEndOffset);
|
||||
}
|
||||
|
||||
// XXX Argument names will be replaced in the following patch.
|
||||
nsresult
|
||||
nsContentIterator::InitInternal(nsINode* startNode, uint32_t startIndx,
|
||||
nsINode* endNode, uint32_t endIndx)
|
||||
{
|
||||
// get common content parent
|
||||
mCommonParent = range->GetCommonAncestor();
|
||||
mCommonParent =
|
||||
nsContentUtils::GetCommonAncestor(startNode, endNode);
|
||||
if (NS_WARN_IF(!mCommonParent)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// get the start node and offset
|
||||
int32_t startIndx = range->StartOffset();
|
||||
NS_WARNING_ASSERTION(startIndx >= 0, "bad startIndx");
|
||||
nsINode* startNode = range->GetStartContainer();
|
||||
if (NS_WARN_IF(!startNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// get the end node and offset
|
||||
int32_t endIndx = range->EndOffset();
|
||||
NS_WARNING_ASSERTION(endIndx >= 0, "bad endIndx");
|
||||
nsINode* endNode = range->GetEndContainer();
|
||||
if (NS_WARN_IF(!endNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool startIsData = startNode->IsNodeOfType(nsINode::eDATA_NODE);
|
||||
|
||||
// short circuit when start node == end node
|
||||
|
@ -1218,6 +1243,9 @@ public:
|
|||
|
||||
virtual nsresult Init(nsIDOMRange* aRange) override;
|
||||
|
||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset) override;
|
||||
|
||||
virtual void Next() override;
|
||||
|
||||
virtual void Prev() override;
|
||||
|
@ -1233,6 +1261,11 @@ public:
|
|||
protected:
|
||||
virtual ~nsContentSubtreeIterator() {}
|
||||
|
||||
/**
|
||||
* Callers must guarantee that mRange isn't nullptr and is positioned.
|
||||
*/
|
||||
nsresult InitWithRange();
|
||||
|
||||
// Returns the highest inclusive ancestor of aNode that's in the range
|
||||
// (possibly aNode itself). Returns null if aNode is null, or is not itself
|
||||
// in the range. A node is in the range if (node, 0) comes strictly after
|
||||
|
@ -1301,7 +1334,48 @@ nsContentSubtreeIterator::Init(nsIDOMRange* aRange)
|
|||
|
||||
mIsDone = false;
|
||||
|
||||
mRange = static_cast<nsRange*>(aRange);
|
||||
nsRange* range = static_cast<nsRange*>(aRange);
|
||||
if (NS_WARN_IF(!range->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mRange = range;
|
||||
|
||||
return InitWithRange();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSubtreeIterator::Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset)
|
||||
{
|
||||
mIsDone = false;
|
||||
|
||||
RefPtr<nsRange> range;
|
||||
nsresult rv = nsRange::CreateRange(aStartContainer, aStartOffset,
|
||||
aEndContainer, aEndOffset,
|
||||
getter_AddRefs(range));
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
|
||||
NS_WARN_IF(!range->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(range->GetStartContainer() != aStartContainer) ||
|
||||
NS_WARN_IF(range->GetEndContainer() != aEndContainer) ||
|
||||
NS_WARN_IF(range->StartOffset() != aStartOffset) ||
|
||||
NS_WARN_IF(range->EndOffset() != aEndOffset)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mRange = Move(range);
|
||||
|
||||
return InitWithRange();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSubtreeIterator::InitWithRange()
|
||||
{
|
||||
MOZ_ASSERT(mRange);
|
||||
MOZ_ASSERT(mRange->IsPositioned());
|
||||
|
||||
// get the start node and offset, convert to nsINode
|
||||
mCommonParent = mRange->GetCommonAncestor();
|
||||
|
|
|
@ -31,6 +31,14 @@ public:
|
|||
*/
|
||||
virtual nsresult Init(nsIDOMRange* aRange) = 0;
|
||||
|
||||
/* Initializes an iterator for the subtree between
|
||||
aStartContainer/aStartOffset and aEndContainer/aEndOffset
|
||||
Callers should guarantee that the start point and end point are in
|
||||
document order.
|
||||
*/
|
||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset) = 0;
|
||||
|
||||
/** First will reset the list.
|
||||
*/
|
||||
virtual void First() = 0;
|
||||
|
|
|
@ -1263,6 +1263,41 @@ nsRange::ComputeRootNode(nsINode* aNode, bool aMaySpanAnonymousSubtrees)
|
|||
return root;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsRange::IsValidPoints(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset)
|
||||
{
|
||||
// Use NS_WARN_IF() only for the cases where the arguments are unexpected.
|
||||
if (NS_WARN_IF(!aStartContainer) || NS_WARN_IF(!aEndContainer) ||
|
||||
NS_WARN_IF(!IsValidOffset(aStartContainer, aStartOffset)) ||
|
||||
NS_WARN_IF(!IsValidOffset(aEndContainer, aEndOffset))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, don't use NS_WARN_IF() for preventing to make console messy.
|
||||
// Instead, check one by one since it is easier to catch the error reason
|
||||
// with debugger.
|
||||
|
||||
if (ComputeRootNode(aStartContainer) != ComputeRootNode(aEndContainer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool disconnected = false;
|
||||
int32_t order =
|
||||
nsContentUtils::ComparePoints(aStartContainer,
|
||||
static_cast<int32_t>(aStartOffset),
|
||||
aEndContainer,
|
||||
static_cast<int32_t>(aEndOffset),
|
||||
&disconnected);
|
||||
// FYI: disconnected should be false unless |order| is 1.
|
||||
if (order == 1 || NS_WARN_IF(disconnected)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsRange::SetStartJS(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr)
|
||||
{
|
||||
|
|
|
@ -328,6 +328,13 @@ public:
|
|||
return ComputeRootNode(aNode, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if aStartContainer/aStartOffset and aEndContainer/aEndOffset
|
||||
* are valid start and end points for a range. Otherwise, return false.
|
||||
*/
|
||||
static bool IsValidPoints(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset);
|
||||
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
|
|
|
@ -200,15 +200,6 @@ ContentEventHandler::RawRange::SelectNodeContents(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsRange>
|
||||
ContentEventHandler::RawRange::CreateRange() const
|
||||
{
|
||||
RefPtr<nsRange> range = new nsRange(mRoot);
|
||||
range->SetStartAndEnd(mStartContainer, mStartOffset,
|
||||
mEndContainer, mEndOffset);
|
||||
return range.forget();
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* ContentEventHandler */
|
||||
/******************************************************************/
|
||||
|
@ -868,8 +859,9 @@ ContentEventHandler::GenerateFlatTextContent(const RawRange& aRawRange,
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> range = aRawRange.CreateRange();
|
||||
nsresult rv = iter->Init(range);
|
||||
nsresult rv =
|
||||
iter->Init(aRawRange.GetStartContainer(), aRawRange.StartOffset(),
|
||||
aRawRange.GetEndContainer(), aRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1040,8 +1032,9 @@ ContentEventHandler::GenerateFlatFontRanges(const RawRange& aRawRange,
|
|||
// baseOffset is the flattened offset of each content node.
|
||||
int32_t baseOffset = 0;
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> range = aRawRange.CreateRange();
|
||||
nsresult rv = iter->Init(range);
|
||||
nsresult rv =
|
||||
iter->Init(aRawRange.GetStartContainer(), aRawRange.StartOffset(),
|
||||
aRawRange.GetEndContainer(), aRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1664,8 +1657,13 @@ ContentEventHandler::GetFirstFrameInRangeForTextRect(const RawRange& aRawRange)
|
|||
{
|
||||
NodePosition nodePosition;
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> range = aRawRange.CreateRange();
|
||||
for (iter->Init(range); !iter->IsDone(); iter->Next()) {
|
||||
nsresult rv =
|
||||
iter->Init(aRawRange.GetStartContainer(), aRawRange.StartOffset(),
|
||||
aRawRange.GetEndContainer(), aRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return FrameAndNodeOffset();
|
||||
}
|
||||
for (; !iter->IsDone(); iter->Next()) {
|
||||
nsINode* node = iter->GetCurrentNode();
|
||||
if (NS_WARN_IF(!node)) {
|
||||
break;
|
||||
|
@ -1712,8 +1710,12 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange)
|
|||
{
|
||||
NodePosition nodePosition;
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> range = aRawRange.CreateRange();
|
||||
iter->Init(range);
|
||||
nsresult rv =
|
||||
iter->Init(aRawRange.GetStartContainer(), aRawRange.StartOffset(),
|
||||
aRawRange.GetEndContainer(), aRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return FrameAndNodeOffset();
|
||||
}
|
||||
|
||||
nsINode* endNode = aRawRange.GetEndContainer();
|
||||
uint32_t endOffset = aRawRange.EndOffset();
|
||||
|
@ -2321,8 +2323,11 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
|
|||
|
||||
// used to iterate over all contents and their frames
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
|
||||
RefPtr<nsRange> range = rawRange.CreateRange();
|
||||
iter->Init(range);
|
||||
rv = iter->Init(rawRange.GetStartContainer(), rawRange.StartOffset(),
|
||||
rawRange.GetEndContainer(), rawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Get the first frame which causes some text after the offset.
|
||||
FrameAndNodeOffset firstFrame = GetFirstFrameInRangeForTextRect(rawRange);
|
||||
|
@ -2946,8 +2951,9 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
|||
return rv;
|
||||
}
|
||||
iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> prevRange = prevRawRange.CreateRange();
|
||||
rv = iter->Init(prevRange);
|
||||
rv =
|
||||
iter->Init(prevRawRange.GetStartContainer(), prevRawRange.StartOffset(),
|
||||
prevRawRange.GetEndContainer(), prevRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2958,8 +2964,9 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
|||
return rv;
|
||||
}
|
||||
iter = NS_NewPreContentIterator();
|
||||
RefPtr<nsRange> prevRange = prevRawRange.CreateRange();
|
||||
rv = iter->Init(prevRange);
|
||||
rv =
|
||||
iter->Init(prevRawRange.GetStartContainer(), prevRawRange.StartOffset(),
|
||||
prevRawRange.GetEndContainer(), prevRawRange.EndOffset());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -86,8 +86,6 @@ private:
|
|||
|
||||
nsresult SelectNodeContents(nsINode* aNodeToSelectContents);
|
||||
|
||||
already_AddRefed<nsRange> CreateRange() const;
|
||||
|
||||
private:
|
||||
bool IsValidOffset(nsINode* aContainer, uint32_t aOffset) const;
|
||||
nsINode* IsValidBoundary(nsINode* aNode) const;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
|
@ -19,6 +20,8 @@
|
|||
#include "nsITextServicesFilter.h"
|
||||
#include "nsRange.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//------------------------------------------------------------
|
||||
nsFilteredContentIterator::nsFilteredContentIterator(nsITextServicesFilter* aFilter) :
|
||||
mFilter(aFilter),
|
||||
|
@ -78,17 +81,62 @@ nsFilteredContentIterator::Init(nsINode* aRoot)
|
|||
nsresult
|
||||
nsFilteredContentIterator::Init(nsIDOMRange* aRange)
|
||||
{
|
||||
NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_ARG_POINTER(aRange);
|
||||
mIsOutOfRange = false;
|
||||
mDirection = eForward;
|
||||
if (NS_WARN_IF(!aRange)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRange* range = static_cast<nsRange*>(aRange);
|
||||
if (NS_WARN_IF(!range->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mRange = range->CloneRange();
|
||||
|
||||
return InitWithRange();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
nsresult
|
||||
nsFilteredContentIterator::Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset)
|
||||
{
|
||||
RefPtr<nsRange> range;
|
||||
nsresult rv = nsRange::CreateRange(aStartContainer, aStartOffset,
|
||||
aEndContainer, aEndOffset,
|
||||
getter_AddRefs(range));
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!range) ||
|
||||
NS_WARN_IF(!range->IsPositioned())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(range->GetStartContainer() == aStartContainer);
|
||||
MOZ_ASSERT(range->GetEndContainer() == aEndContainer);
|
||||
MOZ_ASSERT(range->StartOffset() == aStartOffset);
|
||||
MOZ_ASSERT(range->EndOffset() == aEndOffset);
|
||||
|
||||
mRange = Move(range);
|
||||
|
||||
return InitWithRange();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFilteredContentIterator::InitWithRange()
|
||||
{
|
||||
MOZ_ASSERT(mRange);
|
||||
MOZ_ASSERT(mRange->IsPositioned());
|
||||
|
||||
if (NS_WARN_IF(!mPreIterator) || NS_WARN_IF(!mIterator)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mIsOutOfRange = false;
|
||||
mDirection = eForward;
|
||||
mCurrentIterator = mPreIterator;
|
||||
|
||||
mRange = static_cast<nsRange*>(aRange)->CloneRange();
|
||||
|
||||
nsresult rv = mPreIterator->Init(mRange);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return mIterator->Init(mRange);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
/* nsIContentIterator */
|
||||
virtual nsresult Init(nsINode* aRoot) override;
|
||||
virtual nsresult Init(nsIDOMRange* aRange) override;
|
||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset) override;
|
||||
virtual void First() override;
|
||||
virtual void Last() override;
|
||||
virtual void Next() override;
|
||||
|
@ -49,6 +51,11 @@ protected:
|
|||
|
||||
virtual ~nsFilteredContentIterator();
|
||||
|
||||
/**
|
||||
* Callers must guarantee that mRange isn't nullptr and it's positioned.
|
||||
*/
|
||||
nsresult InitWithRange();
|
||||
|
||||
// enum to give us the direction
|
||||
typedef enum {eDirNotSet, eForward, eBackward} eDirectionType;
|
||||
nsresult AdvanceNode(nsIDOMNode* aNode, nsIDOMNode*& aNewNode, eDirectionType aDir);
|
||||
|
|
|
@ -101,6 +101,12 @@ public:
|
|||
NS_NOTREACHED("internal error");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
|
||||
nsINode* aEndContainer, uint32_t aEndOffset) override
|
||||
{
|
||||
NS_NOTREACHED("internal error");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// Not a range because one of the endpoints may be anonymous.
|
||||
nsresult Init(nsIDOMNode* aStartNode, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndNode, int32_t aEndOffset);
|
||||
|
|
Загрузка…
Ссылка в новой задаче