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:
Masayuki Nakano 2017-06-26 17:26:27 +09:00
parent acde25fb18
commit e3529fd155
9 changed files with 242 additions and 52 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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)
{

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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);