commit b42dc9d35fc6d72432d156a76d4ee694e1577973
parent 86f575acd888168a411e05719eaaa654b12a0ee4
Author: Masayuki Nakano <masayuki@d-toybox.com>
Date: Wed, 7 Jan 2026 01:10:19 +0000
Bug 1998077 - part 1: Make `HTMLEditUtils::IsVisibleElementEvenIfLeafNode` work better if primary frame is available r=m_kato
If an inline frame is dirty due to a change in its child `Text`, the
width may have become 0. Then, checking the frame size may not match
with actual visibility after the next flush. Therefore, it should check
border and padding of inline frames if the frame is dirty.
Differential Revision: https://phabricator.services.mozilla.com/D277518
Diffstat:
2 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/editor/libeditor/HTMLEditUtils.cpp b/editor/libeditor/HTMLEditUtils.cpp
@@ -493,7 +493,11 @@ bool HTMLEditUtils::IsVisibleElementEvenIfLeafNode(const nsIContent& aContent) {
if (!aContent.IsHTMLElement()) {
return true;
}
- // XXX Should we return false if the element is display:none?
+ nsIFrame* const primaryFrame = aContent.GetPrimaryFrame();
+ if (primaryFrame && aContent.IsInComposedDoc() &&
+ HTMLEditUtils::IsInclusiveAncestorCSSDisplayNone(aContent)) {
+ return false;
+ }
if (HTMLEditUtils::IsBlockElement(
aContent, BlockInlineCheck::UseComputedDisplayStyle)) {
return true;
@@ -511,18 +515,19 @@ bool HTMLEditUtils::IsVisibleElementEvenIfLeafNode(const nsIContent& aContent) {
HTMLInputElement::FromNode(&aContent)) {
return inputElement->ControlType() != FormControlType::InputHidden;
}
- // If the element has a primary frame and it's not empty, the element is
- // visible.
- // XXX This method does not guarantee that the layout has already been
- // updated. Therefore, this check might be wrong in the edge cases.
- // However, basically, editor apps should not depend on this path, this
- // is required if last <br> before a block boundary becomes visible because
- // of followed by empty but styled frame like <span style=padding:1px></span>.
- if (aContent.GetPrimaryFrame() &&
- !aContent.GetPrimaryFrame()->GetSize().IsEmpty()) {
- return true;
+ if (primaryFrame) {
+ // If the frame is not dirty or non-inline container frame, we can trust
+ // whether the frame is empty or not.
+ if (!primaryFrame->IsSubtreeDirty() || !primaryFrame->IsInlineFrame()) {
+ return !primaryFrame->GetSize().IsEmpty();
+ }
+ // Otherwise, the inner content may have been changed by the editor or JS.
+ // Let's treat it's visible only when it has non-zero border or padding.
+ return !primaryFrame->IsSelfEmpty();
}
- // Maybe, empty inline element such as <span>.
+ // If aContent does not have a primary frame, it may be inserted to the
+ // document and has not been flushed the pending notifications. Then, we
+ // cannot know the actual style so that let's assume it's invisible.
return false;
}
diff --git a/editor/libeditor/HTMLEditUtils.h b/editor/libeditor/HTMLEditUtils.h
@@ -236,11 +236,13 @@ class HTMLEditUtils final {
BlockInlineCheck aBlockInlineCheck);
/**
- * IsVisibleElementEvenIfLeafNode() returns true if aContent is an empty block
- * element, a visible replaced element such as a form control. This does not
- * check the layout information.
+ * IsVisibleElementEvenIfLeafNode() returns true if aContent is a visible
+ * element when aContent is empty. If aContent has a primary frame (even if
+ * dirty), this checks whether aContent is actually visible. Otherwise, this
+ * guesses it from the element type.
*/
- static bool IsVisibleElementEvenIfLeafNode(const nsIContent& aContent);
+ [[nodiscard]] static bool IsVisibleElementEvenIfLeafNode(
+ const nsIContent& aContent);
/**
* Return true if aContent is an inline element which formats the content