mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1781994 - part 6: Make HTMLEditor::SetInlinePropertyInternal
use AutoRangeArray
r=m_kato
Depends on D154347 Differential Revision: https://phabricator.services.mozilla.com/D154348
This commit is contained in:
parent
9d26dd1005
commit
da11385641
@ -3392,9 +3392,9 @@ nsresult HTMLEditor::InsertLinkAroundSelectionAsAction(
|
||||
nsAutoString value;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
// XXX nsDOMAttributeMap::Item() accesses current attribute at the index.
|
||||
// Therefore, if `SetInlinePropertyInternal()` changed the attributes,
|
||||
// this may fail to scan some attributes. Perhaps, we need to cache
|
||||
// all attributes first.
|
||||
// Therefore, if `SetInlinePropertyAsSubAction()` changed the
|
||||
// attributes, this may fail to scan some attributes. Perhaps, we need
|
||||
// to cache all attributes first.
|
||||
RefPtr<Attr> attribute = attributeMap->Item(i);
|
||||
if (!attribute) {
|
||||
continue;
|
||||
@ -3408,10 +3408,10 @@ nsresult HTMLEditor::InsertLinkAroundSelectionAsAction(
|
||||
|
||||
attribute->GetValue(value);
|
||||
|
||||
nsresult rv = SetInlinePropertyInternal(
|
||||
nsresult rv = SetInlinePropertyAsSubAction(
|
||||
*nsGkAtoms::a, MOZ_KnownLive(attributeName), value);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetInlinePropertyInternal(nsGkAtoms::a) failed");
|
||||
NS_WARNING("SetInlinePropertyAsSubAction(nsGkAtoms::a) failed");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -5666,8 +5666,8 @@ nsresult HTMLEditor::SetCSSBackgroundColorWithTransaction(
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(*this);
|
||||
|
||||
// Loop through the ranges in the selection
|
||||
// XXX This is different from `SetInlinePropertyInternal()`. It uses
|
||||
// AutoSelectionRangeArray to store all ranges first. The result may be
|
||||
// XXX This is different from `SetInlinePropertyAsSubAction()`. It uses
|
||||
// AutoRangeArray to store all ranges first. The result may be
|
||||
// different if mutation event listener changes the `Selection`.
|
||||
// TODO: Store all selection ranges first since this updates the style.
|
||||
for (uint32_t i = 0; i < SelectionRef().RangeCount(); i++) {
|
||||
|
@ -3298,18 +3298,19 @@ class HTMLEditor final : public EditorBase,
|
||||
Document& aDocument, const nsACString& aCharacterSet);
|
||||
|
||||
/**
|
||||
* SetInlinePropertyInternal() stores new style with `mTypeInState` if
|
||||
* SetInlinePropertyAsSubAction() stores new style with `mTypeInState` if
|
||||
* `Selection` is collapsed. Otherwise, applying the style at all selection
|
||||
* ranges.
|
||||
*
|
||||
* @param aProperty One of the presentation tag names which we
|
||||
* @param aHTMLProperty One of the presentation tag names which we
|
||||
* support in style editor.
|
||||
* @param aAttribute For some aProperty values, needs to be set to
|
||||
* its attribute name. Otherwise, nullptr.
|
||||
* @param aAttributeValue The value of aAttribute.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyInternal(
|
||||
nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aValue);
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
SetInlinePropertyAsSubAction(nsAtom& aHTMLProperty, nsAtom* aAttribute,
|
||||
const nsAString& aAttributeValue);
|
||||
|
||||
/**
|
||||
* RemoveInlinePropertyAsSubAction() removes specified style from
|
||||
|
@ -158,10 +158,10 @@ nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
|
||||
}
|
||||
}
|
||||
}
|
||||
rv = SetInlinePropertyInternal(MOZ_KnownLive(*property),
|
||||
MOZ_KnownLive(attribute), value);
|
||||
rv = SetInlinePropertyAsSubAction(MOZ_KnownLive(*property),
|
||||
MOZ_KnownLive(attribute), value);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::SetInlinePropertyInternal() failed");
|
||||
"HTMLEditor::SetInlinePropertyAsSubAction() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
|
||||
@ -195,14 +195,16 @@ NS_IMETHODIMP HTMLEditor::SetInlineProperty(const nsAString& aProperty,
|
||||
"CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
rv = SetInlinePropertyInternal(*property, MOZ_KnownLive(attribute), aValue);
|
||||
rv =
|
||||
SetInlinePropertyAsSubAction(*property, MOZ_KnownLive(attribute), aValue);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"HTMLEditor::SetInlinePropertyInternal() failed");
|
||||
"HTMLEditor::SetInlinePropertyAsSubAction() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aAttributeValue) {
|
||||
nsresult HTMLEditor::SetInlinePropertyAsSubAction(
|
||||
nsAtom& aHTMLProperty, nsAtom* aAttribute,
|
||||
const nsAString& aAttributeValue) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
if (NS_WARN_IF(!mInitSucceeded)) {
|
||||
@ -216,7 +218,7 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
if (SelectionRef().IsCollapsed()) {
|
||||
// Manipulating text attributes on a collapsed selection only sets state
|
||||
// for the next text insertion
|
||||
mTypeInState->SetProp(&aProperty, aAttribute, aAttributeValue);
|
||||
mTypeInState->SetProp(&aHTMLProperty, aAttribute, aAttributeValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -244,45 +246,36 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
!ignoredError.Failed(),
|
||||
"HTMLEditor::OnStartToHandleTopLevelEditSubAction() failed, but ignored");
|
||||
|
||||
{
|
||||
AutoSelectionRestorer restoreSelectionLater(*this);
|
||||
// TODO: We don't need AutoTransactionsConserveSelection here in the normal
|
||||
// cases, but removing this may cause the behavior with the legacy
|
||||
// mutation event listeners. We should try to delete this in a bug.
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(*this);
|
||||
// TODO: We don't need AutoTransactionsConserveSelection here in the normal
|
||||
// cases, but removing this may cause the behavior with the legacy
|
||||
// mutation event listeners. We should try to delete this in a bug.
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(*this);
|
||||
|
||||
// Loop through the ranges in the selection
|
||||
// XXX This is different from `SetCSSBackgroundColorWithTransaction()`.
|
||||
// It refers `Selection::GetRangeAt()` in each time. The result may
|
||||
// be different if mutation event listener changes the `Selection`.
|
||||
AutoSelectionRangeArray arrayOfRanges(SelectionRef());
|
||||
for (auto& range : arrayOfRanges.mRanges) {
|
||||
AutoRangeArray selectionRanges(SelectionRef());
|
||||
{ // TODO: This block keeps the following line history after part.8
|
||||
MOZ_ALWAYS_TRUE(selectionRanges.SaveAndTrackRanges(*this));
|
||||
for (const OwningNonNull<nsRange>& selectionRange :
|
||||
selectionRanges.Ranges()) {
|
||||
// Adjust range to include any ancestors whose children are entirely
|
||||
// selected
|
||||
nsresult rv = PromoteInlineRange(*range);
|
||||
nsresult rv = PromoteInlineRange(*selectionRange);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("HTMLEditor::PromoteInlineRange() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
// XXX Shouldn't we skip the range if it's been collapsed by mutation
|
||||
// event listener?
|
||||
|
||||
EditorDOMPoint startOfRange(range->StartRef());
|
||||
EditorDOMPoint endOfRange(range->EndRef());
|
||||
if (NS_WARN_IF(!startOfRange.IsSet()) ||
|
||||
NS_WARN_IF(!endOfRange.IsSet())) {
|
||||
EditorDOMRange range(selectionRange);
|
||||
if (NS_WARN_IF(!range.IsPositioned())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If range is in a text node, apply new style simply.
|
||||
if (startOfRange.GetContainer() == endOfRange.GetContainer() &&
|
||||
startOfRange.IsInTextNode()) {
|
||||
if (range.InSameContainer() && range.StartRef().IsInTextNode()) {
|
||||
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
|
||||
SetInlinePropertyOnTextNode(
|
||||
MOZ_KnownLive(*startOfRange.ContainerAs<Text>()),
|
||||
startOfRange.Offset(), endOfRange.Offset(), aProperty,
|
||||
aAttribute, aAttributeValue);
|
||||
MOZ_KnownLive(*range.StartRef().ContainerAs<Text>()),
|
||||
range.StartRef().Offset(), range.EndRef().Offset(),
|
||||
aHTMLProperty, aAttribute, aAttributeValue);
|
||||
if (wrapTextInStyledElementResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
|
||||
return wrapTextInStyledElementResult.unwrapErr();
|
||||
@ -294,33 +287,39 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
}
|
||||
|
||||
// Collect editable nodes which are entirely contained in the range.
|
||||
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContents;
|
||||
ContentSubtreeIterator subtreeIter;
|
||||
// If there is no node which is entirely in the range,
|
||||
// `ContentSubtreeIterator::Init()` fails, but this is possible case,
|
||||
// don't warn it.
|
||||
if (NS_SUCCEEDED(subtreeIter.Init(range))) {
|
||||
for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
|
||||
nsINode* node = subtreeIter.GetCurrentNode();
|
||||
if (NS_WARN_IF(!node)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (node->IsContent() && EditorUtils::IsEditableContent(
|
||||
*node->AsContent(), EditorType::HTML)) {
|
||||
arrayOfContents.AppendElement(*node->AsContent());
|
||||
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContentsAroundRange;
|
||||
{
|
||||
ContentSubtreeIterator subtreeIter;
|
||||
// If there is no node which is entirely in the range,
|
||||
// `ContentSubtreeIterator::Init()` fails, but this is possible case,
|
||||
// don't warn it.
|
||||
if (NS_SUCCEEDED(
|
||||
subtreeIter.Init(range.StartRef().ToRawRangeBoundary(),
|
||||
range.EndRef().ToRawRangeBoundary()))) {
|
||||
for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
|
||||
nsINode* node = subtreeIter.GetCurrentNode();
|
||||
if (NS_WARN_IF(!node)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (node->IsContent() &&
|
||||
EditorUtils::IsEditableContent(*node->AsContent(),
|
||||
EditorType::HTML)) {
|
||||
arrayOfContentsAroundRange.AppendElement(*node->AsContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If start node is a text node, apply new style to a part of it.
|
||||
if (startOfRange.IsInTextNode() &&
|
||||
EditorUtils::IsEditableContent(*startOfRange.ContainerAs<Text>(),
|
||||
if (range.StartRef().IsInTextNode() &&
|
||||
EditorUtils::IsEditableContent(*range.StartRef().ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
|
||||
SetInlinePropertyOnTextNode(
|
||||
MOZ_KnownLive(*startOfRange.ContainerAs<Text>()),
|
||||
startOfRange.Offset(), startOfRange.GetContainer()->Length(),
|
||||
aProperty, aAttribute, aAttributeValue);
|
||||
MOZ_KnownLive(*range.StartRef().ContainerAs<Text>()),
|
||||
range.StartRef().Offset(),
|
||||
range.StartRef().ContainerAs<Text>()->TextDataLength(),
|
||||
aHTMLProperty, aAttribute, aAttributeValue);
|
||||
if (wrapTextInStyledElementResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
|
||||
return wrapTextInStyledElementResult.unwrapErr();
|
||||
@ -331,11 +330,11 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
}
|
||||
|
||||
// Then, apply new style to all nodes in the range entirely.
|
||||
for (auto& content : arrayOfContents) {
|
||||
// MOZ_KnownLive because 'arrayOfContents' is guaranteed to
|
||||
for (auto& content : arrayOfContentsAroundRange) {
|
||||
// MOZ_KnownLive because 'arrayOfContentsAroundRange' guarantees to
|
||||
// keep it alive.
|
||||
Result<EditorDOMPoint, nsresult> setStyleResult =
|
||||
SetInlinePropertyOnNode(MOZ_KnownLive(*content), aProperty,
|
||||
SetInlinePropertyOnNode(MOZ_KnownLive(*content), aHTMLProperty,
|
||||
aAttribute, aAttributeValue);
|
||||
if (MOZ_UNLIKELY(setStyleResult.isErr())) {
|
||||
NS_WARNING("HTMLEditor::SetInlinePropertyOnNode() failed");
|
||||
@ -346,13 +345,14 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
}
|
||||
|
||||
// Finally, if end node is a text node, apply new style to a part of it.
|
||||
if (endOfRange.IsInTextNode() &&
|
||||
EditorUtils::IsEditableContent(*endOfRange.ContainerAs<Text>(),
|
||||
if (range.EndRef().IsInTextNode() &&
|
||||
EditorUtils::IsEditableContent(*range.EndRef().ContainerAs<Text>(),
|
||||
EditorType::HTML)) {
|
||||
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
|
||||
SetInlinePropertyOnTextNode(
|
||||
MOZ_KnownLive(*endOfRange.ContainerAs<Text>()), 0,
|
||||
endOfRange.Offset(), aProperty, aAttribute, aAttributeValue);
|
||||
MOZ_KnownLive(*range.EndRef().ContainerAs<Text>()), 0,
|
||||
range.EndRef().Offset(), aHTMLProperty, aAttribute,
|
||||
aAttributeValue);
|
||||
if (wrapTextInStyledElementResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
|
||||
return wrapTextInStyledElementResult.unwrapErr();
|
||||
@ -362,9 +362,17 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||
wrapTextInStyledElementResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(selectionRanges.HasSavedRanges());
|
||||
selectionRanges.RestoreFromSavedRanges();
|
||||
}
|
||||
// Restoring `Selection` may have destroyed us.
|
||||
return NS_WARN_IF(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : NS_OK;
|
||||
|
||||
nsresult rv = selectionRanges.ApplyTo(SelectionRef());
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AutoRangeArray::ApplyTo() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
Result<bool, nsresult> HTMLEditor::ElementIsGoodContainerForTheStyle(
|
||||
|
Loading…
Reference in New Issue
Block a user