Bug 1384915 - Part 4: Update RawRange to use RangeBoundaries, r=masayuki

This commit is contained in:
Michael Layzell 2017-09-08 14:07:00 -04:00
parent 74e8b70a80
commit 615d87dfaf
3 changed files with 83 additions and 86 deletions

View File

@ -85,11 +85,21 @@ public:
return mRoot;
}
const RangeBoundary& StartRef() const
{
return mStart;
}
nsINode* GetStartContainer() const
{
return mStart.Container();
}
const RangeBoundary& EndRef() const
{
return mEnd;
}
nsINode* GetEndContainer() const
{
return mEnd.Container();

View File

@ -47,69 +47,56 @@ void
ContentEventHandler::RawRange::AssertStartIsBeforeOrEqualToEnd()
{
MOZ_ASSERT(
nsContentUtils::ComparePoints(mStartContainer,
static_cast<int32_t>(mStartOffset),
mEndContainer,
static_cast<int32_t>(mEndOffset)) <= 0);
}
bool
ContentEventHandler::RawRange::IsValidOffset(nsINode* aContainer,
uint32_t aOffset) const
{
return aContainer && aOffset <= aContainer->Length();
nsContentUtils::ComparePoints(mStart.Container(),
static_cast<int32_t>(mStart.Offset()),
mEnd.Container(),
static_cast<int32_t>(mEnd.Offset())) <= 0);
}
nsresult
ContentEventHandler::RawRange::SetStart(nsINode* aStartContainer,
uint32_t aStartOffset)
ContentEventHandler::RawRange::SetStart(const RawRangeBoundary& aStart)
{
nsINode* newRoot = nsRange::ComputeRootNode(aStartContainer);
nsINode* newRoot = nsRange::ComputeRootNode(aStart.Container());
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
if (!IsValidOffset(aStartContainer, aStartOffset)) {
if (!aStart.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, or if positioned in another document.
if (!IsPositioned() || newRoot != mRoot) {
mRoot = newRoot;
mStartContainer = mEndContainer = aStartContainer;
mStartOffset = mEndOffset = aStartOffset;
mStart = mEnd = aStart;
return NS_OK;
}
mStartContainer = aStartContainer;
mStartOffset = aStartOffset;
mStart = aStart;
AssertStartIsBeforeOrEqualToEnd();
return NS_OK;
}
nsresult
ContentEventHandler::RawRange::SetEnd(nsINode* aEndContainer,
uint32_t aEndOffset)
ContentEventHandler::RawRange::SetEnd(const RawRangeBoundary& aEnd)
{
nsINode* newRoot = nsRange::ComputeRootNode(aEndContainer);
nsINode* newRoot = nsRange::ComputeRootNode(aEnd.Container());
if (!newRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
if (!IsValidOffset(aEndContainer, aEndOffset)) {
if (!aEnd.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// Collapse if not positioned yet, or if positioned in another document.
if (!IsPositioned() || newRoot != mRoot) {
mRoot = newRoot;
mStartContainer = mEndContainer = aEndContainer;
mStartOffset = mEndOffset = aEndOffset;
mStart = mEnd = aEnd;
return NS_OK;
}
mEndContainer = aEndContainer;
mEndOffset = aEndOffset;
mEnd = aEnd;
AssertStartIsBeforeOrEqualToEnd();
return NS_OK;
}
@ -126,61 +113,53 @@ ContentEventHandler::RawRange::SetEndAfter(nsINode* aEndContainer)
void
ContentEventHandler::RawRange::SetStartAndEnd(const nsRange* aRange)
{
DebugOnly<nsresult> rv = SetStartAndEnd(aRange->GetStartContainer(),
aRange->StartOffset(),
aRange->GetEndContainer(),
aRange->EndOffset());
DebugOnly<nsresult> rv = SetStartAndEnd(aRange->StartRef().AsRaw(),
aRange->EndRef().AsRaw());
MOZ_ASSERT(!aRange->IsPositioned() || NS_SUCCEEDED(rv));
}
nsresult
ContentEventHandler::RawRange::SetStartAndEnd(nsINode* aStartContainer,
uint32_t aStartOffset,
nsINode* aEndContainer,
uint32_t aEndOffset)
ContentEventHandler::RawRange::SetStartAndEnd(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd)
{
nsINode* newStartRoot = nsRange::ComputeRootNode(aStartContainer);
nsINode* newStartRoot = nsRange::ComputeRootNode(aStart.Container());
if (!newStartRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
if (!IsValidOffset(aStartContainer, aStartOffset)) {
if (!aStart.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
if (aStartContainer == aEndContainer) {
if (!IsValidOffset(aEndContainer, aEndOffset)) {
if (aStart.Container() == aEnd.Container()) {
if (!aEnd.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
MOZ_ASSERT(aStartOffset <= aEndOffset);
MOZ_ASSERT(aStart.Offset() <= aEnd.Offset());
mRoot = newStartRoot;
mStartContainer = mEndContainer = aStartContainer;
mStartOffset = aStartOffset;
mEndOffset = aEndOffset;
mStart = aStart;
mEnd = aEnd;
return NS_OK;
}
nsINode* newEndRoot = nsRange::ComputeRootNode(aEndContainer);
nsINode* newEndRoot = nsRange::ComputeRootNode(aEnd.Container());
if (!newEndRoot) {
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
if (!IsValidOffset(aEndContainer, aEndOffset)) {
if (!aEnd.IsSetAndValid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
// If they have different root, this should be collapsed at the end point.
if (newStartRoot != newEndRoot) {
mRoot = newEndRoot;
mStartContainer = mEndContainer = aEndContainer;
mStartOffset = mEndOffset = aEndOffset;
mStart = mEnd = aEnd;
return NS_OK;
}
// Otherwise, set the range as specified.
mRoot = newStartRoot;
mStartContainer = aStartContainer;
mStartOffset = aStartOffset;
mEndContainer = aEndContainer;
mEndOffset = aEndOffset;
mStart = aStart;
mEnd = aEnd;
AssertStartIsBeforeOrEqualToEnd();
return NS_OK;
}
@ -194,9 +173,9 @@ ContentEventHandler::RawRange::SelectNodeContents(
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
}
mRoot = newRoot;
mStartContainer = mEndContainer = aNodeToSelectContents;
mStartOffset = 0;
mEndOffset = aNodeToSelectContents->Length();
mStart = RawRangeBoundary(aNodeToSelectContents, nullptr);
mEnd = RawRangeBoundary(aNodeToSelectContents,
aNodeToSelectContents->GetLastChild());
return NS_OK;
}
@ -416,7 +395,7 @@ ContentEventHandler::InitCommon(SelectionType aSelectionType)
// But otherwise, we need to assume that there is a selection range at the
// beginning of the root content if aSelectionType is eNormal.
rv = mFirstSelectedRawRange.CollapseTo(mRootContent, 0);
rv = mFirstSelectedRawRange.CollapseTo(RawRangeBoundary(mRootContent, 0));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_UNEXPECTED;
}
@ -1160,7 +1139,7 @@ ContentEventHandler::SetRawRangeFromFlatTextOffset(
// Special case like <br contenteditable>
if (!mRootContent->HasChildren()) {
nsresult rv = aRawRange->CollapseTo(mRootContent, 0);
nsresult rv = aRawRange->CollapseTo(RawRangeBoundary(mRootContent, 0));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2917,8 +2896,7 @@ ContentEventHandler::GetFlatTextLengthInRange(
} else {
RawRange prevRawRange;
nsresult rv =
prevRawRange.SetStart(aStartPosition.Container(),
aStartPosition.Offset());
prevRawRange.SetStart(aStartPosition.AsRaw());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2951,7 +2929,7 @@ ContentEventHandler::GetFlatTextLengthInRange(
if (endPosition.IsSetAndValid()) {
// Offset is within node's length; set end of range to that offset
rv = prevRawRange.SetEnd(endPosition.Container(), endPosition.Offset());
rv = prevRawRange.SetEnd(endPosition.AsRaw());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2999,6 +2977,8 @@ ContentEventHandler::GetFlatTextLengthInRange(
if (node->IsNodeOfType(nsINode::eTEXT)) {
// Note: our range always starts from offset 0
if (node == endPosition.Container()) {
// NOTE: We should have an offset here, as endPosition.Container() is a
// nsINode::eTEXT, which always has an offset.
*aLength += GetTextLength(content, aLineBreakType,
endPosition.Offset());
} else {
@ -3099,7 +3079,8 @@ ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(RawRange& aRawRange)
return NS_OK;
}
nsresult rv = aRawRange.CollapseTo(childNode, offsetInChildNode);
nsresult rv =
aRawRange.CollapseTo(RawRangeBoundary(childNode, offsetInChildNode));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -46,56 +46,62 @@ private:
class MOZ_STACK_CLASS RawRange final
{
public:
RawRange()
: mStartOffset(0)
, mEndOffset(0)
{
}
RawRange() {}
void Clear()
{
mRoot = mStartContainer = mEndContainer = nullptr;
mStartOffset = mEndOffset = 0;
mRoot = nullptr;
mStart = RangeBoundary();
mEnd = RangeBoundary();
}
bool IsPositioned() const
{
return mStartContainer && mEndContainer;
return mStart.IsSet() && mEnd.IsSet();
}
bool Collapsed() const
{
return mStartContainer == mEndContainer &&
mStartOffset == mEndOffset &&
IsPositioned();
return mStart == mEnd && IsPositioned();
}
nsINode* GetStartContainer() const { return mStartContainer; }
nsINode* GetEndContainer() const { return mEndContainer; }
uint32_t StartOffset() const { return mStartOffset; }
uint32_t EndOffset() const { return mEndOffset; }
nsINode* GetStartContainer() const { return mStart.Container(); }
nsINode* GetEndContainer() const { return mEnd.Container(); }
uint32_t StartOffset() const { return mStart.Offset(); }
uint32_t EndOffset() const { return mEnd.Offset(); }
nsIContent* StartRef() const { return mStart.Ref(); }
nsIContent* EndRef() const { return mEnd.Ref(); }
nsresult CollapseTo(nsINode* aContainer, uint32_t aOffset)
// XXX: Make these use RangeBoundaries...
nsresult CollapseTo(const RawRangeBoundary& aBoundary)
{
return SetStartAndEnd(aContainer, aOffset, aContainer, aOffset);
return SetStartAndEnd(aBoundary, aBoundary);
}
nsresult SetStart(nsINode* aStartContainer, uint32_t aStartOffset);
nsresult SetEnd(nsINode* aEndContainer, uint32_t aEndOffset);
nsresult SetStart(const RawRangeBoundary& aStart);
nsresult SetEnd(const RawRangeBoundary& aEnd);
// NOTE: These helpers can hide performance problems, as they perform a
// search to find aStartOffset in aStartContainer.
nsresult SetStart(nsINode* aStartContainer, uint32_t aStartOffset) {
return SetStart(RawRangeBoundary(aStartContainer, aStartOffset));
}
nsresult SetEnd(nsINode* aEndContainer, uint32_t aEndOffset) {
return SetEnd(RawRangeBoundary(aEndContainer, aEndOffset));
}
nsresult SetEndAfter(nsINode* aEndContainer);
void SetStartAndEnd(const nsRange* aRange);
nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset);
nsresult SetStartAndEnd(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd);
nsresult SelectNodeContents(nsINode* aNodeToSelectContents);
private:
bool IsValidOffset(nsINode* aContainer, uint32_t aOffset) const;
nsINode* IsValidBoundary(nsINode* aNode) const;
inline void AssertStartIsBeforeOrEqualToEnd();
nsCOMPtr<nsINode> mRoot;
nsCOMPtr<nsINode> mStartContainer;
nsCOMPtr<nsINode> mEndContainer;
uint32_t mStartOffset;
uint32_t mEndOffset;
RangeBoundary mStart;
RangeBoundary mEnd;
};
public: