зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1781994 - part 2: Make `HTMLEditor::SplitAncestorStyledInlineElementsAtRangeEdges` stop touching `Selection` directly r=m_kato
Depends on D154343 Differential Revision: https://phabricator.services.mozilla.com/D154344
This commit is contained in:
Родитель
9f9cd9e318
Коммит
fcecac970b
|
@ -1206,21 +1206,42 @@ class EditorDOMRangeBase final {
|
|||
}
|
||||
|
||||
template <typename MaybeOtherPointType>
|
||||
MOZ_NEVER_INLINE_DEBUG void SetStart(const MaybeOtherPointType& aStart) {
|
||||
void SetStart(const MaybeOtherPointType& aStart) {
|
||||
mStart = aStart.template To<PointType>();
|
||||
}
|
||||
void SetStart(PointType&& aStart) { mStart = std::move(aStart); }
|
||||
template <typename MaybeOtherPointType>
|
||||
MOZ_NEVER_INLINE_DEBUG void SetEnd(const MaybeOtherPointType& aEnd) {
|
||||
void SetEnd(const MaybeOtherPointType& aEnd) {
|
||||
mEnd = aEnd.template To<PointType>();
|
||||
}
|
||||
void SetEnd(PointType&& aEnd) { mEnd = std::move(aEnd); }
|
||||
template <typename StartPointType, typename EndPointType>
|
||||
MOZ_NEVER_INLINE_DEBUG void SetStartAndEnd(const StartPointType& aStart,
|
||||
const EndPointType& aEnd) {
|
||||
void SetStartAndEnd(const StartPointType& aStart, const EndPointType& aEnd) {
|
||||
MOZ_ASSERT_IF(aStart.IsSet() && aEnd.IsSet(),
|
||||
aStart.EqualsOrIsBefore(aEnd));
|
||||
mStart = aStart.template To<PointType>();
|
||||
mEnd = aEnd.template To<PointType>();
|
||||
}
|
||||
template <typename StartPointType>
|
||||
void SetStartAndEnd(const StartPointType& aStart, PointType&& aEnd) {
|
||||
MOZ_ASSERT_IF(aStart.IsSet() && aEnd.IsSet(),
|
||||
aStart.EqualsOrIsBefore(aEnd));
|
||||
mStart = aStart.template To<PointType>();
|
||||
mEnd = std::move(aEnd);
|
||||
}
|
||||
template <typename EndPointType>
|
||||
void SetStartAndEnd(PointType&& aStart, const EndPointType& aEnd) {
|
||||
MOZ_ASSERT_IF(aStart.IsSet() && aEnd.IsSet(),
|
||||
aStart.EqualsOrIsBefore(aEnd));
|
||||
mStart = std::move(aStart);
|
||||
mEnd = aEnd.template To<PointType>();
|
||||
}
|
||||
void SetStartAndEnd(PointType&& aStart, PointType&& aEnd) {
|
||||
MOZ_ASSERT_IF(aStart.IsSet() && aEnd.IsSet(),
|
||||
aStart.EqualsOrIsBefore(aEnd));
|
||||
mStart = std::move(aStart);
|
||||
mEnd = std::move(aEnd);
|
||||
}
|
||||
void Clear() {
|
||||
mStart.Clear();
|
||||
mEnd.Clear();
|
||||
|
@ -1248,6 +1269,11 @@ class EditorDOMRangeBase final {
|
|||
MOZ_ASSERT(IsPositioned());
|
||||
return IsPositioned() && mStart.GetContainer() == mEnd.GetContainer();
|
||||
}
|
||||
bool InAdjacentSiblings() const {
|
||||
MOZ_ASSERT(IsPositioned());
|
||||
return IsPositioned() &&
|
||||
mStart.GetContainer()->GetNextSibling() == mEnd.GetContainer();
|
||||
}
|
||||
bool IsInContentNodes() const {
|
||||
MOZ_ASSERT(IsPositioned());
|
||||
return IsPositioned() && mStart.IsInContentNode() && mEnd.IsInContentNode();
|
||||
|
|
|
@ -936,60 +936,84 @@ class MOZ_STACK_CLASS SplitRangeOffResult final {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is at right node of split at start point.
|
||||
* The start boundary is at the right of split at split point. The end
|
||||
* boundary is at right node of split at end point, i.e., the end boundary
|
||||
* points out of the range to have been split off.
|
||||
*/
|
||||
constexpr const EditorDOMPoint& SplitPointAtStart() const {
|
||||
return mSplitPointAtStart;
|
||||
}
|
||||
constexpr const EditorDOMRange& RangeRef() const { return mRange; }
|
||||
|
||||
/**
|
||||
* This is at right node of split at end point. I.e., not in the range.
|
||||
* This is after the range.
|
||||
* Suggest caret position to aHTMLEditor.
|
||||
*/
|
||||
constexpr const EditorDOMPoint& SplitPointAtEnd() const {
|
||||
return mSplitPointAtEnd;
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SuggestCaretPointTo(
|
||||
const HTMLEditor& aHTMLEditor, const SuggestCaretOptions& aOptions) const;
|
||||
|
||||
/**
|
||||
* IgnoreCaretPointSuggestion() should be called if the method does not want
|
||||
* to use caret position recommended by this instance.
|
||||
*/
|
||||
void IgnoreCaretPointSuggestion() const { mHandledCaretPoint = true; }
|
||||
|
||||
bool HasCaretPointSuggestion() const { return mCaretPoint.IsSet(); }
|
||||
constexpr EditorDOMPoint&& UnwrapCaretPoint() {
|
||||
mHandledCaretPoint = true;
|
||||
return std::move(mCaretPoint);
|
||||
}
|
||||
bool MoveCaretPointTo(EditorDOMPoint& aPointToPutCaret,
|
||||
const SuggestCaretOptions& aOptions) {
|
||||
MOZ_ASSERT(!aOptions.contains(SuggestCaret::AndIgnoreTrivialError));
|
||||
MOZ_ASSERT(
|
||||
!aOptions.contains(SuggestCaret::OnlyIfTransactionsAllowedToDoIt));
|
||||
if (aOptions.contains(SuggestCaret::OnlyIfHasSuggestion) &&
|
||||
!mCaretPoint.IsSet()) {
|
||||
return false;
|
||||
}
|
||||
aPointToPutCaret = UnwrapCaretPoint();
|
||||
return true;
|
||||
}
|
||||
bool MoveCaretPointTo(EditorDOMPoint& aPointToPutCaret,
|
||||
const HTMLEditor& aHTMLEditor,
|
||||
const SuggestCaretOptions& aOptions);
|
||||
|
||||
SplitRangeOffResult() = delete;
|
||||
|
||||
/**
|
||||
* Constructor for success case.
|
||||
*
|
||||
* @param aTrackedRangeStart This should be at topmost right node
|
||||
* child at start point if actually split
|
||||
* there, or at start point to be tried
|
||||
* to split. Note that if the method
|
||||
* allows to run script after splitting
|
||||
* at start point, the point should be
|
||||
* tracked with AutoTrackDOMPoint.
|
||||
* @param aTrackedRangeStart The range whose start is at topmost
|
||||
* right node child at start point if
|
||||
* actually split there, or at the point
|
||||
* to be tried to split, and whose end is
|
||||
* at topmost right node child at end point
|
||||
* if actually split there, or at the point
|
||||
* to be tried to split. Note that if the
|
||||
* method allows to run script after
|
||||
* splitting the range boundaries, they
|
||||
* should be tracked with
|
||||
* AutoTrackDOMRange.
|
||||
* @param aSplitNodeResultAtStart Raw split node result at start point.
|
||||
* @param aTrackedRangeEnd This should be at topmost right node
|
||||
* child at end point if actually split
|
||||
* here, or at end point to be tried to
|
||||
* split. As same as aTrackedRangeStart,
|
||||
* this value should be tracked while
|
||||
* running some script.
|
||||
* @param aSplitNodeResultAtEnd Raw split node result at start point.
|
||||
*/
|
||||
SplitRangeOffResult(EditorDOMPoint&& aTrackedRangeStart,
|
||||
SplitRangeOffResult(EditorDOMRange&& aTrackedRange,
|
||||
SplitNodeResult&& aSplitNodeResultAtStart,
|
||||
EditorDOMPoint&& aTrackedRangeEnd,
|
||||
SplitNodeResult&& aSplitNodeResultAtEnd)
|
||||
: mSplitPointAtStart(aTrackedRangeStart),
|
||||
mSplitPointAtEnd(aTrackedRangeEnd),
|
||||
: mRange(std::move(aTrackedRange)),
|
||||
mRv(NS_OK),
|
||||
mHandled(aSplitNodeResultAtStart.Handled() ||
|
||||
aSplitNodeResultAtEnd.Handled()) {
|
||||
MOZ_ASSERT(mSplitPointAtStart.IsSet());
|
||||
MOZ_ASSERT(mSplitPointAtEnd.IsSet());
|
||||
MOZ_ASSERT(mRange.StartRef().IsSet());
|
||||
MOZ_ASSERT(mRange.EndRef().IsSet());
|
||||
MOZ_ASSERT(aSplitNodeResultAtStart.isOk());
|
||||
MOZ_ASSERT(aSplitNodeResultAtEnd.isOk());
|
||||
// The given results are created for creating this instance so that the
|
||||
// caller may not need to handle with them. For making who taking the
|
||||
// reposible clearer, we should move them into this constructor.
|
||||
// responsible clearer, we should move them into this constructor.
|
||||
SplitNodeResult splitNodeResultAtStart(std::move(aSplitNodeResultAtStart));
|
||||
SplitNodeResult splitNodeResultAtEnd(std::move(aSplitNodeResultAtEnd));
|
||||
splitNodeResultAtStart.IgnoreCaretPointSuggestion();
|
||||
splitNodeResultAtEnd.IgnoreCaretPointSuggestion();
|
||||
splitNodeResultAtStart.MoveCaretPointTo(
|
||||
mCaretPoint, {SuggestCaret::OnlyIfHasSuggestion});
|
||||
splitNodeResultAtEnd.MoveCaretPointTo(mCaretPoint,
|
||||
{SuggestCaret::OnlyIfHasSuggestion});
|
||||
}
|
||||
|
||||
explicit SplitRangeOffResult(nsresult aRv) : mRv(aRv), mHandled(false) {
|
||||
|
@ -1002,8 +1026,7 @@ class MOZ_STACK_CLASS SplitRangeOffResult final {
|
|||
SplitRangeOffResult& operator=(SplitRangeOffResult&& aOther) = default;
|
||||
|
||||
private:
|
||||
EditorDOMPoint mSplitPointAtStart;
|
||||
EditorDOMPoint mSplitPointAtEnd;
|
||||
EditorDOMRange mRange;
|
||||
|
||||
// If you need to store previous and/or next node at start/end point,
|
||||
// you might be able to use `SplitNodeResult::GetPreviousNode()` etc in the
|
||||
|
@ -1011,9 +1034,14 @@ class MOZ_STACK_CLASS SplitRangeOffResult final {
|
|||
// the node might have gone with another DOM tree mutation. So, be careful
|
||||
// if you do it.
|
||||
|
||||
// The point which is a good point to put caret from point of view the
|
||||
// splitter.
|
||||
EditorDOMPoint mCaretPoint;
|
||||
|
||||
nsresult mRv;
|
||||
|
||||
bool mHandled;
|
||||
bool mutable mHandledCaretPoint = false;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -886,20 +886,19 @@ class HTMLEditor final : public EditorBase,
|
|||
|
||||
/**
|
||||
* SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
|
||||
* elements in the block at both aStartPoint and aEndPoint if given style
|
||||
* matches with some of them.
|
||||
* elements in the block at aRange if given style matches with some of them.
|
||||
*
|
||||
* @param aStartPoint Start of range to split ancestor inline elements.
|
||||
* @param aEndPoint End of range to split ancestor inline elements.
|
||||
* @param aRange Ancestor inline elements of the start and end boundaries
|
||||
* will be split.
|
||||
* @param aProperty The style tag name which you want to split. Set
|
||||
* nullptr if you want to split any styled elements.
|
||||
* @param aAttribute Attribute name if aProperty has some styles like
|
||||
* nsGkAtoms::font.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT SplitRangeOffResult
|
||||
SplitAncestorStyledInlineElementsAtRangeEdges(
|
||||
const EditorDOMPoint& aStartPoint, const EditorDOMPoint& aEndPoint,
|
||||
nsAtom* aProperty, nsAtom* aAttribute);
|
||||
SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange& aRange,
|
||||
nsAtom* aProperty,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
/**
|
||||
* SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
|
||||
|
|
|
@ -911,35 +911,27 @@ Result<EditorDOMPoint, nsresult> HTMLEditor::SetInlinePropertyOnNode(
|
|||
}
|
||||
|
||||
SplitRangeOffResult HTMLEditor::SplitAncestorStyledInlineElementsAtRangeEdges(
|
||||
const EditorDOMPoint& aStartOfRange, const EditorDOMPoint& aEndOfRange,
|
||||
nsAtom* aProperty, nsAtom* aAttribute) {
|
||||
const EditorDOMRange& aRange, nsAtom* aProperty, nsAtom* aAttribute) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
if (NS_WARN_IF(!aStartOfRange.IsSet()) || NS_WARN_IF(!aEndOfRange.IsSet())) {
|
||||
return SplitRangeOffResult(NS_ERROR_INVALID_ARG);
|
||||
if (NS_WARN_IF(!aRange.IsPositioned())) {
|
||||
return SplitRangeOffResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
EditorDOMPoint startOfRange(aStartOfRange);
|
||||
EditorDOMPoint endOfRange(aEndOfRange);
|
||||
EditorDOMRange range(aRange);
|
||||
|
||||
// split any matching style nodes above the start of range
|
||||
SplitNodeResult resultAtStart = [&]() MOZ_CAN_RUN_SCRIPT {
|
||||
AutoTrackDOMPoint tracker(RangeUpdaterRef(), &endOfRange);
|
||||
AutoTrackDOMRange tracker(RangeUpdaterRef(), &range);
|
||||
SplitNodeResult result = SplitAncestorStyledInlineElementsAt(
|
||||
startOfRange, aProperty, aAttribute);
|
||||
range.StartRef(), aProperty, aAttribute);
|
||||
if (result.isErr()) {
|
||||
NS_WARNING("HTMLEditor::SplitAncestorStyledInlineElementsAt() failed");
|
||||
return SplitNodeResult(result.unwrapErr());
|
||||
}
|
||||
nsresult rv = result.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SplitNodeResult::SuggestCaretPointTo() failed");
|
||||
return SplitNodeResult(rv);
|
||||
}
|
||||
tracker.FlushAndStopTracking();
|
||||
if (result.Handled()) {
|
||||
startOfRange = result.AtSplitPoint<EditorDOMPoint>();
|
||||
auto startOfRange = result.AtSplitPoint<EditorDOMPoint>();
|
||||
if (!startOfRange.IsSet()) {
|
||||
result.IgnoreCaretPointSuggestion();
|
||||
NS_WARNING(
|
||||
|
@ -947,6 +939,7 @@ SplitRangeOffResult HTMLEditor::SplitAncestorStyledInlineElementsAtRangeEdges(
|
|||
"split point");
|
||||
return SplitNodeResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
range.SetStart(std::move(startOfRange));
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
@ -956,22 +949,16 @@ SplitRangeOffResult HTMLEditor::SplitAncestorStyledInlineElementsAtRangeEdges(
|
|||
|
||||
// second verse, same as the first...
|
||||
SplitNodeResult resultAtEnd = [&]() MOZ_CAN_RUN_SCRIPT {
|
||||
AutoTrackDOMPoint tracker(RangeUpdaterRef(), &startOfRange);
|
||||
SplitNodeResult result =
|
||||
SplitAncestorStyledInlineElementsAt(endOfRange, aProperty, aAttribute);
|
||||
AutoTrackDOMRange tracker(RangeUpdaterRef(), &range);
|
||||
SplitNodeResult result = SplitAncestorStyledInlineElementsAt(
|
||||
range.EndRef(), aProperty, aAttribute);
|
||||
if (result.isErr()) {
|
||||
NS_WARNING("HTMLEditor::SplitAncestorStyledInlineElementsAt() failed");
|
||||
return SplitNodeResult(result.unwrapErr());
|
||||
}
|
||||
nsresult rv = result.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SplitNodeResult::SuggestCaretPointTo() failed");
|
||||
return SplitNodeResult(rv);
|
||||
}
|
||||
tracker.FlushAndStopTracking();
|
||||
if (result.Handled()) {
|
||||
endOfRange = result.AtSplitPoint<EditorDOMPoint>();
|
||||
auto endOfRange = result.AtSplitPoint<EditorDOMPoint>();
|
||||
if (!endOfRange.IsSet()) {
|
||||
result.IgnoreCaretPointSuggestion();
|
||||
NS_WARNING(
|
||||
|
@ -979,15 +966,17 @@ SplitRangeOffResult HTMLEditor::SplitAncestorStyledInlineElementsAtRangeEdges(
|
|||
"split point");
|
||||
return SplitNodeResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
range.SetEnd(std::move(endOfRange));
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
if (resultAtEnd.isErr()) {
|
||||
resultAtStart.IgnoreCaretPointSuggestion();
|
||||
return SplitRangeOffResult(resultAtEnd.unwrapErr());
|
||||
}
|
||||
|
||||
return SplitRangeOffResult(std::move(startOfRange), std::move(resultAtStart),
|
||||
std::move(endOfRange), std::move(resultAtEnd));
|
||||
return SplitRangeOffResult(std::move(range), std::move(resultAtStart),
|
||||
std::move(resultAtEnd));
|
||||
}
|
||||
|
||||
SplitNodeResult HTMLEditor::SplitAncestorStyledInlineElementsAt(
|
||||
|
@ -2232,8 +2221,7 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
|||
// them as appropriate
|
||||
SplitRangeOffResult splitRangeOffResult =
|
||||
SplitAncestorStyledInlineElementsAtRangeEdges(
|
||||
EditorDOMPoint(range->StartRef()),
|
||||
EditorDOMPoint(range->EndRef()), MOZ_KnownLive(style.mProperty),
|
||||
EditorDOMRange(range), MOZ_KnownLive(style.mProperty),
|
||||
MOZ_KnownLive(style.mAttribute));
|
||||
if (splitRangeOffResult.isErr()) {
|
||||
NS_WARNING(
|
||||
|
@ -2241,21 +2229,21 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
|||
"failed");
|
||||
return splitRangeOffResult.unwrapErr();
|
||||
}
|
||||
// Ignore caret suggestion because of dontChangeMySelection.
|
||||
splitRangeOffResult.IgnoreCaretPointSuggestion();
|
||||
|
||||
// XXX Modifying `range` means that we may modify ranges in `Selection`.
|
||||
// Is this intentional? Note that the range may be not in
|
||||
// `Selection` too. It seems that at least one of them is not
|
||||
// an unexpected case.
|
||||
const EditorDOMPoint& startOfRange(
|
||||
splitRangeOffResult.SplitPointAtStart());
|
||||
const EditorDOMPoint& endOfRange(splitRangeOffResult.SplitPointAtEnd());
|
||||
if (NS_WARN_IF(!startOfRange.IsSet()) ||
|
||||
NS_WARN_IF(!endOfRange.IsSet())) {
|
||||
const EditorDOMRange& splitRange = splitRangeOffResult.RangeRef();
|
||||
if (NS_WARN_IF(!splitRange.IsPositioned())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsresult rv = range->SetStartAndEnd(startOfRange.ToRawRangeBoundary(),
|
||||
endOfRange.ToRawRangeBoundary());
|
||||
nsresult rv =
|
||||
range->SetStartAndEnd(splitRange.StartRef().ToRawRangeBoundary(),
|
||||
splitRange.EndRef().ToRawRangeBoundary());
|
||||
// Note that modifying a range in `Selection` may run script so that
|
||||
// we might have been destroyed here.
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
|
@ -2268,34 +2256,37 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
|||
|
||||
// Collect editable nodes which are entirely contained in the range.
|
||||
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContents;
|
||||
if (startOfRange.GetContainer() == endOfRange.GetContainer() &&
|
||||
startOfRange.IsInTextNode()) {
|
||||
if (!EditorUtils::IsEditableContent(*startOfRange.ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
if (splitRange.InSameContainer() &&
|
||||
splitRange.StartRef().IsInTextNode()) {
|
||||
if (!EditorUtils::IsEditableContent(
|
||||
*splitRange.StartRef().ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
continue;
|
||||
}
|
||||
arrayOfContents.AppendElement(*startOfRange.ContainerAs<Text>());
|
||||
} else if (startOfRange.IsInTextNode() && endOfRange.IsInTextNode() &&
|
||||
startOfRange.GetContainer()->GetNextSibling() ==
|
||||
endOfRange.GetContainer()) {
|
||||
if (EditorUtils::IsEditableContent(*startOfRange.ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(*startOfRange.ContainerAs<Text>());
|
||||
}
|
||||
if (EditorUtils::IsEditableContent(*endOfRange.ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(*endOfRange.ContainerAs<Text>());
|
||||
}
|
||||
if (arrayOfContents.IsEmpty()) {
|
||||
arrayOfContents.AppendElement(
|
||||
*splitRange.StartRef().ContainerAs<Text>());
|
||||
} else if (splitRange.IsInTextNodes() &&
|
||||
splitRange.InAdjacentSiblings()) {
|
||||
// Adjacent siblings are in a same element, so the editable state of
|
||||
// both text nodes are always same.
|
||||
if (!EditorUtils::IsEditableContent(
|
||||
*splitRange.StartRef().ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
continue;
|
||||
}
|
||||
arrayOfContents.AppendElement(
|
||||
*splitRange.StartRef().ContainerAs<Text>());
|
||||
arrayOfContents.AppendElement(
|
||||
*splitRange.EndRef().ContainerAs<Text>());
|
||||
} else {
|
||||
// Append first node if it's a text node but selected not entirely.
|
||||
if (startOfRange.IsInTextNode() &&
|
||||
!startOfRange.IsStartOfContainer() &&
|
||||
EditorUtils::IsEditableContent(*startOfRange.ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(*startOfRange.ContainerAs<Text>());
|
||||
if (splitRange.StartRef().IsInTextNode() &&
|
||||
!splitRange.StartRef().IsStartOfContainer() &&
|
||||
EditorUtils::IsEditableContent(
|
||||
*splitRange.StartRef().ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(
|
||||
*splitRange.StartRef().ContainerAs<Text>());
|
||||
}
|
||||
// Append all entirely selected nodes.
|
||||
ContentSubtreeIterator subtreeIter;
|
||||
|
@ -2313,11 +2304,13 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
|||
}
|
||||
}
|
||||
// Append last node if it's a text node but selected not entirely.
|
||||
if (startOfRange.GetContainer() != endOfRange.GetContainer() &&
|
||||
endOfRange.IsInTextNode() && !endOfRange.IsEndOfContainer() &&
|
||||
EditorUtils::IsEditableContent(*endOfRange.ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(*endOfRange.ContainerAs<Text>());
|
||||
if (!splitRange.InSameContainer() &&
|
||||
splitRange.EndRef().IsInTextNode() &&
|
||||
!splitRange.EndRef().IsEndOfContainer() &&
|
||||
EditorUtils::IsEditableContent(
|
||||
*splitRange.EndRef().ContainerAs<Text>(), EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(
|
||||
*splitRange.EndRef().ContainerAs<Text>());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2385,11 +2378,11 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
|||
// don't join text nodes when removing a style. Therefore, there
|
||||
// may be multiple text nodes as adjacent siblings. That's the
|
||||
// reason why we need to handle text nodes in this loop.
|
||||
uint32_t startOffset = content == startOfRange.GetContainer()
|
||||
? startOfRange.Offset()
|
||||
uint32_t startOffset = content == splitRange.StartRef().GetContainer()
|
||||
? splitRange.StartRef().Offset()
|
||||
: 0;
|
||||
uint32_t endOffset = content == endOfRange.GetContainer()
|
||||
? endOfRange.Offset()
|
||||
uint32_t endOffset = content == splitRange.EndRef().GetContainer()
|
||||
? splitRange.EndRef().Offset()
|
||||
: content->Length();
|
||||
nsresult rv = SetInlinePropertyOnTextNode(
|
||||
MOZ_KnownLive(*content->AsText()), startOffset, endOffset,
|
||||
|
|
|
@ -399,14 +399,21 @@ class MOZ_STACK_CLASS AutoTrackDOMRange final {
|
|||
mStartPointTracker.emplace(aRangeUpdater, &mStartPoint);
|
||||
mEndPointTracker.emplace(aRangeUpdater, &mEndPoint);
|
||||
}
|
||||
~AutoTrackDOMRange() {
|
||||
if (!mRangeRefPtr && !mRangeOwningNonNull) {
|
||||
// The destructor of the trackers will update automatically.
|
||||
~AutoTrackDOMRange() { FlushAndStopTracking(); }
|
||||
|
||||
void FlushAndStopTracking() {
|
||||
if (!mStartPointTracker || !mEndPointTracker) {
|
||||
return;
|
||||
}
|
||||
// Otherwise, destroy them now.
|
||||
mStartPointTracker.reset();
|
||||
mEndPointTracker.reset();
|
||||
if (!mRangeRefPtr && !mRangeOwningNonNull) {
|
||||
// This must be created with EditorDOMRange or EditorDOMPoints. In the
|
||||
// cases, destroying mStartPointTracker and mEndPointTracker has done
|
||||
// everything which we need to do.
|
||||
return;
|
||||
}
|
||||
// Otherwise, update the DOM ranges by ourselves.
|
||||
if (mRangeRefPtr) {
|
||||
(*mRangeRefPtr)
|
||||
->SetStartAndEnd(mStartPoint.ToRawRangeBoundary(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче