зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1460509 - part 23: Make HTMLEditRules::RemoveListStructure() return NS_ERROR_EDITOR_DESTROYED if it causes destroying the editor r=m_kato
MozReview-Commit-ID: JLfjjtQS6Ar --HG-- extra : rebase_source : a62dcf9cfa48c7c361efd80f76af7032703205e2
This commit is contained in:
Родитель
cf3ad1d97a
Коммит
3608fb3fbd
|
@ -400,7 +400,10 @@ HTMLEditRules::BeforeEdit(EditAction aAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that selection is in subtree defined by body node
|
// Check that selection is in subtree defined by body node
|
||||||
ConfirmSelectionInBody();
|
nsresult rv = ConfirmSelectionInBody();
|
||||||
|
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
// Let rules remember the top level action
|
// Let rules remember the top level action
|
||||||
mTheAction = aAction;
|
mTheAction = aAction;
|
||||||
}
|
}
|
||||||
|
@ -464,7 +467,11 @@ HTMLEditRules::AfterEditInner(EditAction aAction,
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
|
||||||
ConfirmSelectionInBody();
|
nsresult rv = ConfirmSelectionInBody();
|
||||||
|
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to normalize Selection");
|
||||||
if (aAction == EditAction::ignore) {
|
if (aAction == EditAction::ignore) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -582,9 +589,7 @@ HTMLEditRules::AfterEditInner(EditAction aAction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv =
|
rv = HTMLEditorRef().HandleInlineSpellCheck(aAction, SelectionRef(),
|
||||||
HTMLEditorRef().HandleInlineSpellCheck(
|
|
||||||
aAction, SelectionRef(),
|
|
||||||
mRangeItem->mStartContainer,
|
mRangeItem->mStartContainer,
|
||||||
mRangeItem->mStartOffset,
|
mRangeItem->mStartOffset,
|
||||||
rangeStartContainer,
|
rangeStartContainer,
|
||||||
|
@ -9312,44 +9317,68 @@ HTMLEditRules::PopListItem(nsIContent& aListItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditRules::RemoveListStructure(Element& aList)
|
HTMLEditRules::RemoveListStructure(Element& aListElement)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsEditorDataAvailable());
|
MOZ_ASSERT(IsEditorDataAvailable());
|
||||||
|
MOZ_ASSERT(HTMLEditUtils::IsList(&aListElement));
|
||||||
|
|
||||||
while (aList.GetFirstChild()) {
|
while (aListElement.GetFirstChild()) {
|
||||||
OwningNonNull<nsIContent> child = *aList.GetFirstChild();
|
OwningNonNull<nsIContent> child = *aListElement.GetFirstChild();
|
||||||
|
|
||||||
if (HTMLEditUtils::IsListItem(child)) {
|
if (HTMLEditUtils::IsListItem(child)) {
|
||||||
bool isOutOfList;
|
bool isOutOfList;
|
||||||
// Keep popping it out until it's not in a list anymore
|
// Keep popping it out until it's not in a list anymore
|
||||||
|
// XXX Using PopuListItem() is too expensive for this purpose. Looks
|
||||||
|
// like the reason why this method uses it is, only this loop
|
||||||
|
// wants to work with first child of aList. However, what it
|
||||||
|
// actually does is removing <li> as container. So, just using
|
||||||
|
// RemoveBlockContainerWithTransaction() is reasonable.
|
||||||
|
// XXX This loop means that if aListElement is is a child of another
|
||||||
|
// list element (although it's invalid tree), this moves the
|
||||||
|
// list item to outside of aListElement's parent. Is that really
|
||||||
|
// intentional behavior?
|
||||||
do {
|
do {
|
||||||
nsresult rv = PopListItem(child, &isOutOfList);
|
nsresult rv = PopListItem(child, &isOutOfList);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
} while (!isOutOfList);
|
} while (!isOutOfList);
|
||||||
} else if (HTMLEditUtils::IsList(child)) {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HTMLEditUtils::IsList(child)) {
|
||||||
nsresult rv = RemoveListStructure(*child->AsElement());
|
nsresult rv = RemoveListStructure(*child->AsElement());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete any non-list items for now
|
// Delete any non-list items for now
|
||||||
|
// XXX This is not HTML5 aware. HTML5 allows all list elements to have
|
||||||
|
// <script> and <template> and <dl> element to have <div> to group
|
||||||
|
// some <dt> and <dd> elements. So, this may break valid children.
|
||||||
nsresult rv = HTMLEditorRef().DeleteNodeWithTransaction(*child);
|
nsresult rv = HTMLEditorRef().DeleteNodeWithTransaction(*child);
|
||||||
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the now-empty list
|
// Delete the now-empty list
|
||||||
nsresult rv = HTMLEditorRef().RemoveBlockContainerWithTransaction(aList);
|
nsresult rv =
|
||||||
|
HTMLEditorRef().RemoveBlockContainerWithTransaction(aListElement);
|
||||||
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX This method is not necessary because even if selection is outside the
|
|
||||||
// <body> element, the element can be editable.
|
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditRules::ConfirmSelectionInBody()
|
HTMLEditRules::ConfirmSelectionInBody()
|
||||||
{
|
{
|
||||||
|
@ -9377,6 +9406,9 @@ HTMLEditRules::ConfirmSelectionInBody()
|
||||||
if (!temp) {
|
if (!temp) {
|
||||||
IgnoredErrorResult ignoredError;
|
IgnoredErrorResult ignoredError;
|
||||||
SelectionRef().Collapse(RawRangeBoundary(rootElement, 0), ignoredError);
|
SelectionRef().Collapse(RawRangeBoundary(rootElement, 0), ignoredError);
|
||||||
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||||
"Failed to collapse selection at start of the root element");
|
"Failed to collapse selection at start of the root element");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -9398,6 +9430,9 @@ HTMLEditRules::ConfirmSelectionInBody()
|
||||||
if (!temp) {
|
if (!temp) {
|
||||||
IgnoredErrorResult ignoredError;
|
IgnoredErrorResult ignoredError;
|
||||||
SelectionRef().Collapse(RawRangeBoundary(rootElement, 0), ignoredError);
|
SelectionRef().Collapse(RawRangeBoundary(rootElement, 0), ignoredError);
|
||||||
|
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||||
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
|
}
|
||||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||||
"Failed to collapse selection at start of the root element");
|
"Failed to collapse selection at start of the root element");
|
||||||
}
|
}
|
||||||
|
|
|
@ -558,7 +558,21 @@ protected:
|
||||||
|
|
||||||
Element* GetTopEnclosingMailCite(nsINode& aNode);
|
Element* GetTopEnclosingMailCite(nsINode& aNode);
|
||||||
nsresult PopListItem(nsIContent& aListItem, bool* aOutOfList = nullptr);
|
nsresult PopListItem(nsIContent& aListItem, bool* aOutOfList = nullptr);
|
||||||
nsresult RemoveListStructure(Element& aList);
|
|
||||||
|
/**
|
||||||
|
* RemoveListStructure() destroys the list structure of aListElement.
|
||||||
|
* If aListElement has <li>, <dl> or <dt> as a child, the element is removed
|
||||||
|
* but its descendants are moved to where the list item element was.
|
||||||
|
* If aListElement has another <ul>, <ol> or <dl> as a child, this method
|
||||||
|
* is called recursively.
|
||||||
|
* If aListElement has other nodes as its child, they are just removed.
|
||||||
|
* Finally, aListElement is removed. and its all children are moved to
|
||||||
|
* where the aListElement was.
|
||||||
|
*
|
||||||
|
* @param aListElement A <ul>, <ol> or <dl> element.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE nsresult RemoveListStructure(Element& aListElement);
|
||||||
|
|
||||||
nsresult CacheInlineStyles(nsINode* aNode);
|
nsresult CacheInlineStyles(nsINode* aNode);
|
||||||
nsresult ReapplyCachedStyles();
|
nsresult ReapplyCachedStyles();
|
||||||
void ClearCachedStyles();
|
void ClearCachedStyles();
|
||||||
|
@ -595,7 +609,17 @@ protected:
|
||||||
nsresult RemoveEmptyNodes();
|
nsresult RemoveEmptyNodes();
|
||||||
nsresult SelectionEndpointInNode(nsINode* aNode, bool* aResult);
|
nsresult SelectionEndpointInNode(nsINode* aNode, bool* aResult);
|
||||||
nsresult UpdateDocChangeRange(nsRange* aRange);
|
nsresult UpdateDocChangeRange(nsRange* aRange);
|
||||||
nsresult ConfirmSelectionInBody();
|
|
||||||
|
/**
|
||||||
|
* ConfirmSelectionInBody() makes sure that Selection is in editor root
|
||||||
|
* element typically <body> element (see HTMLEditor::UpdateRootElement())
|
||||||
|
* and only one Selection range.
|
||||||
|
* XXX This method is not necessary because even if selection is outside the
|
||||||
|
* <body> element, elements outside the <body> element should be
|
||||||
|
* editable, e.g., any element can be inserted siblings as <body> element
|
||||||
|
* and other browsers allow to edit such elements.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE nsresult ConfirmSelectionInBody();
|
||||||
|
|
||||||
bool IsEmptyInline(nsINode& aNode);
|
bool IsEmptyInline(nsINode& aNode);
|
||||||
bool ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& arrayOfNodes);
|
bool ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& arrayOfNodes);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче