зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1646296 - part 8: Make stack only classes to group start/end boundary information of `WSRunScanner` r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D79973
This commit is contained in:
Родитель
5b98dad2b2
Коммит
6b7588bbe2
|
@ -74,15 +74,9 @@ WSRunScanner::WSRunScanner(const HTMLEditor* aHTMLEditor,
|
|||
mScanEndPoint(aScanEndPoint),
|
||||
mEditingHost(aHTMLEditor->GetActiveEditingHost()),
|
||||
mPRE(false),
|
||||
mStartOffset(0),
|
||||
mEndOffset(0),
|
||||
mFirstNBSPOffset(0),
|
||||
mLastNBSPOffset(0),
|
||||
mStartRun(nullptr),
|
||||
mEndRun(nullptr),
|
||||
mHTMLEditor(aHTMLEditor),
|
||||
mStartReason(WSType::NotInitialized),
|
||||
mEndReason(WSType::NotInitialized) {
|
||||
mHTMLEditor(aHTMLEditor) {
|
||||
MOZ_ASSERT(
|
||||
*nsContentUtils::ComparePoints(aScanStartPoint.ToRawRangeBoundary(),
|
||||
aScanEndPoint.ToRawRangeBoundary()) <= 0);
|
||||
|
@ -424,8 +418,8 @@ nsresult WSRunObject::InsertText(Document& aDocument,
|
|||
} else if (afterRunObject.EndsByBlockBoundary()) {
|
||||
// When afterRun is null, it means that mScanEndPoint is last point in
|
||||
// editing host or editing block.
|
||||
// If this text insertion replaces composition, this.mEndReason is
|
||||
// start position of compositon. So we have to use afterRunObject's
|
||||
// If this text insertion replaces composition, this.mEnd.mReason is
|
||||
// start position of composition. So we have to use afterRunObject's
|
||||
// reason instead.
|
||||
theString.SetCharAt(kNBSP, lastCharIndex);
|
||||
}
|
||||
|
@ -635,12 +629,11 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
}
|
||||
}
|
||||
|
||||
if (mStartReasonContent != mStartNode) {
|
||||
// In this case, mStartOffset is not meaningful.
|
||||
return WSScanResult(mStartReasonContent, mStartReason);
|
||||
if (mStart.GetReasonContent() != mStart.PointRef().GetContainer()) {
|
||||
// In this case, mStart.PointRef().Offset() is not meaningful.
|
||||
return WSScanResult(mStart.GetReasonContent(), mStart.RawReason());
|
||||
}
|
||||
return WSScanResult(EditorDOMPoint(mStartReasonContent, mStartOffset),
|
||||
mStartReason);
|
||||
return WSScanResult(mStart.PointRef(), mStart.RawReason());
|
||||
}
|
||||
|
||||
template <typename PT, typename CT>
|
||||
|
@ -671,19 +664,18 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
|||
}
|
||||
}
|
||||
|
||||
if (mEndReasonContent != mEndNode) {
|
||||
// In this case, mEndOffset is not meaningful.
|
||||
return WSScanResult(mEndReasonContent, mEndReason);
|
||||
if (mEnd.GetReasonContent() != mEnd.PointRef().GetContainer()) {
|
||||
// In this case, mEnd.PointRef().Offset() is not meaningful.
|
||||
return WSScanResult(mEnd.GetReasonContent(), mEnd.RawReason());
|
||||
}
|
||||
return WSScanResult(EditorDOMPoint(mEndReasonContent, mEndOffset),
|
||||
mEndReason);
|
||||
return WSScanResult(mEnd.PointRef(), mEnd.RawReason());
|
||||
}
|
||||
|
||||
nsresult WSRunObject::AdjustWhiteSpace() {
|
||||
// this routine examines a run of ws and tries to get rid of some unneeded
|
||||
// nbsp's, replacing them with regualr ascii space if possible. Keeping
|
||||
// nbsp's, replacing them with regular ascii space if possible. Keeping
|
||||
// things simple for now and just trying to fix up the trailing ws in the run.
|
||||
if (!mLastNBSPNode) {
|
||||
if (!mNBSPData.FoundNBSP()) {
|
||||
// nothing to do!
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -770,19 +762,14 @@ bool WSRunScanner::InitializeRangeStartWithTextNode(
|
|||
}
|
||||
|
||||
if (ch == HTMLEditUtils::kNBSP) {
|
||||
mFirstNBSPNode = aPoint.ContainerAsText();
|
||||
mFirstNBSPOffset = i - 1;
|
||||
if (!mLastNBSPNode) {
|
||||
mLastNBSPNode = aPoint.ContainerAsText();
|
||||
mLastNBSPOffset = i - 1;
|
||||
}
|
||||
mNBSPData.NotifyNBSP(
|
||||
EditorDOMPointInText(aPoint.ContainerAsText(), i - 1),
|
||||
NoBreakingSpaceData::Scanning::Backward);
|
||||
continue;
|
||||
}
|
||||
|
||||
mStartNode = aPoint.ContainerAsText();
|
||||
mStartOffset = i;
|
||||
mStartReason = WSType::NormalText;
|
||||
mStartReasonContent = aPoint.ContainerAsText();
|
||||
mStart = BoundaryData(EditorDOMPoint(aPoint.ContainerAsText(), i),
|
||||
*aPoint.ContainerAsText(), WSType::NormalText);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -815,21 +802,19 @@ void WSRunScanner::InitializeRangeStart(
|
|||
if (!previousLeafContentOrBlock) {
|
||||
// no prior node means we exhausted
|
||||
// aEditableBlockParentOrTopmostEditableInlineContent
|
||||
mStartNode = aPoint.GetContainer();
|
||||
mStartOffset = aPoint.Offset();
|
||||
mStartReason = WSType::CurrentBlockBoundary;
|
||||
// mStartReasonContent can be either a block element or any non-editable
|
||||
// mStart.mReasonContent can be either a block element or any non-editable
|
||||
// content in this case.
|
||||
mStartReasonContent = const_cast<nsIContent*>(
|
||||
&aEditableBlockParentOrTopmostEditableInlineContent);
|
||||
mStart =
|
||||
BoundaryData(aPoint,
|
||||
const_cast<nsIContent&>(
|
||||
aEditableBlockParentOrTopmostEditableInlineContent),
|
||||
WSType::CurrentBlockBoundary);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HTMLEditUtils::IsBlockElement(*previousLeafContentOrBlock)) {
|
||||
mStartNode = aPoint.GetContainer();
|
||||
mStartOffset = aPoint.Offset();
|
||||
mStartReason = WSType::OtherBlockBoundary;
|
||||
mStartReasonContent = previousLeafContentOrBlock;
|
||||
mStart = BoundaryData(aPoint, *previousLeafContentOrBlock,
|
||||
WSType::OtherBlockBoundary);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -837,12 +822,11 @@ void WSRunScanner::InitializeRangeStart(
|
|||
!previousLeafContentOrBlock->IsEditable()) {
|
||||
// it's a break or a special node, like <img>, that is not a block and
|
||||
// not a break but still serves as a terminator to ws runs.
|
||||
mStartNode = aPoint.GetContainer();
|
||||
mStartOffset = aPoint.Offset();
|
||||
mStartReason = previousLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
|
||||
? WSType::BRElement
|
||||
: WSType::SpecialContent;
|
||||
mStartReasonContent = previousLeafContentOrBlock;
|
||||
mStart =
|
||||
BoundaryData(aPoint, *previousLeafContentOrBlock,
|
||||
previousLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
|
||||
? WSType::BRElement
|
||||
: WSType::SpecialContent);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -881,19 +865,13 @@ bool WSRunScanner::InitializeRangeEndWithTextNode(
|
|||
}
|
||||
|
||||
if (ch == HTMLEditUtils::kNBSP) {
|
||||
mLastNBSPNode = aPoint.ContainerAsText();
|
||||
mLastNBSPOffset = i;
|
||||
if (!mFirstNBSPNode) {
|
||||
mFirstNBSPNode = aPoint.ContainerAsText();
|
||||
mFirstNBSPOffset = i;
|
||||
}
|
||||
mNBSPData.NotifyNBSP(EditorDOMPointInText(aPoint.ContainerAsText(), i),
|
||||
NoBreakingSpaceData::Scanning::Forward);
|
||||
continue;
|
||||
}
|
||||
|
||||
mEndNode = aPoint.ContainerAsText();
|
||||
mEndOffset = i;
|
||||
mEndReason = WSType::NormalText;
|
||||
mEndReasonContent = aPoint.ContainerAsText();
|
||||
mEnd = BoundaryData(EditorDOMPoint(aPoint.ContainerAsText(), i),
|
||||
*aPoint.ContainerAsText(), WSType::NormalText);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -925,22 +903,19 @@ void WSRunScanner::InitializeRangeEnd(
|
|||
if (!nextLeafContentOrBlock) {
|
||||
// no next node means we exhausted
|
||||
// aEditableBlockParentOrTopmostEditableInlineContent
|
||||
mEndNode = aPoint.GetContainer();
|
||||
mEndOffset = aPoint.Offset();
|
||||
mEndReason = WSType::CurrentBlockBoundary;
|
||||
// mEndReasonContent can be either a block element or any non-editable
|
||||
// mEnd.mReasonContent can be either a block element or any non-editable
|
||||
// content in this case.
|
||||
mEndReasonContent = const_cast<nsIContent*>(
|
||||
&aEditableBlockParentOrTopmostEditableInlineContent);
|
||||
mEnd = BoundaryData(aPoint,
|
||||
const_cast<nsIContent&>(
|
||||
aEditableBlockParentOrTopmostEditableInlineContent),
|
||||
WSType::CurrentBlockBoundary);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HTMLEditUtils::IsBlockElement(*nextLeafContentOrBlock)) {
|
||||
// we encountered a new block. therefore no more ws.
|
||||
mEndNode = aPoint.GetContainer();
|
||||
mEndOffset = aPoint.Offset();
|
||||
mEndReason = WSType::OtherBlockBoundary;
|
||||
mEndReasonContent = nextLeafContentOrBlock;
|
||||
mEnd = BoundaryData(aPoint, *nextLeafContentOrBlock,
|
||||
WSType::OtherBlockBoundary);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -949,12 +924,10 @@ void WSRunScanner::InitializeRangeEnd(
|
|||
// we encountered a break or a special node, like <img>,
|
||||
// that is not a block and not a break but still
|
||||
// serves as a terminator to ws runs.
|
||||
mEndNode = aPoint.GetContainer();
|
||||
mEndOffset = aPoint.Offset();
|
||||
mEndReason = nextLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
|
||||
? WSType::BRElement
|
||||
: WSType::SpecialContent;
|
||||
mEndReasonContent = nextLeafContentOrBlock;
|
||||
mEnd = BoundaryData(aPoint, *nextLeafContentOrBlock,
|
||||
nextLeafContentOrBlock->IsHTMLElement(nsGkAtoms::br)
|
||||
? WSType::BRElement
|
||||
: WSType::SpecialContent);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1002,7 +975,7 @@ void WSRunScanner::GetRuns() {
|
|||
|
||||
// if we are before or after a block (or after a break), and there are no
|
||||
// nbsp's, then it's all non-rendering ws.
|
||||
if (!mFirstNBSPNode && !mLastNBSPNode &&
|
||||
if (!mNBSPData.FoundNBSP() &&
|
||||
(StartsFromHardLineBreak() || EndsByBlockBoundary())) {
|
||||
InitializeWithSingleFragment(
|
||||
WSFragment::Visible::No,
|
||||
|
@ -1015,57 +988,74 @@ void WSRunScanner::GetRuns() {
|
|||
|
||||
// otherwise a little trickier. shucks.
|
||||
mStartRun = new WSFragment();
|
||||
mStartRun->mStartNode = mStartNode;
|
||||
mStartRun->mStartOffset = mStartOffset;
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
mStartRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
mStartRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
|
||||
if (StartsFromHardLineBreak()) {
|
||||
// set up mStartRun
|
||||
mStartRun->MarkAsStartOfHardLine();
|
||||
mStartRun->mEndNode = mFirstNBSPNode;
|
||||
mStartRun->mEndOffset = mFirstNBSPOffset;
|
||||
mStartRun->SetStartFrom(mStartReason);
|
||||
if (mNBSPData.FirstPointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mNBSPData.FirstPointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mNBSPData.FirstPointRef().Offset();
|
||||
}
|
||||
mStartRun->SetStartFrom(mStart.RawReason());
|
||||
mStartRun->SetEndByNormalWiteSpaces();
|
||||
|
||||
// set up next run
|
||||
WSFragment* normalRun = new WSFragment();
|
||||
mStartRun->mRight = normalRun;
|
||||
normalRun->MarkAsVisible();
|
||||
normalRun->mStartNode = mFirstNBSPNode;
|
||||
normalRun->mStartOffset = mFirstNBSPOffset;
|
||||
if (mNBSPData.FirstPointRef().IsSet()) {
|
||||
normalRun->mStartNode = mNBSPData.FirstPointRef().GetContainer();
|
||||
normalRun->mStartOffset = mNBSPData.FirstPointRef().Offset();
|
||||
}
|
||||
normalRun->SetStartFromLeadingWhiteSpaces();
|
||||
normalRun->mLeft = mStartRun;
|
||||
if (!EndsByBlockBoundary()) {
|
||||
// then no trailing ws. this normal run ends the overall ws run.
|
||||
normalRun->SetEndBy(mEndReason);
|
||||
normalRun->mEndNode = mEndNode;
|
||||
normalRun->mEndOffset = mEndOffset;
|
||||
normalRun->SetEndBy(mEnd.RawReason());
|
||||
if (mEnd.PointRef().IsSet()) {
|
||||
normalRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
normalRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
}
|
||||
mEndRun = normalRun;
|
||||
} else {
|
||||
// we might have trailing ws.
|
||||
// it so happens that *if* there is an nbsp at end,
|
||||
// {mEndNode,mEndOffset-1} will point to it, even though in general
|
||||
// start/end points not guaranteed to be in text nodes.
|
||||
if (mLastNBSPNode == mEndNode && mLastNBSPOffset == mEndOffset - 1) {
|
||||
if (mNBSPData.LastPointRef().IsSet() && mEnd.PointRef().IsSet() &&
|
||||
mNBSPData.LastPointRef().GetContainer() ==
|
||||
mEnd.PointRef().GetContainer() &&
|
||||
mNBSPData.LastPointRef().Offset() == mEnd.PointRef().Offset() - 1) {
|
||||
// normal ws runs right up to adjacent block (nbsp next to block)
|
||||
normalRun->SetEndBy(mEndReason);
|
||||
normalRun->mEndNode = mEndNode;
|
||||
normalRun->mEndOffset = mEndOffset;
|
||||
normalRun->SetEndBy(mEnd.RawReason());
|
||||
normalRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
normalRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
mEndRun = normalRun;
|
||||
} else {
|
||||
normalRun->mEndNode = mLastNBSPNode;
|
||||
normalRun->mEndOffset = mLastNBSPOffset + 1;
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
normalRun->mEndNode = mNBSPData.LastPointRef().GetContainer();
|
||||
normalRun->mEndOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
}
|
||||
normalRun->SetEndByTrailingWhiteSpaces();
|
||||
|
||||
// set up next run
|
||||
WSFragment* lastRun = new WSFragment();
|
||||
lastRun->MarkAsEndOfHardLine();
|
||||
lastRun->mStartNode = mLastNBSPNode;
|
||||
lastRun->mStartOffset = mLastNBSPOffset + 1;
|
||||
lastRun->mEndNode = mEndNode;
|
||||
lastRun->mEndOffset = mEndOffset;
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
lastRun->mStartNode = mNBSPData.LastPointRef().GetContainer();
|
||||
lastRun->mStartOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
}
|
||||
if (mEnd.PointRef().IsSet()) {
|
||||
lastRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
lastRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
}
|
||||
lastRun->SetStartFromNormalWhiteSpaces();
|
||||
lastRun->mLeft = normalRun;
|
||||
lastRun->SetEndBy(mEndReason);
|
||||
lastRun->SetEndBy(mEnd.RawReason());
|
||||
mEndRun = lastRun;
|
||||
normalRun->mRight = lastRun;
|
||||
}
|
||||
|
@ -1073,28 +1063,35 @@ void WSRunScanner::GetRuns() {
|
|||
} else {
|
||||
MOZ_ASSERT(!StartsFromHardLineBreak());
|
||||
mStartRun->MarkAsVisible();
|
||||
mStartRun->mEndNode = mLastNBSPNode;
|
||||
mStartRun->mEndOffset = mLastNBSPOffset + 1;
|
||||
mStartRun->SetStartFrom(mStartReason);
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mNBSPData.LastPointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
}
|
||||
mStartRun->SetStartFrom(mStart.RawReason());
|
||||
|
||||
// we might have trailing ws.
|
||||
// it so happens that *if* there is an nbsp at end, {mEndNode,mEndOffset-1}
|
||||
// will point to it, even though in general start/end points not
|
||||
// guaranteed to be in text nodes.
|
||||
if (mLastNBSPNode == mEndNode && mLastNBSPOffset == (mEndOffset - 1)) {
|
||||
mStartRun->SetEndBy(mEndReason);
|
||||
mStartRun->mEndNode = mEndNode;
|
||||
mStartRun->mEndOffset = mEndOffset;
|
||||
if (mNBSPData.LastPointRef().IsSet() && mEnd.PointRef().IsSet() &&
|
||||
mNBSPData.LastPointRef().GetContainer() ==
|
||||
mEnd.PointRef().GetContainer() &&
|
||||
mNBSPData.LastPointRef().Offset() == mEnd.PointRef().Offset() - 1) {
|
||||
mStartRun->SetEndBy(mEnd.RawReason());
|
||||
mStartRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
mEndRun = mStartRun;
|
||||
} else {
|
||||
// set up next run
|
||||
WSFragment* lastRun = new WSFragment();
|
||||
lastRun->MarkAsEndOfHardLine();
|
||||
lastRun->mStartNode = mLastNBSPNode;
|
||||
lastRun->mStartOffset = mLastNBSPOffset + 1;
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
lastRun->mStartNode = mNBSPData.LastPointRef().GetContainer();
|
||||
lastRun->mStartOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
}
|
||||
lastRun->SetStartFromNormalWhiteSpaces();
|
||||
lastRun->mLeft = mStartRun;
|
||||
lastRun->SetEndBy(mEndReason);
|
||||
lastRun->SetEndBy(mEnd.RawReason());
|
||||
mEndRun = lastRun;
|
||||
mStartRun->mRight = lastRun;
|
||||
mStartRun->SetEndByTrailingWhiteSpaces();
|
||||
|
@ -1123,8 +1120,10 @@ void WSRunScanner::InitializeWithSingleFragment(
|
|||
|
||||
mStartRun = new WSFragment();
|
||||
|
||||
mStartRun->mStartNode = mStartNode;
|
||||
mStartRun->mStartOffset = mStartOffset;
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
mStartRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
mStartRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
if (aIsVisible == WSFragment::Visible::Yes) {
|
||||
mStartRun->MarkAsVisible();
|
||||
}
|
||||
|
@ -1134,10 +1133,12 @@ void WSRunScanner::InitializeWithSingleFragment(
|
|||
if (aIsEndOfHardLine == WSFragment::EndOfHardLine::Yes) {
|
||||
mStartRun->MarkAsEndOfHardLine();
|
||||
}
|
||||
mStartRun->mEndNode = mEndNode;
|
||||
mStartRun->mEndOffset = mEndOffset;
|
||||
mStartRun->SetStartFrom(mStartReason);
|
||||
mStartRun->SetEndBy(mEndReason);
|
||||
if (mEnd.PointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
}
|
||||
mStartRun->SetStartFrom(mStart.RawReason());
|
||||
mStartRun->SetEndBy(mEnd.RawReason());
|
||||
|
||||
mEndRun = mStartRun;
|
||||
}
|
||||
|
@ -1353,7 +1354,7 @@ EditorDOMPointInText WSRunScanner::GetInclusiveNextEditableCharPoint(
|
|||
return EditorDOMPointInText(point.ContainerAsText(), point.Offset());
|
||||
}
|
||||
|
||||
if (point.GetContainer() == mEndReasonContent) {
|
||||
if (point.GetContainer() == mEnd.GetReasonContent()) {
|
||||
return EditorDOMPointInText();
|
||||
}
|
||||
|
||||
|
@ -1375,7 +1376,7 @@ EditorDOMPointInText WSRunScanner::GetInclusiveNextEditableCharPoint(
|
|||
*nextContent, *editableBlockParentOrTopmotEditableInlineContent,
|
||||
mEditingHost)) {
|
||||
if (!nextContent->IsText() || !nextContent->IsEditable()) {
|
||||
if (nextContent == mEndReasonContent) {
|
||||
if (nextContent == mEnd.GetReasonContent()) {
|
||||
break; // Reached end of current runs.
|
||||
}
|
||||
continue;
|
||||
|
@ -1421,7 +1422,7 @@ EditorDOMPointInText WSRunScanner::GetPreviousEditableCharPoint(
|
|||
return EditorDOMPointInText(point.ContainerAsText(), point.Offset() - 1);
|
||||
}
|
||||
|
||||
if (point.GetContainer() == mStartReasonContent) {
|
||||
if (point.GetContainer() == mStart.GetReasonContent()) {
|
||||
return EditorDOMPointInText();
|
||||
}
|
||||
|
||||
|
@ -1445,7 +1446,7 @@ EditorDOMPointInText WSRunScanner::GetPreviousEditableCharPoint(
|
|||
*editableBlockParentOrTopmotEditableInlineContent,
|
||||
mEditingHost)) {
|
||||
if (!previousContent->IsText() || !previousContent->IsEditable()) {
|
||||
if (previousContent == mStartReasonContent) {
|
||||
if (previousContent == mStart.GetReasonContent()) {
|
||||
break; // Reached start of current runs.
|
||||
}
|
||||
continue;
|
||||
|
|
|
@ -379,62 +379,42 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
* which is editable, but also may be non-element and/or non-editable. See
|
||||
* MOZ_ASSERT_IF()s in WSScanResult::AssertIfInvalidData() for the detail.
|
||||
*/
|
||||
nsIContent* GetStartReasonContent() const { return mStartReasonContent; }
|
||||
nsIContent* GetEndReasonContent() const { return mEndReasonContent; }
|
||||
nsIContent* GetStartReasonContent() const {
|
||||
return mStart.GetReasonContent();
|
||||
}
|
||||
nsIContent* GetEndReasonContent() const { return mEnd.GetReasonContent(); }
|
||||
|
||||
bool StartsFromNormalText() const {
|
||||
return mStartReason == WSType::NormalText;
|
||||
}
|
||||
bool StartsFromSpecialContent() const {
|
||||
return mStartReason == WSType::SpecialContent;
|
||||
}
|
||||
bool StartsFromBRElement() const { return mStartReason == WSType::BRElement; }
|
||||
bool StartsFromNormalText() const { return mStart.IsNormalText(); }
|
||||
bool StartsFromSpecialContent() const { return mStart.IsSpecialContent(); }
|
||||
bool StartsFromBRElement() const { return mStart.IsBRElement(); }
|
||||
bool StartsFromCurrentBlockBoundary() const {
|
||||
return mStartReason == WSType::CurrentBlockBoundary;
|
||||
return mStart.IsCurrentBlockBoundary();
|
||||
}
|
||||
bool StartsFromOtherBlockElement() const {
|
||||
return mStartReason == WSType::OtherBlockBoundary;
|
||||
return mStart.IsOtherBlockBoundary();
|
||||
}
|
||||
bool StartsFromBlockBoundary() const {
|
||||
return mStartReason == WSType::CurrentBlockBoundary ||
|
||||
mStartReason == WSType::OtherBlockBoundary;
|
||||
}
|
||||
bool StartsFromHardLineBreak() const {
|
||||
return mStartReason == WSType::CurrentBlockBoundary ||
|
||||
mStartReason == WSType::OtherBlockBoundary ||
|
||||
mStartReason == WSType::BRElement;
|
||||
}
|
||||
bool EndsByNormalText() const { return mEndReason == WSType::NormalText; }
|
||||
bool EndsBySpecialContent() const {
|
||||
return mEndReason == WSType::SpecialContent;
|
||||
}
|
||||
bool EndsByBRElement() const { return mEndReason == WSType::BRElement; }
|
||||
bool StartsFromBlockBoundary() const { return mStart.IsBlockBoundary(); }
|
||||
bool StartsFromHardLineBreak() const { return mStart.IsHardLineBreak(); }
|
||||
bool EndsByNormalText() const { return mEnd.IsNormalText(); }
|
||||
bool EndsBySpecialContent() const { return mEnd.IsSpecialContent(); }
|
||||
bool EndsByBRElement() const { return mEnd.IsBRElement(); }
|
||||
bool EndsByCurrentBlockBoundary() const {
|
||||
return mEndReason == WSType::CurrentBlockBoundary;
|
||||
}
|
||||
bool EndsByOtherBlockElement() const {
|
||||
return mEndReason == WSType::OtherBlockBoundary;
|
||||
}
|
||||
bool EndsByBlockBoundary() const {
|
||||
return mEndReason == WSType::CurrentBlockBoundary ||
|
||||
mEndReason == WSType::OtherBlockBoundary;
|
||||
return mEnd.IsCurrentBlockBoundary();
|
||||
}
|
||||
bool EndsByOtherBlockElement() const { return mEnd.IsOtherBlockBoundary(); }
|
||||
bool EndsByBlockBoundary() const { return mEnd.IsBlockBoundary(); }
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG dom::Element* StartReasonOtherBlockElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mStartReasonContent->IsElement());
|
||||
return mStartReasonContent->AsElement();
|
||||
return mStart.OtherBlockElementPtr();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG dom::HTMLBRElement* StartReasonBRElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mStartReasonContent->IsHTMLElement(nsGkAtoms::br));
|
||||
return static_cast<dom::HTMLBRElement*>(mStartReasonContent.get());
|
||||
return mStart.BRElementPtr();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG dom::Element* EndReasonOtherBlockElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mEndReasonContent->IsElement());
|
||||
return mEndReasonContent->AsElement();
|
||||
return mEnd.OtherBlockElementPtr();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG dom::HTMLBRElement* EndReasonBRElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mEndReasonContent->IsHTMLElement(nsGkAtoms::br));
|
||||
return static_cast<dom::HTMLBRElement*>(mEndReasonContent.get());
|
||||
return mEnd.BRElementPtr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -580,7 +560,7 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
* GetInclusiveNextEditableCharPoint() returns aPoint if it points a character
|
||||
* in an editable text node, or start of next editable text node otherwise.
|
||||
* FYI: For the performance, this does not check whether given container
|
||||
* is not after mStartReasonContent or not.
|
||||
* is not after mStart.mReasonContent or not.
|
||||
*/
|
||||
template <typename PT, typename CT>
|
||||
EditorDOMPointInText GetInclusiveNextEditableCharPoint(
|
||||
|
@ -591,7 +571,7 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
* text node. Note that this returns last character point when it meets
|
||||
* non-empty text node, otherwise, returns a point in an empty text node.
|
||||
* FYI: For the performance, this does not check whether given container
|
||||
* is not before mEndReasonContent or not.
|
||||
* is not before mEnd.mReasonContent or not.
|
||||
*/
|
||||
template <typename PT, typename CT>
|
||||
EditorDOMPointInText GetPreviousEditableCharPoint(
|
||||
|
@ -632,6 +612,83 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
|
||||
char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset) const;
|
||||
|
||||
class MOZ_STACK_CLASS BoundaryData final {
|
||||
public:
|
||||
BoundaryData() : mReason(WSType::NotInitialized) {}
|
||||
template <typename EditorDOMPointType>
|
||||
BoundaryData(const EditorDOMPointType& aPoint, nsIContent& aReasonContent,
|
||||
WSType aReason)
|
||||
: mReasonContent(&aReasonContent), mPoint(aPoint), mReason(aReason) {}
|
||||
bool Initialized() const { return mReasonContent && mPoint.IsSet(); }
|
||||
|
||||
nsIContent* GetReasonContent() const { return mReasonContent; }
|
||||
const EditorDOMPoint& PointRef() const { return mPoint; }
|
||||
WSType RawReason() const { return mReason; }
|
||||
|
||||
bool IsNormalText() const { return mReason == WSType::NormalText; }
|
||||
bool IsSpecialContent() const { return mReason == WSType::SpecialContent; }
|
||||
bool IsBRElement() const { return mReason == WSType::BRElement; }
|
||||
bool IsCurrentBlockBoundary() const {
|
||||
return mReason == WSType::CurrentBlockBoundary;
|
||||
}
|
||||
bool IsOtherBlockBoundary() const {
|
||||
return mReason == WSType::OtherBlockBoundary;
|
||||
}
|
||||
bool IsBlockBoundary() const {
|
||||
return mReason == WSType::CurrentBlockBoundary ||
|
||||
mReason == WSType::OtherBlockBoundary;
|
||||
}
|
||||
bool IsHardLineBreak() const {
|
||||
return mReason == WSType::CurrentBlockBoundary ||
|
||||
mReason == WSType::OtherBlockBoundary ||
|
||||
mReason == WSType::BRElement;
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG dom::Element* OtherBlockElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mReasonContent->IsElement());
|
||||
return mReasonContent->AsElement();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG dom::HTMLBRElement* BRElementPtr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mReasonContent->IsHTMLElement(nsGkAtoms::br));
|
||||
return static_cast<dom::HTMLBRElement*>(mReasonContent.get());
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mReasonContent;
|
||||
EditorDOMPoint mPoint;
|
||||
// Must be one of WSType::NotInitialized, WSType::NormalText,
|
||||
// WSType::SpecialContent, WSType::BRElement, WSType::CurrentBlockBoundary
|
||||
// or WSType::OtherBlockBoundary.
|
||||
WSType mReason;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS NoBreakingSpaceData final {
|
||||
public:
|
||||
enum class Scanning { Forward, Backward };
|
||||
void NotifyNBSP(const EditorDOMPointInText& aPoint,
|
||||
Scanning aScanningDirection) {
|
||||
MOZ_ASSERT(aPoint.IsSetAndValid());
|
||||
MOZ_ASSERT(aPoint.IsCharNBSP());
|
||||
if (!mFirst.IsSet() || aScanningDirection == Scanning::Backward) {
|
||||
mFirst = aPoint;
|
||||
}
|
||||
if (!mLast.IsSet() || aScanningDirection == Scanning::Forward) {
|
||||
mLast = aPoint;
|
||||
}
|
||||
}
|
||||
|
||||
const EditorDOMPointInText& FirstPointRef() const { return mFirst; }
|
||||
const EditorDOMPointInText& LastPointRef() const { return mLast; }
|
||||
|
||||
bool FoundNBSP() const {
|
||||
MOZ_ASSERT(mFirst.IsSet() == mLast.IsSet());
|
||||
return mFirst.IsSet();
|
||||
}
|
||||
|
||||
private:
|
||||
EditorDOMPointInText mFirst;
|
||||
EditorDOMPointInText mLast;
|
||||
};
|
||||
|
||||
void GetRuns();
|
||||
void ClearRuns();
|
||||
void InitializeWithSingleFragment(
|
||||
|
@ -663,42 +720,19 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
// true if we are in preformatted white-space context.
|
||||
bool mPRE;
|
||||
|
||||
// Node/offset where ws starts and ends.
|
||||
nsCOMPtr<nsINode> mStartNode;
|
||||
int32_t mStartOffset;
|
||||
|
||||
// Node/offset where ws ends.
|
||||
nsCOMPtr<nsINode> mEndNode;
|
||||
int32_t mEndOffset;
|
||||
|
||||
// Location of first nbsp in ws run, if any.
|
||||
RefPtr<dom::Text> mFirstNBSPNode;
|
||||
int32_t mFirstNBSPOffset;
|
||||
|
||||
// Location of last nbsp in ws run, if any.
|
||||
RefPtr<dom::Text> mLastNBSPNode;
|
||||
int32_t mLastNBSPOffset;
|
||||
|
||||
// The first WSFragment in the run.
|
||||
WSFragment* mStartRun;
|
||||
|
||||
// The last WSFragment in the run, may be same as first.
|
||||
WSFragment* mEndRun;
|
||||
|
||||
// See above comment for GetStartReasonContent() and GetEndReasonContent().
|
||||
nsCOMPtr<nsIContent> mStartReasonContent;
|
||||
nsCOMPtr<nsIContent> mEndReasonContent;
|
||||
|
||||
// Non-owning.
|
||||
const HTMLEditor* mHTMLEditor;
|
||||
|
||||
private:
|
||||
// Must be one of WSType::NotInitialized, WSType::NormalText,
|
||||
// WSType::SpecialContent, WSType::BRElement, WSType::CurrentBlockBoundary or
|
||||
// WSType::OtherBlockBoundary. Access these values with StartsFrom*() and
|
||||
// EndsBy*() accessors.
|
||||
WSType mStartReason;
|
||||
WSType mEndReason;
|
||||
protected:
|
||||
BoundaryData mStart;
|
||||
BoundaryData mEnd;
|
||||
NoBreakingSpaceData mNBSPData;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS WSRunObject final : public WSRunScanner {
|
||||
|
@ -896,13 +930,6 @@ class MOZ_STACK_CLASS WSRunObject final : public WSRunScanner {
|
|||
|
||||
MOZ_CAN_RUN_SCRIPT nsresult Scrub();
|
||||
|
||||
EditorDOMPoint StartPoint() const {
|
||||
return EditorDOMPoint(mStartNode, mStartOffset);
|
||||
}
|
||||
EditorDOMPoint EndPoint() const {
|
||||
return EditorDOMPoint(mEndNode, mEndOffset);
|
||||
}
|
||||
|
||||
// Because of MOZ_CAN_RUN_SCRIPT constructors, each instanciater of this class
|
||||
// guarantees the lifetime of the HTMLEditor.
|
||||
HTMLEditor& mHTMLEditor;
|
||||
|
|
Загрузка…
Ссылка в новой задаче