Bug 1770877 - part 33: Make HTMLEditor::RelativeFontChangeOnTextNode stop touching Selection directly r=m_kato

Differential Revision: https://phabricator.services.mozilla.com/D149104
This commit is contained in:
Masayuki Nakano
2022-06-22 08:18:40 +00:00
parent 788f5cd59f
commit db9c8aa4f4
4 changed files with 154 additions and 139 deletions

View File

@@ -176,6 +176,10 @@ class MOZ_STACK_CLASS CreateNodeResultBase final {
// isErr() must not required to wrap with them.
bool isOk() const { return NS_SUCCEEDED(mRv); }
bool isErr() const { return NS_FAILED(mRv); }
bool Handled() const {
MOZ_ASSERT_IF(mRv == NS_SUCCESS_DOM_NO_OPERATION, !mNode);
return isOk() && mRv == NS_SUCCESS_DOM_NO_OPERATION;
}
constexpr nsresult inspectErr() const { return mRv; }
constexpr nsresult unwrapErr() const { return inspectErr(); }
constexpr bool EditorDestroyed() const {
@@ -220,8 +224,6 @@ class MOZ_STACK_CLASS CreateNodeResultBase final {
const EditorBase& aEditorBase,
const SuggestCaretOptions& aOptions);
CreateNodeResultBase() = delete;
explicit CreateNodeResultBase(nsresult aRv) : mRv(aRv) {
MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mRv));
}
@@ -252,6 +254,25 @@ class MOZ_STACK_CLASS CreateNodeResultBase final {
mCaretPoint(std::move(aCandidateCaretPoint)),
mRv(mNode.get() ? NS_OK : NS_ERROR_FAILURE) {}
[[nodiscard]] static SelfType NotHandled() {
SelfType result;
result.mRv = NS_SUCCESS_DOM_NO_OPERATION;
return result;
}
[[nodiscard]] static SelfType NotHandled(
const EditorDOMPoint& aPointToPutCaret) {
SelfType result;
result.mRv = NS_SUCCESS_DOM_NO_OPERATION;
result.mCaretPoint = aPointToPutCaret;
return result;
}
[[nodiscard]] static SelfType NotHandled(EditorDOMPoint&& aPointToPutCaret) {
SelfType result;
result.mRv = NS_SUCCESS_DOM_NO_OPERATION;
result.mCaretPoint = std::move(aPointToPutCaret);
return result;
}
#ifdef DEBUG
~CreateNodeResultBase() {
MOZ_ASSERT_IF(isOk(), !mCaretPoint.IsSet() || mHandledCaretPoint);
@@ -264,9 +285,11 @@ class MOZ_STACK_CLASS CreateNodeResultBase final {
SelfType& operator=(SelfType&& aOther) = default;
private:
CreateNodeResultBase() = default;
RefPtr<NodeType> mNode;
EditorDOMPoint mCaretPoint;
nsresult mRv;
nsresult mRv = NS_OK;
bool mutable mHandledCaretPoint = false;
};

View File

@@ -5850,16 +5850,28 @@ nsresult HTMLEditor::CreateStyleForInsertText(
// dir indicated bigger versus smaller. 1 = bigger, -1 = smaller
HTMLEditor::FontSize dir = relFontSize > 0 ? HTMLEditor::FontSize::incr
: HTMLEditor::FontSize::decr;
EditorDOMPoint pointToPutCaret;
for (int32_t j = 0; j < DeprecatedAbs(relFontSize); j++) {
nsresult rv =
CreateElementResult wrapTextInBigOrSmallElementResult =
RelativeFontChangeOnTextNode(dir, *newEmptyTextNode, 0, UINT32_MAX);
if (NS_WARN_IF(Destroyed())) {
if (wrapTextInBigOrSmallElementResult.isErr()) {
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
return wrapTextInBigOrSmallElementResult.unwrapErr();
}
wrapTextInBigOrSmallElementResult.MoveCaretPointTo(
pointToPutCaret, *this,
{SuggestCaret::OnlyIfHasSuggestion,
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
}
if (pointToPutCaret.IsSet()) {
nsresult rv = CollapseSelectionTo(pointToPutCaret);
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
return NS_ERROR_EDITOR_DESTROYED;
}
if (NS_FAILED(rv)) {
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
return rv;
}
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"EditorBase::CollapseSelectionTo() failed, but ignored");
}
}

View File

@@ -859,7 +859,7 @@ class HTMLEditor final : public EditorBase,
* Helper routines for font size changing.
*/
enum class FontSize { incr, decr };
MOZ_CAN_RUN_SCRIPT nsresult
[[nodiscard]] MOZ_CAN_RUN_SCRIPT CreateElementResult
RelativeFontChangeOnTextNode(FontSize aDir, Text& aTextNode,
uint32_t aStartOffset, uint32_t aEndOffset);

View File

@@ -2547,13 +2547,17 @@ nsresult HTMLEditor::RelativeFontChange(FontSize aDir) {
MOZ_ASSERT(startNode);
MOZ_ASSERT(endNode);
if (startNode == endNode && startNode->IsText()) {
nsresult rv = RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*startNode->GetAsText()), range->StartOffset(),
range->EndOffset());
if (NS_FAILED(rv)) {
CreateElementResult wrapWithBigOrSmallElementResult =
RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*startNode->GetAsText()),
range->StartOffset(), range->EndOffset());
if (wrapWithBigOrSmallElementResult.isErr()) {
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
return rv;
return wrapWithBigOrSmallElementResult.unwrapErr();
}
// There is an AutoTransactionsConserveSelection instance so that we don't
// need to update selection for this change.
wrapWithBigOrSmallElementResult.IgnoreCaretPointSuggestion();
} else {
// Not the easy case. Range not contained in single text node. There
// are up to three phases here. There are all the nodes reported by the
@@ -2599,22 +2603,30 @@ nsresult HTMLEditor::RelativeFontChange(FontSize aDir) {
// the subtree iterator works - it will not have reported them).
if (startNode->IsText() && EditorUtils::IsEditableContent(
*startNode->AsText(), EditorType::HTML)) {
nsresult rv = RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*startNode->AsText()), range->StartOffset(),
startNode->Length());
if (NS_FAILED(rv)) {
CreateElementResult wrapWithBigOrSmallElementResult =
RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*startNode->AsText()), range->StartOffset(),
startNode->Length());
if (wrapWithBigOrSmallElementResult.isErr()) {
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
return rv;
return wrapWithBigOrSmallElementResult.unwrapErr();
}
// There is an AutoTransactionsConserveSelection instance so that we
// don't need to update selection for this change.
wrapWithBigOrSmallElementResult.IgnoreCaretPointSuggestion();
}
if (endNode->IsText() && EditorUtils::IsEditableContent(
*endNode->AsText(), EditorType::HTML)) {
nsresult rv = RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*endNode->AsText()), 0, range->EndOffset());
if (NS_FAILED(rv)) {
CreateElementResult wrapWithBigOrSmallElementResult =
RelativeFontChangeOnTextNode(
aDir, MOZ_KnownLive(*endNode->AsText()), 0, range->EndOffset());
if (wrapWithBigOrSmallElementResult.isErr()) {
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
return rv;
return wrapWithBigOrSmallElementResult.unwrapErr();
}
// There is an AutoTransactionsConserveSelection instance so that we
// don't need to update selection for this change.
wrapWithBigOrSmallElementResult.IgnoreCaretPointSuggestion();
}
}
}
@@ -2622,19 +2634,18 @@ nsresult HTMLEditor::RelativeFontChange(FontSize aDir) {
return NS_OK;
}
nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
Text& aTextNode,
uint32_t aStartOffset,
uint32_t aEndOffset) {
CreateElementResult HTMLEditor::RelativeFontChangeOnTextNode(
FontSize aDir, Text& aTextNode, uint32_t aStartOffset,
uint32_t aEndOffset) {
// Don't need to do anything if no characters actually selected
if (aStartOffset == aEndOffset) {
return NS_OK;
return CreateElementResult::NotHandled();
}
if (!aTextNode.GetParentNode() ||
!HTMLEditUtils::CanNodeContain(*aTextNode.GetParentNode(),
*nsGkAtoms::big)) {
return NS_OK;
return CreateElementResult::NotHandled();
}
aEndOffset = std::min(aTextNode.Length(), aEndOffset);
@@ -2642,77 +2653,70 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
// Make the range an independent node.
RefPtr<Text> textNodeForTheRange = &aTextNode;
auto pointToPutCaretOrError =
[&]() MOZ_CAN_RUN_SCRIPT -> Result<EditorDOMPoint, nsresult> {
EditorDOMPoint pointToPutCaret;
// Split at the end of the range.
EditorDOMPoint atEnd(textNodeForTheRange, aEndOffset);
if (!atEnd.IsEndOfContainer()) {
// We need to split off back of text node
SplitNodeResult splitAtEndResult = SplitNodeWithTransaction(atEnd);
if (splitAtEndResult.isErr()) {
NS_WARNING("HTMLEditor::SplitNodeWithTransaction() failed");
return Err(splitAtEndResult.unwrapErr());
EditorDOMPoint pointToPutCaret;
{
auto pointToPutCaretOrError =
[&]() MOZ_CAN_RUN_SCRIPT -> Result<EditorDOMPoint, nsresult> {
EditorDOMPoint pointToPutCaret;
// Split at the end of the range.
EditorDOMPoint atEnd(textNodeForTheRange, aEndOffset);
if (!atEnd.IsEndOfContainer()) {
// We need to split off back of text node
SplitNodeResult splitAtEndResult = SplitNodeWithTransaction(atEnd);
if (splitAtEndResult.isErr()) {
NS_WARNING("HTMLEditor::SplitNodeWithTransaction() failed");
return Err(splitAtEndResult.unwrapErr());
}
if (MOZ_UNLIKELY(!splitAtEndResult.HasCaretPointSuggestion())) {
NS_WARNING(
"HTMLEditor::SplitNodeWithTransaction() didn't suggest caret "
"point");
return Err(NS_ERROR_FAILURE);
}
splitAtEndResult.MoveCaretPointTo(pointToPutCaret, *this, {});
MOZ_ASSERT_IF(AllowsTransactionsToChangeSelection(),
pointToPutCaret.IsSet());
textNodeForTheRange =
Text::FromNodeOrNull(splitAtEndResult.GetPreviousContent());
MOZ_DIAGNOSTIC_ASSERT(textNodeForTheRange);
// When adding caret suggestion to SplitNodeResult, here didn't change
// selection so that just ignore it.
splitAtEndResult.IgnoreCaretPointSuggestion();
}
if (MOZ_UNLIKELY(!splitAtEndResult.HasCaretPointSuggestion())) {
NS_WARNING(
"HTMLEditor::SplitNodeWithTransaction() didn't suggest caret "
"point");
return Err(NS_ERROR_FAILURE);
}
splitAtEndResult.MoveCaretPointTo(
pointToPutCaret, *this,
{SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
MOZ_ASSERT_IF(AllowsTransactionsToChangeSelection(),
pointToPutCaret.IsSet());
textNodeForTheRange =
Text::FromNodeOrNull(splitAtEndResult.GetPreviousContent());
MOZ_DIAGNOSTIC_ASSERT(textNodeForTheRange);
// When adding caret suggestion to SplitNodeResult, here didn't change
// selection so that just ignore it.
splitAtEndResult.IgnoreCaretPointSuggestion();
}
// Split at the start of the range.
EditorDOMPoint atStart(textNodeForTheRange, aStartOffset);
if (!atStart.IsStartOfContainer()) {
// We need to split off front of text node
SplitNodeResult splitAtStartResult = SplitNodeWithTransaction(atStart);
if (splitAtStartResult.isErr()) {
NS_WARNING("HTMLEditor::SplitNodeWithTransaction() failed");
return Err(splitAtStartResult.unwrapErr());
// Split at the start of the range.
EditorDOMPoint atStart(textNodeForTheRange, aStartOffset);
if (!atStart.IsStartOfContainer()) {
// We need to split off front of text node
SplitNodeResult splitAtStartResult = SplitNodeWithTransaction(atStart);
if (splitAtStartResult.isErr()) {
NS_WARNING("HTMLEditor::SplitNodeWithTransaction() failed");
return Err(splitAtStartResult.unwrapErr());
}
if (MOZ_UNLIKELY(!splitAtStartResult.HasCaretPointSuggestion())) {
NS_WARNING(
"HTMLEditor::SplitNodeWithTransaction() didn't suggest caret "
"point");
return Err(NS_ERROR_FAILURE);
}
splitAtStartResult.MoveCaretPointTo(pointToPutCaret, *this, {});
MOZ_ASSERT_IF(AllowsTransactionsToChangeSelection(),
pointToPutCaret.IsSet());
textNodeForTheRange =
Text::FromNodeOrNull(splitAtStartResult.GetNextContent());
MOZ_DIAGNOSTIC_ASSERT(textNodeForTheRange);
// When adding caret suggestion to SplitNodeResult, here didn't change
// selection so that just ignore it.
splitAtStartResult.IgnoreCaretPointSuggestion();
}
if (MOZ_UNLIKELY(!splitAtStartResult.HasCaretPointSuggestion())) {
NS_WARNING(
"HTMLEditor::SplitNodeWithTransaction() didn't suggest caret "
"point");
return Err(NS_ERROR_FAILURE);
}
splitAtStartResult.MoveCaretPointTo(
pointToPutCaret, *this,
{SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
MOZ_ASSERT_IF(AllowsTransactionsToChangeSelection(),
pointToPutCaret.IsSet());
textNodeForTheRange =
Text::FromNodeOrNull(splitAtStartResult.GetNextContent());
MOZ_DIAGNOSTIC_ASSERT(textNodeForTheRange);
// When adding caret suggestion to SplitNodeResult, here didn't change
// selection so that just ignore it.
splitAtStartResult.IgnoreCaretPointSuggestion();
}
return pointToPutCaret;
}();
if (MOZ_UNLIKELY(pointToPutCaretOrError.isErr())) {
// Don't warn here since it should be done in the lambda.
return pointToPutCaretOrError.unwrapErr();
}
if (pointToPutCaretOrError.inspect().IsSet()) {
nsresult rv = CollapseSelectionTo(pointToPutCaretOrError.inspect());
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
return rv;
return pointToPutCaret;
}();
if (MOZ_UNLIKELY(pointToPutCaretOrError.isErr())) {
// Don't warn here since it should be done in the lambda.
return CreateElementResult(pointToPutCaretOrError.unwrapErr());
}
pointToPutCaret = pointToPutCaretOrError.unwrap();
}
// Look for siblings that are correct type of node
@@ -2722,70 +2726,46 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
*textNodeForTheRange, {WalkTreeOption::IgnoreNonEditableNode});
if (sibling && sibling->IsHTMLElement(bigOrSmallTagName)) {
// Previous sib is already right kind of inline node; slide this over
const MoveNodeResult moveTextNodeResult =
MoveNodeResult moveTextNodeResult =
MoveNodeToEndWithTransaction(*textNodeForTheRange, *sibling);
if (moveTextNodeResult.isErr()) {
NS_WARNING("HTMLEditor::MoveNodeToEndWithTransaction() failed");
return moveTextNodeResult.unwrapErr();
return CreateElementResult(moveTextNodeResult.unwrapErr());
}
nsresult rv = moveTextNodeResult.SuggestCaretPointTo(
*this, {SuggestCaret::OnlyIfHasSuggestion,
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
SuggestCaret::AndIgnoreTrivialError});
if (NS_FAILED(rv)) {
NS_WARNING("MoveNodeResult::SuggestCaretPointTo() failed");
return rv;
}
NS_WARNING_ASSERTION(
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
"MoveNodeResult::SuggestCaretPointTo() failed, but ignored");
return NS_OK;
moveTextNodeResult.MoveCaretPointTo(pointToPutCaret, *this,
{SuggestCaret::OnlyIfHasSuggestion});
// XXX Should we return the new container?
return CreateElementResult::NotHandled(std::move(pointToPutCaret));
}
sibling = HTMLEditUtils::GetNextSibling(
*textNodeForTheRange, {WalkTreeOption::IgnoreNonEditableNode});
if (sibling && sibling->IsHTMLElement(bigOrSmallTagName)) {
// Following sib is already right kind of inline node; slide this over
const MoveNodeResult moveTextNodeResult = MoveNodeWithTransaction(
MoveNodeResult moveTextNodeResult = MoveNodeWithTransaction(
*textNodeForTheRange, EditorDOMPoint(sibling, 0u));
if (moveTextNodeResult.isErr()) {
NS_WARNING("HTMLEditor::MoveNodeWithTransaction() failed");
return moveTextNodeResult.unwrapErr();
return CreateElementResult(moveTextNodeResult.unwrapErr());
}
nsresult rv = moveTextNodeResult.SuggestCaretPointTo(
*this, {SuggestCaret::OnlyIfHasSuggestion,
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
SuggestCaret::AndIgnoreTrivialError});
if (NS_FAILED(rv)) {
NS_WARNING("MoveNodeResult::SuggestCaretPointTo() failed");
return rv;
}
NS_WARNING_ASSERTION(
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
"MoveNodeResult::SuggestCaretPointTo() failed, but ignored");
return NS_OK;
moveTextNodeResult.MoveCaretPointTo(pointToPutCaret, *this,
{SuggestCaret::OnlyIfHasSuggestion});
// XXX Should we return the new container?
return CreateElementResult::NotHandled(std::move(pointToPutCaret));
}
// Else wrap the node inside font node with appropriate relative size
const CreateElementResult wrapTextWithBigOrSmallElementResult =
CreateElementResult wrapTextWithBigOrSmallElementResult =
InsertContainerWithTransaction(*textNodeForTheRange,
MOZ_KnownLive(*bigOrSmallTagName));
if (wrapTextWithBigOrSmallElementResult.isErr()) {
NS_WARNING("HTMLEditor::InsertContainerWithTransaction() failed");
return wrapTextWithBigOrSmallElementResult.inspectErr();
return wrapTextWithBigOrSmallElementResult;
}
MOZ_ASSERT(wrapTextWithBigOrSmallElementResult.GetNewNode());
nsresult rv = wrapTextWithBigOrSmallElementResult.SuggestCaretPointTo(
*this, {SuggestCaret::OnlyIfHasSuggestion,
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
SuggestCaret::AndIgnoreTrivialError});
if (NS_FAILED(rv)) {
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
return rv;
}
NS_WARNING_ASSERTION(
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
"CreateElementResult::SuggestCaretPointTo() failed, but ignored");
return rv;
wrapTextWithBigOrSmallElementResult.MoveCaretPointTo(
pointToPutCaret, {SuggestCaret::OnlyIfHasSuggestion});
return CreateElementResult(
wrapTextWithBigOrSmallElementResult.UnwrapNewNode(),
std::move(pointToPutCaret));
}
nsresult HTMLEditor::RelativeFontChangeHelper(int32_t aSizeChange,