зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1646325 - part 2: Manage `WSFragment`s with array r=m_kato
`WSFragment` is created at least one instance, and at most 3 instances per `WSRunScanner` instance. They can be managed with `AutoTArray` simpler and we can avoid heap allocation with this approach. Differential Revision: https://phabricator.services.mozilla.com/D80314
This commit is contained in:
Родитель
7b964c86a2
Коммит
69d6f854ee
|
@ -74,8 +74,6 @@ WSRunScanner::WSRunScanner(const HTMLEditor* aHTMLEditor,
|
|||
mScanEndPoint(aScanEndPoint),
|
||||
mEditingHost(aHTMLEditor->GetActiveEditingHost()),
|
||||
mPRE(false),
|
||||
mStartRun(nullptr),
|
||||
mEndRun(nullptr),
|
||||
mHTMLEditor(aHTMLEditor) {
|
||||
MOZ_ASSERT(
|
||||
*nsContentUtils::ComparePoints(aScanStartPoint.ToRawRangeBoundary(),
|
||||
|
@ -86,8 +84,6 @@ WSRunScanner::WSRunScanner(const HTMLEditor* aHTMLEditor,
|
|||
GetRuns();
|
||||
}
|
||||
|
||||
WSRunScanner::~WSRunScanner() { ClearRuns(); }
|
||||
|
||||
template <typename PT, typename CT>
|
||||
WSRunObject::WSRunObject(HTMLEditor& aHTMLEditor,
|
||||
const EditorDOMPointBase<PT, CT>& aScanStartPoint,
|
||||
|
@ -679,11 +675,11 @@ nsresult WSRunObject::AdjustWhiteSpace() {
|
|||
// nothing to do!
|
||||
return NS_OK;
|
||||
}
|
||||
for (WSFragment* run = mStartRun; run; run = run->mRight) {
|
||||
if (!run->IsVisibleAndMiddleOfHardLine()) {
|
||||
for (const WSFragment& fragment : mFragments) {
|
||||
if (!fragment.IsVisibleAndMiddleOfHardLine()) {
|
||||
continue;
|
||||
}
|
||||
nsresult rv = NormalizeWhiteSpacesAtEndOf(*run);
|
||||
nsresult rv = NormalizeWhiteSpacesAtEndOf(fragment);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("WSRunObject::NormalizeWhiteSpacesAtEndOf() failed");
|
||||
return rv;
|
||||
|
@ -953,7 +949,7 @@ void WSRunScanner::InitializeRangeEnd(
|
|||
}
|
||||
|
||||
void WSRunScanner::GetRuns() {
|
||||
ClearRuns();
|
||||
MOZ_ASSERT(mFragments.IsEmpty());
|
||||
|
||||
// Handle preformatted case first since it's simple. Note that if end of
|
||||
// the scan range isn't in preformatted element, we need to check only the
|
||||
|
@ -986,20 +982,18 @@ void WSRunScanner::GetRuns() {
|
|||
return;
|
||||
}
|
||||
|
||||
// otherwise a little trickier. shucks.
|
||||
mStartRun = new WSFragment();
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
mStartRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
mStartRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
|
||||
if (!StartsFromHardLineBreak()) {
|
||||
mStartRun->MarkAsVisible();
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mNBSPData.LastPointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
WSFragment* startRun = mFragments.AppendElement();
|
||||
startRun->MarkAsVisible();
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
startRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
startRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
startRun->SetStartFrom(mStart.RawReason());
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
startRun->mEndNode = mNBSPData.LastPointRef().GetContainer();
|
||||
startRun->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}
|
||||
|
@ -1009,50 +1003,52 @@ void WSRunScanner::GetRuns() {
|
|||
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;
|
||||
startRun->SetEndBy(mEnd.RawReason());
|
||||
startRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
startRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
return;
|
||||
}
|
||||
|
||||
// set up next run
|
||||
WSFragment* lastRun = new WSFragment();
|
||||
WSFragment* lastRun = mFragments.AppendElement();
|
||||
lastRun->MarkAsEndOfHardLine();
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
lastRun->mStartNode = mNBSPData.LastPointRef().GetContainer();
|
||||
lastRun->mStartOffset = mNBSPData.LastPointRef().Offset() + 1;
|
||||
}
|
||||
lastRun->SetStartFromNormalWhiteSpaces();
|
||||
lastRun->mLeft = mStartRun;
|
||||
lastRun->mLeft = startRun;
|
||||
lastRun->SetEndBy(mEnd.RawReason());
|
||||
mEndRun = lastRun;
|
||||
mStartRun->mRight = lastRun;
|
||||
mStartRun->SetEndByTrailingWhiteSpaces();
|
||||
startRun->mRight = lastRun;
|
||||
startRun->SetEndByTrailingWhiteSpaces();
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(StartsFromHardLineBreak());
|
||||
|
||||
// set up mStartRun
|
||||
mStartRun->MarkAsStartOfHardLine();
|
||||
if (mNBSPData.FirstPointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mNBSPData.FirstPointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mNBSPData.FirstPointRef().Offset();
|
||||
WSFragment* startRun = mFragments.AppendElement();
|
||||
startRun->MarkAsStartOfHardLine();
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
startRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
startRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
mStartRun->SetStartFrom(mStart.RawReason());
|
||||
mStartRun->SetEndByNormalWiteSpaces();
|
||||
startRun->SetStartFrom(mStart.RawReason());
|
||||
if (mNBSPData.FirstPointRef().IsSet()) {
|
||||
startRun->mEndNode = mNBSPData.FirstPointRef().GetContainer();
|
||||
startRun->mEndOffset = mNBSPData.FirstPointRef().Offset();
|
||||
}
|
||||
startRun->SetEndByNormalWiteSpaces();
|
||||
|
||||
// set up next run
|
||||
WSFragment* normalRun = new WSFragment();
|
||||
mStartRun->mRight = normalRun;
|
||||
WSFragment* normalRun = mFragments.AppendElement();
|
||||
startRun->mRight = normalRun;
|
||||
normalRun->MarkAsVisible();
|
||||
if (mNBSPData.FirstPointRef().IsSet()) {
|
||||
normalRun->mStartNode = mNBSPData.FirstPointRef().GetContainer();
|
||||
normalRun->mStartOffset = mNBSPData.FirstPointRef().Offset();
|
||||
}
|
||||
normalRun->SetStartFromLeadingWhiteSpaces();
|
||||
normalRun->mLeft = mStartRun;
|
||||
normalRun->mLeft = startRun;
|
||||
if (!EndsByBlockBoundary()) {
|
||||
// then no trailing ws. this normal run ends the overall ws run.
|
||||
normalRun->SetEndBy(mEnd.RawReason());
|
||||
|
@ -1060,7 +1056,6 @@ void WSRunScanner::GetRuns() {
|
|||
normalRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
normalRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
}
|
||||
mEndRun = normalRun;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1076,7 +1071,6 @@ void WSRunScanner::GetRuns() {
|
|||
normalRun->SetEndBy(mEnd.RawReason());
|
||||
normalRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
normalRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
mEndRun = normalRun;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1087,7 +1081,7 @@ void WSRunScanner::GetRuns() {
|
|||
normalRun->SetEndByTrailingWhiteSpaces();
|
||||
|
||||
// set up next run
|
||||
WSFragment* lastRun = new WSFragment();
|
||||
WSFragment* lastRun = mFragments.AppendElement();
|
||||
lastRun->MarkAsEndOfHardLine();
|
||||
if (mNBSPData.LastPointRef().IsSet()) {
|
||||
lastRun->mStartNode = mNBSPData.LastPointRef().GetContainer();
|
||||
|
@ -1100,52 +1094,36 @@ void WSRunScanner::GetRuns() {
|
|||
lastRun->SetStartFromNormalWhiteSpaces();
|
||||
lastRun->mLeft = normalRun;
|
||||
lastRun->SetEndBy(mEnd.RawReason());
|
||||
mEndRun = lastRun;
|
||||
normalRun->mRight = lastRun;
|
||||
}
|
||||
|
||||
void WSRunScanner::ClearRuns() {
|
||||
WSFragment *tmp, *run;
|
||||
run = mStartRun;
|
||||
while (run) {
|
||||
tmp = run->mRight;
|
||||
delete run;
|
||||
run = tmp;
|
||||
}
|
||||
mStartRun = 0;
|
||||
mEndRun = 0;
|
||||
}
|
||||
|
||||
void WSRunScanner::InitializeWithSingleFragment(
|
||||
WSFragment::Visible aIsVisible,
|
||||
WSFragment::StartOfHardLine aIsStartOfHardLine,
|
||||
WSFragment::EndOfHardLine aIsEndOfHardLine) {
|
||||
MOZ_ASSERT(!mStartRun);
|
||||
MOZ_ASSERT(!mEndRun);
|
||||
MOZ_ASSERT(mFragments.IsEmpty());
|
||||
|
||||
mStartRun = new WSFragment();
|
||||
WSFragment* startRun = mFragments.AppendElement();
|
||||
|
||||
if (mStart.PointRef().IsSet()) {
|
||||
mStartRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
mStartRun->mStartOffset = mStart.PointRef().Offset();
|
||||
startRun->mStartNode = mStart.PointRef().GetContainer();
|
||||
startRun->mStartOffset = mStart.PointRef().Offset();
|
||||
}
|
||||
if (aIsVisible == WSFragment::Visible::Yes) {
|
||||
mStartRun->MarkAsVisible();
|
||||
startRun->MarkAsVisible();
|
||||
}
|
||||
if (aIsStartOfHardLine == WSFragment::StartOfHardLine::Yes) {
|
||||
mStartRun->MarkAsStartOfHardLine();
|
||||
startRun->MarkAsStartOfHardLine();
|
||||
}
|
||||
if (aIsEndOfHardLine == WSFragment::EndOfHardLine::Yes) {
|
||||
mStartRun->MarkAsEndOfHardLine();
|
||||
startRun->MarkAsEndOfHardLine();
|
||||
}
|
||||
if (mEnd.PointRef().IsSet()) {
|
||||
mStartRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
mStartRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
startRun->mEndNode = mEnd.PointRef().GetContainer();
|
||||
startRun->mEndOffset = mEnd.PointRef().Offset();
|
||||
}
|
||||
mStartRun->SetStartFrom(mStart.RawReason());
|
||||
mStartRun->SetEndBy(mEnd.RawReason());
|
||||
|
||||
mEndRun = mStartRun;
|
||||
startRun->SetStartFrom(mStart.RawReason());
|
||||
startRun->SetEndBy(mEnd.RawReason());
|
||||
}
|
||||
|
||||
nsresult WSRunObject::PrepareToDeleteRangePriv(WSRunObject* aEndObject) {
|
||||
|
@ -1636,37 +1614,38 @@ const WSRunScanner::WSFragment* WSRunScanner::FindNearestFragment(
|
|||
const EditorDOMPointBase<PT, CT>& aPoint, bool aForward) const {
|
||||
MOZ_ASSERT(aPoint.IsSetAndValid());
|
||||
|
||||
for (WSFragment* run = mStartRun; run; run = run->mRight) {
|
||||
int32_t comp = run->mStartNode ? *nsContentUtils::ComparePoints(
|
||||
aPoint.ToRawRangeBoundary(),
|
||||
run->StartPoint().ToRawRangeBoundary())
|
||||
: -1;
|
||||
for (const WSFragment& fragment : mFragments) {
|
||||
int32_t comp = fragment.mStartNode
|
||||
? *nsContentUtils::ComparePoints(
|
||||
aPoint.ToRawRangeBoundary(),
|
||||
fragment.StartPoint().ToRawRangeBoundary())
|
||||
: -1;
|
||||
if (comp <= 0) {
|
||||
// aPoint equals or before start of the run. Return the run if we're
|
||||
// scanning forward, otherwise, nullptr.
|
||||
return aForward ? run : nullptr;
|
||||
// aPoint equals or before start of the fragment.
|
||||
// Return it if we're scanning forward, otherwise, nullptr.
|
||||
return aForward ? &fragment : nullptr;
|
||||
}
|
||||
|
||||
comp = run->mEndNode ? *nsContentUtils::ComparePoints(
|
||||
aPoint.ToRawRangeBoundary(),
|
||||
run->EndPoint().ToRawRangeBoundary())
|
||||
: -1;
|
||||
comp = fragment.mEndNode ? *nsContentUtils::ComparePoints(
|
||||
aPoint.ToRawRangeBoundary(),
|
||||
fragment.EndPoint().ToRawRangeBoundary())
|
||||
: -1;
|
||||
if (comp < 0) {
|
||||
// If aPoint is in the run, return the run.
|
||||
return run;
|
||||
// If aPoint is in the fragment, return it.
|
||||
return &fragment;
|
||||
}
|
||||
|
||||
if (!comp) {
|
||||
// If aPoint is at end of the run, return next run if we're scanning
|
||||
// forward, otherwise, return the run.
|
||||
return aForward ? run->mRight : run;
|
||||
// If aPoint is at end of the fragment, return next fragment if we're
|
||||
// scanning forward, otherwise, return it.
|
||||
return aForward ? fragment.mRight : &fragment;
|
||||
}
|
||||
|
||||
if (!run->mRight) {
|
||||
// If the run is the last run and aPoint is after end of the last run,
|
||||
// return nullptr if we're scanning forward, otherwise, return this
|
||||
// last run.
|
||||
return aForward ? nullptr : run;
|
||||
if (!fragment.mRight) {
|
||||
// If the fragment is the last fragment and aPoint is after end of the
|
||||
// last fragment, return nullptr if we're scanning forward, otherwise,
|
||||
// return this last fragment.
|
||||
return aForward ? nullptr : &fragment;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1996,13 +1975,13 @@ nsresult WSRunObject::MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace(
|
|||
}
|
||||
|
||||
nsresult WSRunObject::Scrub() {
|
||||
for (WSFragment* run = mStartRun; run; run = run->mRight) {
|
||||
if (run->IsMiddleOfHardLine()) {
|
||||
for (const WSFragment& fragment : mFragments) {
|
||||
if (fragment.IsMiddleOfHardLine()) {
|
||||
continue;
|
||||
}
|
||||
nsresult rv = MOZ_KnownLive(mHTMLEditor)
|
||||
.DeleteTextAndTextNodesWithTransaction(run->StartPoint(),
|
||||
run->EndPoint());
|
||||
.DeleteTextAndTextNodesWithTransaction(
|
||||
fragment.StartPoint(), fragment.EndPoint());
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("HTMLEditor::DeleteTextAndTextNodesWithTransaction() failed");
|
||||
return rv;
|
||||
|
|
|
@ -307,7 +307,6 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
: WSRunScanner(aHTMLEditor,
|
||||
EditorRawDOMPoint(aScanStartNode, aScanStartOffset),
|
||||
EditorRawDOMPoint(aScanStartNode, aScanStartOffset)) {}
|
||||
~WSRunScanner();
|
||||
|
||||
// ScanNextVisibleNodeOrBlockBoundaryForwardFrom() returns the first visible
|
||||
// node after aPoint. If there is no visible nodes after aPoint, returns
|
||||
|
@ -428,7 +427,7 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
// WSFragment represents a single run of ws (all leadingws, or all normalws,
|
||||
// or all trailingws, or all leading+trailingws). Note that this single run
|
||||
// may still span multiple nodes.
|
||||
struct WSFragment final {
|
||||
struct MOZ_STACK_CLASS WSFragment final {
|
||||
nsCOMPtr<nsINode> mStartNode; // node where ws run starts
|
||||
nsCOMPtr<nsINode> mEndNode; // node where ws run ends
|
||||
int32_t mStartOffset; // offset where ws run starts
|
||||
|
@ -531,6 +530,8 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
EndOfHardLine mIsEndOfHardLine;
|
||||
};
|
||||
|
||||
using WSFragmentArray = AutoTArray<WSFragment, 3>;
|
||||
|
||||
/**
|
||||
* FindNearestFragment() looks for a WSFragment which is closest to specified
|
||||
* direction from aPoint.
|
||||
|
@ -690,7 +691,6 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
};
|
||||
|
||||
void GetRuns();
|
||||
void ClearRuns();
|
||||
void InitializeWithSingleFragment(
|
||||
WSFragment::Visible aIsVisible,
|
||||
WSFragment::StartOfHardLine aIsStartOfHardLine,
|
||||
|
@ -720,11 +720,7 @@ class MOZ_STACK_CLASS WSRunScanner {
|
|||
// true if we are in preformatted white-space context.
|
||||
bool mPRE;
|
||||
|
||||
// The first WSFragment in the run.
|
||||
WSFragment* mStartRun;
|
||||
|
||||
// The last WSFragment in the run, may be same as first.
|
||||
WSFragment* mEndRun;
|
||||
WSFragmentArray mFragments;
|
||||
|
||||
// Non-owning.
|
||||
const HTMLEditor* mHTMLEditor;
|
||||
|
|
Загрузка…
Ссылка в новой задаче