Bug 1781994 - part 8: Make `HTMLEditor::SetInlinePropertyAsSubAction` handle multiple styles once r=m_kato

Depends on D154349

Differential Revision: https://phabricator.services.mozilla.com/D154350
This commit is contained in:
Masayuki Nakano 2022-08-16 01:01:05 +00:00
Родитель 5b2fd01232
Коммит 648f892bde
5 изменённых файлов: 128 добавлений и 66 удалений

Просмотреть файл

@ -117,9 +117,10 @@ class WSScanResult; // WSRunObject.h
* structs
******************************************************************************/
struct EditorInlineStyle; // HTMLEditHelpers.h
struct PropItem; // mozilla/TypeInState.h
struct RangeItem; // mozilla/SelectionState.h
struct EditorInlineStyle; // HTMLEditHelpers.h
struct EditorInlineStyleAndValue; // HTMLEditHelpers.h
struct PropItem; // mozilla/TypeInState.h
struct RangeItem; // mozilla/SelectionState.h
/******************************************************************************
* template classes

Просмотреть файл

@ -1234,6 +1234,40 @@ struct MOZ_STACK_CLASS EditorInlineStyle {
EditorInlineStyle() = default;
};
/******************************************************************************
* EditorInlineStyleAndValue represents an inline style and stores its value.
******************************************************************************/
struct MOZ_STACK_CLASS EditorInlineStyleAndValue : public EditorInlineStyle {
// Stores the value of mAttribute.
nsString const mAttributeValue;
bool IsStyleToClearAllInlineStyles() const = delete;
EditorInlineStyleAndValue() = delete;
explicit EditorInlineStyleAndValue(nsStaticAtom& aHTMLProperty)
: EditorInlineStyle(aHTMLProperty) {}
EditorInlineStyleAndValue(nsStaticAtom& aHTMLProperty, nsAtom& aAttribute,
const nsAString& aValue)
: EditorInlineStyle(aHTMLProperty, &aAttribute),
mAttributeValue(aValue) {}
EditorInlineStyleAndValue(nsStaticAtom& aHTMLProperty,
RefPtr<nsAtom>&& aAttribute,
const nsAString& aValue)
: EditorInlineStyle(aHTMLProperty, std::move(aAttribute)),
mAttributeValue(aValue) {
MOZ_ASSERT(mAttribute);
}
EditorInlineStyleAndValue(nsStaticAtom& aHTMLProperty, nsAtom& aAttribute,
nsString&& aValue)
: EditorInlineStyle(aHTMLProperty, &aAttribute),
mAttributeValue(std::move(aValue)) {}
EditorInlineStyleAndValue(nsStaticAtom& aHTMLProperty,
RefPtr<nsAtom>&& aAttribute, nsString&& aValue)
: EditorInlineStyle(aHTMLProperty, std::move(aAttribute)),
mAttributeValue(aValue) {}
};
} // namespace mozilla
#endif // #ifndef mozilla_HTMLEditHelpers_h

Просмотреть файл

@ -3388,34 +3388,31 @@ nsresult HTMLEditor::InsertLinkAroundSelectionAsAction(
return NS_ERROR_FAILURE;
}
uint32_t count = attributeMap->Length();
nsAutoString value;
for (uint32_t i = 0; i < count; ++i) {
// XXX nsDOMAttributeMap::Item() accesses current attribute at the index.
// Therefore, if `SetInlinePropertyAsSubAction()` changed the
// attributes, this may fail to scan some attributes. Perhaps, we need
// to cache all attributes first.
// TODO: We should stop using this loop for adding attributes to newly created
// `<a href="...">` elements. Then, we can avoid to increate the ref-
// counter of attribute names since we can use nsStaticAtom if we don't
// need to support unknown attributes.
AutoTArray<EditorInlineStyleAndValue, 32> stylesToSet;
stylesToSet.SetCapacity(attributeMap->Length());
nsString value;
for (uint32_t i : IntegerRange(attributeMap->Length())) {
RefPtr<Attr> attribute = attributeMap->Item(i);
if (!attribute) {
continue;
}
// We must clear the string buffers
// because GetValue appends to previous string!
value.Truncate();
nsAtom* attributeName = attribute->NodeInfo()->NameAtom();
RefPtr<nsAtom> attributeName = attribute->NodeInfo()->NameAtom();
MOZ_ASSERT(value.IsEmpty());
attribute->GetValue(value);
nsresult rv = SetInlinePropertyAsSubAction(
*nsGkAtoms::a, MOZ_KnownLive(attributeName), value);
if (NS_FAILED(rv)) {
NS_WARNING("SetInlinePropertyAsSubAction(nsGkAtoms::a) failed");
return rv;
}
stylesToSet.AppendElement(EditorInlineStyleAndValue(
*nsGkAtoms::a, std::move(attributeName), std::move(value)));
}
return NS_OK;
rv = SetInlinePropertiesAsSubAction(stylesToSet);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::SetInlinePropertiesAsSubAction() failed");
return rv;
}
nsresult HTMLEditor::SetHTMLBackgroundColorWithTransaction(
@ -5666,7 +5663,7 @@ nsresult HTMLEditor::SetCSSBackgroundColorWithTransaction(
AutoTransactionsConserveSelection dontChangeMySelection(*this);
// Loop through the ranges in the selection
// XXX This is different from `SetInlinePropertyAsSubAction()`. It uses
// XXX This is different from `SetInlinePropertiesAsSubAction()`. 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.

Просмотреть файл

@ -486,8 +486,8 @@ class HTMLEditor final : public EditorBase,
* called by system.
*/
MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertyAsAction(
nsAtom& aProperty, nsAtom* aAttribute, const nsAString& aValue,
nsIPrincipal* aPrincipal = nullptr);
nsStaticAtom& aProperty, nsStaticAtom* aAttribute,
const nsAString& aValue, nsIPrincipal* aPrincipal = nullptr);
/**
* GetInlineProperty() gets aggregate properties of the current selection.
@ -3298,19 +3298,16 @@ class HTMLEditor final : public EditorBase,
Document& aDocument, const nsACString& aCharacterSet);
/**
* SetInlinePropertyAsSubAction() stores new style with `mTypeInState` if
* `Selection` is collapsed. Otherwise, applying the style at all selection
* ranges.
* SetInlinePropertiesAsSubAction() stores new styles with mTypeInState if
* `Selection` is collapsed. Otherwise, applying the styles to all selected
* contents.
*
* @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.
* @param aStylesToSet The styles which should be applied to the
* selected content.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertyAsSubAction(nsAtom& aHTMLProperty, nsAtom* aAttribute,
const nsAString& aAttributeValue);
template <size_t N>
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetInlinePropertiesAsSubAction(
const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet);
/**
* RemoveInlinePropertiesAsSubAction() removes specified styles from

Просмотреть файл

@ -57,8 +57,13 @@ using LeafNodeType = HTMLEditUtils::LeafNodeType;
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
using WalkTreeOption = HTMLEditUtils::WalkTreeOption;
nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
nsAtom* aAttribute,
template nsresult HTMLEditor::SetInlinePropertiesAsSubAction(
const AutoTArray<EditorInlineStyleAndValue, 1>& aStylesToSet);
template nsresult HTMLEditor::SetInlinePropertiesAsSubAction(
const AutoTArray<EditorInlineStyleAndValue, 32>& aStylesToSet);
nsresult HTMLEditor::SetInlinePropertyAsAction(nsStaticAtom& aProperty,
nsStaticAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aPrincipal) {
AutoEditActionDataSetter editActionData(
@ -91,9 +96,9 @@ nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
AutoPlaceholderBatch treatAsOneTransaction(*this, ScrollSelectionIntoView::No,
__FUNCTION__);
nsAtom* property = &aProperty;
nsAtom* attribute = aAttribute;
nsAutoString value(aValue);
nsStaticAtom* property = &aProperty;
nsStaticAtom* attribute = aAttribute;
nsString value(aValue);
AutoTArray<EditorInlineStyle, 1> stylesToRemove;
if (&aProperty == nsGkAtoms::sup) {
@ -135,17 +140,21 @@ nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
}
}
rv = SetInlinePropertyAsSubAction(MOZ_KnownLive(*property),
MOZ_KnownLive(attribute), value);
AutoTArray<EditorInlineStyleAndValue, 1> styleToSet;
styleToSet.AppendElement(
attribute
? EditorInlineStyleAndValue(*property, *attribute, std::move(value))
: EditorInlineStyleAndValue(*property));
rv = SetInlinePropertiesAsSubAction(styleToSet);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::SetInlinePropertyAsSubAction() failed");
"HTMLEditor::SetInlinePropertiesAsSubAction() failed");
return EditorBase::ToGenericNSResult(rv);
}
NS_IMETHODIMP HTMLEditor::SetInlineProperty(const nsAString& aProperty,
const nsAString& aAttribute,
const nsAString& aValue) {
RefPtr<nsAtom> property = NS_Atomize(aProperty);
nsStaticAtom* property = NS_GetStaticAtom(aProperty);
if (NS_WARN_IF(!property)) {
return NS_ERROR_INVALID_ARG;
}
@ -172,21 +181,22 @@ NS_IMETHODIMP HTMLEditor::SetInlineProperty(const nsAString& aProperty,
"CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
return EditorBase::ToGenericNSResult(rv);
}
rv =
SetInlinePropertyAsSubAction(*property, MOZ_KnownLive(attribute), aValue);
AutoTArray<EditorInlineStyleAndValue, 1> styleToSet;
styleToSet.AppendElement(
attribute ? EditorInlineStyleAndValue(*property, *attribute, aValue)
: EditorInlineStyleAndValue(*property));
rv = SetInlinePropertiesAsSubAction(styleToSet);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::SetInlinePropertyAsSubAction() failed");
"HTMLEditor::SetInlinePropertiesAsSubAction() failed");
return EditorBase::ToGenericNSResult(rv);
}
nsresult HTMLEditor::SetInlinePropertyAsSubAction(
nsAtom& aHTMLProperty, nsAtom* aAttribute,
const nsAString& aAttributeValue) {
template <size_t N>
nsresult HTMLEditor::SetInlinePropertiesAsSubAction(
const AutoTArray<EditorInlineStyleAndValue, N>& aStylesToSet) {
MOZ_ASSERT(IsEditActionDataAvailable());
if (NS_WARN_IF(!mInitSucceeded)) {
return NS_ERROR_NOT_INITIALIZED;
}
MOZ_ASSERT(!aStylesToSet.IsEmpty());
DebugOnly<nsresult> rvIgnored = CommitComposition();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
@ -195,7 +205,10 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
if (SelectionRef().IsCollapsed()) {
// Manipulating text attributes on a collapsed selection only sets state
// for the next text insertion
mTypeInState->SetProp(&aHTMLProperty, aAttribute, aAttributeValue);
for (const EditorInlineStyleAndValue& styleToSet : aStylesToSet) {
mTypeInState->SetProp(styleToSet.mHTMLProperty, styleToSet.mAttribute,
styleToSet.mAttributeValue);
}
return NS_OK;
}
@ -229,7 +242,14 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
AutoTransactionsConserveSelection dontChangeMySelection(*this);
AutoRangeArray selectionRanges(SelectionRef());
{ // TODO: This block keeps the following line history after part.8
for (const EditorInlineStyleAndValue& styleToSet : aStylesToSet) {
// The ranges may be updated by changing the DOM tree. In strictly
// speaking, we should save and restore the ranges at every range loop,
// but we've never done so and it may be expensive if there are a lot of
// ranges. Therefore, we should do it for every style handling for now.
// TODO: We should collect everything required for removing the style before
// touching the DOM tree. Then, we need to save and restore the
// ranges only once.
MOZ_ALWAYS_TRUE(selectionRanges.SaveAndTrackRanges(*this));
for (const OwningNonNull<nsRange>& selectionRange :
selectionRanges.Ranges()) {
@ -248,11 +268,15 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
// If range is in a text node, apply new style simply.
if (range.InSameContainer() && range.StartRef().IsInTextNode()) {
// MOZ_KnownLive(...ContainerAs<Text>()) because of grabbed by `range`.
// MOZ_KnownLive(styleToSet.*) due to bug 1622253.
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
SetInlinePropertyOnTextNode(
MOZ_KnownLive(*range.StartRef().ContainerAs<Text>()),
range.StartRef().Offset(), range.EndRef().Offset(),
aHTMLProperty, aAttribute, aAttributeValue);
MOZ_KnownLive(*styleToSet.mHTMLProperty),
MOZ_KnownLive(styleToSet.mAttribute),
styleToSet.mAttributeValue);
if (wrapTextInStyledElementResult.isErr()) {
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
return wrapTextInStyledElementResult.unwrapErr();
@ -291,12 +315,16 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
if (range.StartRef().IsInTextNode() &&
EditorUtils::IsEditableContent(*range.StartRef().ContainerAs<Text>(),
EditorType::HTML)) {
// MOZ_KnownLive(...ContainerAs<Text>()) because of grabbed by `range`.
// MOZ_KnownLive(styleToSet.*) due to bug 1622253.
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
SetInlinePropertyOnTextNode(
MOZ_KnownLive(*range.StartRef().ContainerAs<Text>()),
range.StartRef().Offset(),
range.StartRef().ContainerAs<Text>()->TextDataLength(),
aHTMLProperty, aAttribute, aAttributeValue);
MOZ_KnownLive(*styleToSet.mHTMLProperty),
MOZ_KnownLive(styleToSet.mAttribute),
styleToSet.mAttributeValue);
if (wrapTextInStyledElementResult.isErr()) {
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
return wrapTextInStyledElementResult.unwrapErr();
@ -308,11 +336,12 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
// Then, apply new style to all nodes in the range entirely.
for (auto& content : arrayOfContentsAroundRange) {
// MOZ_KnownLive because 'arrayOfContentsAroundRange' guarantees to
// keep it alive.
// MOZ_KnownLive due to bug 1622253.
Result<EditorDOMPoint, nsresult> setStyleResult =
SetInlinePropertyOnNode(MOZ_KnownLive(*content), aHTMLProperty,
aAttribute, aAttributeValue);
SetInlinePropertyOnNode(MOZ_KnownLive(*content),
MOZ_KnownLive(*styleToSet.mHTMLProperty),
MOZ_KnownLive(styleToSet.mAttribute),
styleToSet.mAttributeValue);
if (MOZ_UNLIKELY(setStyleResult.isErr())) {
NS_WARNING("HTMLEditor::SetInlinePropertyOnNode() failed");
return setStyleResult.unwrapErr();
@ -325,11 +354,15 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
if (range.EndRef().IsInTextNode() &&
EditorUtils::IsEditableContent(*range.EndRef().ContainerAs<Text>(),
EditorType::HTML)) {
// MOZ_KnownLive(...ContainerAs<Text>()) because of grabbed by `range`.
// MOZ_KnownLive(styleToSet.mAttribute) due to bug 1622253.
SplitRangeOffFromNodeResult wrapTextInStyledElementResult =
SetInlinePropertyOnTextNode(
MOZ_KnownLive(*range.EndRef().ContainerAs<Text>()), 0,
range.EndRef().Offset(), aHTMLProperty, aAttribute,
aAttributeValue);
range.EndRef().Offset(),
MOZ_KnownLive(*styleToSet.mHTMLProperty),
MOZ_KnownLive(styleToSet.mAttribute),
styleToSet.mAttributeValue);
if (wrapTextInStyledElementResult.isErr()) {
NS_WARNING("HTMLEditor::SetInlinePropertyOnTextNode() failed");
return wrapTextInStyledElementResult.unwrapErr();
@ -339,11 +372,11 @@ nsresult HTMLEditor::SetInlinePropertyAsSubAction(
wrapTextInStyledElementResult.IgnoreCaretPointSuggestion();
}
}
MOZ_ASSERT(selectionRanges.HasSavedRanges());
selectionRanges.RestoreFromSavedRanges();
}
MOZ_ASSERT(!selectionRanges.HasSavedRanges());
nsresult rv = selectionRanges.ApplyTo(SelectionRef());
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;