Bug 1627175 - part 55: Move `HTMLEditor::IsEmptyInlineNode()` and `HTMLEditor::IsEmptyOneHardLine()` to `HTMLEditUtils` r=m_kato

Differential Revision: https://phabricator.services.mozilla.com/D115164
This commit is contained in:
Masayuki Nakano 2021-05-17 08:38:55 +00:00
Родитель 38e52dd665
Коммит b6ea40871b
7 изменённых файлов: 80 добавлений и 80 удалений

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

@ -85,8 +85,8 @@ class EditorDOMPointBase final {
: mParent(nullptr), mChild(nullptr), mIsChildInitialized(false) {}
template <typename ContainerType>
EditorDOMPointBase(ContainerType* aContainer, int32_t aOffset)
: mParent(aContainer),
EditorDOMPointBase(const ContainerType* aContainer, int32_t aOffset)
: mParent(const_cast<ContainerType*>(aContainer)),
mChild(nullptr),
mOffset(mozilla::Some(aOffset)),
mIsChildInitialized(false) {

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

@ -2527,7 +2527,8 @@ EditActionResult HTMLEditor::ChangeSelectedHardLinesToList(
bool bOnlyBreaks = true;
for (auto& content : arrayOfContents) {
// if content is not a Break or empty inline, we're done
if (!content->IsHTMLElement(nsGkAtoms::br) && !IsEmptyInlineNode(content)) {
if (!content->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsEmptyInlineContent(content)) {
bOnlyBreaks = false;
break;
}
@ -2647,7 +2648,8 @@ EditActionResult HTMLEditor::ChangeSelectedHardLinesToList(
// list item element.
// If current node is an empty inline node, just delete it.
if (EditorUtils::IsEditableContent(content, EditorType::HTML) &&
(content->IsHTMLElement(nsGkAtoms::br) || IsEmptyInlineNode(content))) {
(content->IsHTMLElement(nsGkAtoms::br) ||
HTMLEditUtils::IsEmptyInlineContent(content))) {
nsresult rv = DeleteNodeWithTransaction(*content);
if (NS_WARN_IF(Destroyed())) {
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
@ -3097,7 +3099,7 @@ nsresult HTMLEditor::FormatBlockContainerWithTransaction(nsAtom& blockType) {
// If there is no visible and editable nodes in the edit targets, make an
// empty block.
// XXX Isn't this odd if there are only non-editable visible nodes?
if (IsEmptyOneHardLine(arrayOfContents)) {
if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) {
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
@ -3555,7 +3557,7 @@ nsresult HTMLEditor::HandleCSSIndentAtSelectionInternal() {
// If there is no visible and editable nodes in the edit targets, make an
// empty block.
// XXX Isn't this odd if there are only non-editable visible nodes?
if (IsEmptyOneHardLine(arrayOfContents)) {
if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) {
// get selection location
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
@ -3776,7 +3778,7 @@ nsresult HTMLEditor::HandleHTMLIndentAtSelectionInternal() {
// If there is no visible and editable nodes in the edit targets, make an
// empty block.
// XXX Isn't this odd if there are only non-editable visible nodes?
if (IsEmptyOneHardLine(arrayOfContents)) {
if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) {
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
@ -9365,7 +9367,7 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
// If there is no visible and editable nodes in the edit targets, make an
// empty block.
// XXX Isn't this odd if there are only non-editable visible nodes?
if (IsEmptyOneHardLine(arrayOfContents)) {
if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) {
const nsRange* firstRange = SelectionRef().GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;

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

@ -204,7 +204,7 @@ bool HTMLEditUtils::IsHeader(nsINode& aNode) {
/**
* IsListItem() returns true if aNode is an html list item.
*/
bool HTMLEditUtils::IsListItem(nsINode* aNode) {
bool HTMLEditUtils::IsListItem(const nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsAnyOfHTMLElements(nsGkAtoms::li, nsGkAtoms::dd,
nsGkAtoms::dt);
@ -248,7 +248,7 @@ bool HTMLEditUtils::IsTableRow(nsINode* aNode) {
/**
* IsTableCell() returns true if aNode is an html td or th.
*/
bool HTMLEditUtils::IsTableCell(nsINode* aNode) {
bool HTMLEditUtils::IsTableCell(const nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th);
}
@ -302,7 +302,7 @@ bool HTMLEditUtils::IsLink(nsINode* aNode) {
return !tmpText.IsEmpty();
}
bool HTMLEditUtils::IsNamedAnchor(nsINode* aNode) {
bool HTMLEditUtils::IsNamedAnchor(const nsINode* aNode) {
MOZ_ASSERT(aNode);
if (!aNode->IsHTMLElement(nsGkAtoms::a)) {
return false;
@ -350,7 +350,7 @@ bool HTMLEditUtils::IsMailCite(nsINode* aNode) {
/**
* IsFormWidget() returns true if aNode is a form widget of some kind.
*/
bool HTMLEditUtils::IsFormWidget(nsINode* aNode) {
bool HTMLEditUtils::IsFormWidget(const nsINode* aNode) {
MOZ_ASSERT(aNode);
return aNode->IsAnyOfHTMLElements(nsGkAtoms::textarea, nsGkAtoms::select,
nsGkAtoms::button, nsGkAtoms::output,
@ -366,13 +366,13 @@ bool HTMLEditUtils::SupportsAlignAttr(nsINode& aNode) {
nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6);
}
bool HTMLEditUtils::IsVisibleTextNode(Text& aText,
Element* aEditingHost /* = nullptr */) {
bool HTMLEditUtils::IsVisibleTextNode(
const Text& aText, const Element* aEditingHost /* = nullptr */) {
if (!aText.TextDataLength()) {
return false;
}
if (!aText.TextIsOnlyWhitespace()) {
if (!const_cast<Text&>(aText).TextIsOnlyWhitespace()) {
return true;
}
@ -388,7 +388,7 @@ bool HTMLEditUtils::IsVisibleTextNode(Text& aText,
}
bool HTMLEditUtils::IsInVisibleTextFrames(nsPresContext* aPresContext,
Text& aText) {
const Text& aText) {
MOZ_ASSERT(aPresContext);
nsIFrame* frame = aText.GetPrimaryFrame();
@ -417,7 +417,7 @@ bool HTMLEditUtils::IsInVisibleTextFrames(nsPresContext* aPresContext,
// bug 46209.)
bool isVisible = false;
rv = selectionController->CheckVisibilityContent(
&aText, 0, aText.TextDataLength(), &isVisible);
const_cast<Text*>(&aText), 0, aText.TextDataLength(), &isVisible);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"nsISelectionController::CheckVisibilityContent() failed");
@ -489,7 +489,8 @@ bool HTMLEditUtils::IsVisibleBRElement(
.ReachedBlockBoundary();
}
bool HTMLEditUtils::IsEmptyNode(nsPresContext* aPresContext, nsINode& aNode,
bool HTMLEditUtils::IsEmptyNode(nsPresContext* aPresContext,
const nsINode& aNode,
const EmptyCheckOptions& aOptions /* = {} */,
bool* aSeenBR /* = nullptr */) {
MOZ_ASSERT_IF(aOptions.contains(EmptyCheckOption::SafeToAskLayout),
@ -506,7 +507,7 @@ bool HTMLEditUtils::IsEmptyNode(nsPresContext* aPresContext, nsINode& aNode,
*aNode.AsContent())
: nullptr;
if (Text* text = Text::FromNode(&aNode)) {
if (const Text* text = Text::FromNode(&aNode)) {
return aOptions.contains(EmptyCheckOption::SafeToAskLayout)
? !IsInVisibleTextFrames(aPresContext, *text)
: !IsVisibleTextNode(*text, maybeParentBlockElement);

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

@ -120,21 +120,21 @@ class HTMLEditUtils final {
static bool IsFormatNode(nsINode* aNode);
static bool IsNodeThatCanOutdent(nsINode* aNode);
static bool IsHeader(nsINode& aNode);
static bool IsListItem(nsINode* aNode);
static bool IsListItem(const nsINode* aNode);
static bool IsTable(nsINode* aNode);
static bool IsTableRow(nsINode* aNode);
static bool IsAnyTableElement(nsINode* aNode);
static bool IsAnyTableElementButNotTable(nsINode* aNode);
static bool IsTableCell(nsINode* node);
static bool IsTableCell(const nsINode* aNode);
static bool IsTableCellOrCaption(nsINode& aNode);
static bool IsAnyListElement(nsINode* aNode);
static bool IsPre(nsINode* aNode);
static bool IsImage(nsINode* aNode);
static bool IsLink(nsINode* aNode);
static bool IsNamedAnchor(nsINode* aNode);
static bool IsNamedAnchor(const nsINode* aNode);
static bool IsMozDiv(nsINode* aNode);
static bool IsMailCite(nsINode* aNode);
static bool IsFormWidget(nsINode* aNode);
static bool IsFormWidget(const nsINode* aNode);
static bool SupportsAlignAttr(nsINode& aNode);
static bool CanNodeContain(const nsINode& aParent, const nsIContent& aChild) {
@ -252,15 +252,15 @@ class HTMLEditUtils final {
* But if you call this a lot, please specify proper editing host (or parent
* block) for the performance.
*/
static bool IsVisibleTextNode(dom::Text& aText,
Element* aEditingHost = nullptr);
static bool IsVisibleTextNode(const dom::Text& aText,
const Element* aEditingHost = nullptr);
/**
* IsInVisibleTextFrames() returns true if all text in aText is in visible
* text frames. Callers have to guarantee that there is no pending reflow.
*/
static bool IsInVisibleTextFrames(nsPresContext* aPresContext,
dom::Text& aText);
const dom::Text& aText);
/**
* IsVisibleBRElement() and IsInvisibleBRElement() return true if aContent is
@ -298,16 +298,59 @@ class HTMLEditUtils final {
SafeToAskLayout,
};
using EmptyCheckOptions = EnumSet<EmptyCheckOption, uint32_t>;
static bool IsEmptyNode(nsPresContext* aPresContext, nsINode& aNode,
static bool IsEmptyNode(nsPresContext* aPresContext, const nsINode& aNode,
const EmptyCheckOptions& aOptions = {},
bool* aSeenBR = nullptr);
static bool IsEmptyNode(nsINode& aNode,
static bool IsEmptyNode(const nsINode& aNode,
const EmptyCheckOptions& aOptions = {},
bool* aSeenBR = nullptr) {
MOZ_ASSERT(!aOptions.contains(EmptyCheckOption::SafeToAskLayout));
return IsEmptyNode(nullptr, aNode, aOptions, aSeenBR);
}
/**
* IsEmptyInlineContent() returns true if aContent is an inline node and it
* does not have meaningful content.
*/
static bool IsEmptyInlineContent(const nsIContent& aContent) {
return HTMLEditUtils::IsInlineElement(aContent) &&
HTMLEditUtils::IsContainerNode(aContent) &&
HTMLEditUtils::IsEmptyNode(
aContent, {EmptyCheckOption::TreatSingleBRElementAsVisible});
}
/**
* IsEmptyOneHardLine() returns true if aArrayOfContents does not represent
* 2 or more lines and have meaningful content.
*/
static bool IsEmptyOneHardLine(
nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents) {
if (NS_WARN_IF(aArrayOfContents.IsEmpty())) {
return true;
}
bool brElementHasFound = false;
for (OwningNonNull<nsIContent>& content : aArrayOfContents) {
if (!EditorUtils::IsEditableContent(content,
EditorUtils::EditorType::HTML)) {
continue;
}
if (content->IsHTMLElement(nsGkAtoms::br)) {
// If there are 2 or more `<br>` elements, it's not empty line since
// there may be only one `<br>` element in a hard line.
if (brElementHasFound) {
return false;
}
brElementHasFound = true;
continue;
}
if (!HTMLEditUtils::IsEmptyInlineContent(content)) {
return false;
}
}
return true;
}
/**
* IsPointAtEdgeOfLink() returns true if aPoint is at start or end of a
* link.

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

@ -899,17 +899,6 @@ NS_IMETHODIMP HTMLEditor::NodeIsBlock(nsINode* aNode, bool* aIsBlock) {
return NS_OK;
}
bool HTMLEditor::IsEmptyInlineNode(nsIContent& aContent) const {
MOZ_ASSERT(IsEditActionDataAvailable());
if (!HTMLEditUtils::IsInlineElement(aContent) ||
!HTMLEditUtils::IsContainerNode(aContent)) {
return false;
}
return HTMLEditUtils::IsEmptyNode(
aContent, {EmptyCheckOption::TreatSingleBRElementAsVisible});
}
/**
* IsNextCharInNodeWhiteSpace() checks the adjacent content in the same node to
* see if following selection is white-space or nbsp.

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

@ -1442,43 +1442,6 @@ class HTMLEditor final : public TextEditor,
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
/**
* IsEmptyInlineNode() returns true if aContent is an inline node and it does
* not have meaningful content.
*/
bool IsEmptyInlineNode(nsIContent& aContent) const;
/**
* IsEmptyOneHardLine() returns true if aArrayOfContents does not represent
* 2 or more lines and have meaningful content.
*/
bool IsEmptyOneHardLine(
nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents) const {
if (NS_WARN_IF(aArrayOfContents.IsEmpty())) {
return true;
}
bool brElementHasFound = false;
for (OwningNonNull<nsIContent>& content : aArrayOfContents) {
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
continue;
}
if (content->IsHTMLElement(nsGkAtoms::br)) {
// If there are 2 or more `<br>` elements, it's not empty line since
// there may be only one `<br>` element in a hard line.
if (brElementHasFound) {
return false;
}
brElementHasFound = true;
continue;
}
if (!IsEmptyInlineNode(content)) {
return false;
}
}
return true;
}
/**
* MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
* aStartOfDeepestRightNode can have an element whose tag name is aTag.

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

@ -283,10 +283,10 @@ class MOZ_STACK_CLASS WSRunScanner final {
using WSType = WSScanResult::WSType;
template <typename EditorDOMPointType>
WSRunScanner(dom::Element* aEditingHost,
WSRunScanner(const dom::Element* aEditingHost,
const EditorDOMPointType& aScanStartPoint)
: mScanStartPoint(aScanStartPoint),
mEditingHost(aEditingHost),
mEditingHost(const_cast<dom::Element*>(aEditingHost)),
mTextFragmentDataAtStart(mScanStartPoint, mEditingHost) {}
// ScanNextVisibleNodeOrBlockBoundaryForwardFrom() returns the first visible
@ -298,7 +298,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
const EditorDOMPointBase<PT, CT>& aPoint) const;
template <typename PT, typename CT>
static WSScanResult ScanNextVisibleNodeOrBlockBoundary(
dom::Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
const dom::Element* aEditingHost,
const EditorDOMPointBase<PT, CT>& aPoint) {
return WSRunScanner(aEditingHost, aPoint)
.ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint);
}
@ -312,7 +313,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
const EditorDOMPointBase<PT, CT>& aPoint) const;
template <typename PT, typename CT>
static WSScanResult ScanPreviousVisibleNodeOrBlockBoundary(
dom::Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
const dom::Element* aEditingHost,
const EditorDOMPointBase<PT, CT>& aPoint) {
return WSRunScanner(aEditingHost, aPoint)
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint);
}