зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5b2fd01232
Коммит
648f892bde
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче