Bug 1851951 - Make `HTMLEditor` refer computed `display` instead of the HTML default style at considering block or inline element r=m_kato

Blink [1] and WebKit [2] refers `display-outside` value when they consider whether an
element is a block or an inline.

However, our editor refers HTML default style instead.  Therefore, our editor
cannot handle the following cases:
* If a container block is a non-HTML element whose `display` style is `block`.
* If a container `<div>` etc is styled as `inline` and typing `Enter` in it.
* If a container `<span>` is styled as `block` and it ends with spaces.

For making users get better result, we should follow the other browsers.

However, this is too risky change.  Therefore, this patch enables new behavior
only in the Nightly channel and early beta builds to collect feedback from
testers.

The big rules of checking block vs. inline are:
* When we handle block level edit actions such as formatting block, indenting
or outdenting selection, making or removing list, we should keep referring
the HTML default style because the other browsers do so and the commands are
intended for modifying the HTML structure.
* Otherwise, we should refer the computed style of the block.  However, if
working with non-connected elements, we may need a special handling that is
falling back to refer the HTML default style because `HTMLEditorDataTransfer`
work with non-connected document fragments.
* Finally, if we check visibility of collapsible white-spaces and `<br>`s, we
should refer computed style.  However, in this case, we may need to treat
ancestor `inline-block`s as block too, but for siblings, we should refer only
`display-outside`.

1. https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/editing_utilities.cc;l=779;drc=31fb07c05718d671d96c227855bfe97af9e3fb20
2. https://searchfox.org/wubkat/rev/b054636fffeffa0314914a11ce39725a3057131e/Source/WebCore/editing/Editing.cpp#317

Differential Revision: https://phabricator.services.mozilla.com/D188598
This commit is contained in:
Masayuki Nakano 2023-09-27 03:01:26 +00:00
Родитель 7488358a82
Коммит 09514edd73
25 изменённых файлов: 1325 добавлений и 661 удалений

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

@ -521,7 +521,8 @@ void AutoRangeArray::
Element* const maybeNonEditableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*aStartPoint.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestBlockElement);
HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayStyle);
if (!maybeNonEditableBlockElement) {
return;
}
@ -548,7 +549,7 @@ void AutoRangeArray::
* outside of editing host.
*/
static EditorDOMPoint
GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock(
GetPointAtFirstContentOfLineOrParentHTMLBlockIfFirstContentOfBlock(
const EditorDOMPoint& aPointInLine, EditSubAction aEditSubAction,
const Element& aEditingHost) {
// FYI: This was moved from
@ -586,12 +587,15 @@ GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock(
HTMLEditUtils::WalkTreeOption::IgnoreNonEditableNode,
HTMLEditUtils::WalkTreeOption::StopAtBlockBoundary};
for (nsIContent* previousEditableContent = HTMLEditUtils::GetPreviousContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost);
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost);
previousEditableContent && previousEditableContent->GetParentNode() &&
!HTMLEditUtils::IsVisibleBRElement(*previousEditableContent) &&
!HTMLEditUtils::IsBlockElement(*previousEditableContent);
!HTMLEditUtils::IsBlockElement(*previousEditableContent,
BlockInlineCheck::UseHTMLDefaultStyle);
previousEditableContent = HTMLEditUtils::GetPreviousContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost)) {
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) {
EditorDOMPoint atLastPreformattedNewLine =
HTMLEditUtils::GetPreviousPreformattedNewLineInTextNode<EditorDOMPoint>(
EditorRawDOMPoint::AtEndOf(*previousEditableContent));
@ -606,11 +610,13 @@ GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock(
// the container (typically, start of nearest block ancestor), and as long
// as we haven't hit the body node.
for (nsIContent* nearContent = HTMLEditUtils::GetPreviousContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost);
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost);
!nearContent && !point.IsContainerHTMLElement(nsGkAtoms::body) &&
point.GetContainerParent();
nearContent = HTMLEditUtils::GetPreviousContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost)) {
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) {
// Don't keep looking up if we have found a blockquote element to act on
// when we handle outdent.
// XXX Sounds like this is hacky. If possible, it should be check in
@ -658,7 +664,7 @@ GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock(
* If the line ends with a block boundary, returns the
* point of the block.
*/
static EditorDOMPoint GetPointAfterFollowingLineBreakOrAtFollowingBlock(
static EditorDOMPoint GetPointAfterFollowingLineBreakOrAtFollowingHTMLBlock(
const EditorDOMPoint& aPointInLine, const Element& aEditingHost) {
// FYI: This was moved from
// https://searchfox.org/mozilla-central/rev/3419858c997f422e3e70020a46baae7f0ec6dacc/editor/libeditor/HTMLEditSubActionHandler.cpp#6541
@ -682,7 +688,7 @@ static EditorDOMPoint GetPointAfterFollowingLineBreakOrAtFollowingBlock(
if (atNextPreformattedNewLine.IsSet()) {
// If the linefeed is last character of the text node, it may be
// invisible if it's immediately before a block boundary. In such
// case, we should retrun the block boundary.
// case, we should return the block boundary.
Element* maybeNonEditableBlockElement = nullptr;
if (HTMLEditUtils::IsInvisiblePreformattedNewLine(
atNextPreformattedNewLine, &maybeNonEditableBlockElement) &&
@ -730,19 +736,22 @@ static EditorDOMPoint GetPointAfterFollowingLineBreakOrAtFollowingBlock(
HTMLEditUtils::WalkTreeOption::IgnoreNonEditableNode,
HTMLEditUtils::WalkTreeOption::StopAtBlockBoundary};
for (nsIContent* nextEditableContent = HTMLEditUtils::GetNextContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost);
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost);
nextEditableContent &&
!HTMLEditUtils::IsBlockElement(*nextEditableContent) &&
!HTMLEditUtils::IsBlockElement(*nextEditableContent,
BlockInlineCheck::UseHTMLDefaultStyle) &&
nextEditableContent->GetParent();
nextEditableContent = HTMLEditUtils::GetNextContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost)) {
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) {
EditorDOMPoint atFirstPreformattedNewLine =
HTMLEditUtils::GetInclusiveNextPreformattedNewLineInTextNode<
EditorDOMPoint>(EditorRawDOMPoint(nextEditableContent, 0));
if (atFirstPreformattedNewLine.IsSet()) {
// If the linefeed is last character of the text node, it may be
// invisible if it's immediately before a block boundary. In such
// case, we should retrun the block boundary.
// case, we should return the block boundary.
Element* maybeNonEditableBlockElement = nullptr;
if (HTMLEditUtils::IsInvisiblePreformattedNewLine(
atFirstPreformattedNewLine, &maybeNonEditableBlockElement) &&
@ -780,11 +789,13 @@ static EditorDOMPoint GetPointAfterFollowingLineBreakOrAtFollowingBlock(
// container (typically, block node), and as long as we haven't hit the body
// node.
for (nsIContent* nearContent = HTMLEditUtils::GetNextContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost);
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost);
!nearContent && !point.IsContainerHTMLElement(nsGkAtoms::body) &&
point.GetContainerParent();
nearContent = HTMLEditUtils::GetNextContent(
point, ignoreNonEditableNodeAndStopAtBlockBoundary, &aEditingHost)) {
point, ignoreNonEditableNodeAndStopAtBlockBoundary,
BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) {
// Don't walk past the editable section. Note that we need to check before
// walking up to a parent because we need to return the parent object, so
// the parent itself might not be in the editable area, but it's OK.
@ -887,8 +898,9 @@ nsresult AutoRangeArray::ExtendRangeToWrapStartAndEndLinesContainingBoundaries(
// implement a method which checks both two DOM points in the editor
// root.
startPoint = GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock(
startPoint, aEditSubAction, aEditingHost);
startPoint =
GetPointAtFirstContentOfLineOrParentHTMLBlockIfFirstContentOfBlock(
startPoint, aEditSubAction, aEditingHost);
// XXX GetPointAtFirstContentOfLineOrParentBlockIfFirstContentOfBlock() may
// return point of editing host. Perhaps, we should change it and stop
// checking it here since this check may be expensive.
@ -899,8 +911,8 @@ nsresult AutoRangeArray::ExtendRangeToWrapStartAndEndLinesContainingBoundaries(
&aEditingHost)) {
return NS_ERROR_FAILURE;
}
endPoint =
GetPointAfterFollowingLineBreakOrAtFollowingBlock(endPoint, aEditingHost);
endPoint = GetPointAfterFollowingLineBreakOrAtFollowingHTMLBlock(
endPoint, aEditingHost);
const EditorDOMPoint lastRawPoint =
endPoint.IsStartOfContainer() ? endPoint : endPoint.PreviousPoint();
// XXX GetPointAfterFollowingLineBreakOrAtFollowingBlock() may return point of
@ -924,7 +936,8 @@ nsresult AutoRangeArray::ExtendRangeToWrapStartAndEndLinesContainingBoundaries(
Result<EditorDOMPoint, nsresult>
AutoRangeArray::SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries(
HTMLEditor& aHTMLEditor, const Element& aEditingHost,
HTMLEditor& aHTMLEditor, BlockInlineCheck aBlockInlineCheck,
const Element& aEditingHost,
const nsIContent* aAncestorLimiter /* = nullptr */) {
// FYI: The following code is originated in
// https://searchfox.org/mozilla-central/rev/c8e15e17bc6fd28f558c395c948a6251b38774ff/editor/libeditor/HTMLEditSubActionHandler.cpp#6971
@ -987,11 +1000,11 @@ AutoRangeArray::SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries(
for (const OwningNonNull<RangeItem>& item : Reversed(rangeItemArray)) {
// MOZ_KnownLive because 'rangeItemArray' is guaranteed to keep it alive.
Result<EditorDOMPoint, nsresult> splitParentsResult =
aHTMLEditor.SplitParentInlineElementsAtRangeBoundaries(
MOZ_KnownLive(*item), aEditingHost, aAncestorLimiter);
aHTMLEditor.SplitInlineAncestorsAtRangeBoundaries(
MOZ_KnownLive(*item), aBlockInlineCheck, aEditingHost,
aAncestorLimiter);
if (MOZ_UNLIKELY(splitParentsResult.isErr())) {
NS_WARNING(
"HTMLEditor::SplitParentInlineElementsAtRangeBoundaries() failed");
NS_WARNING("HTMLEditor::SplitInlineAncestorsAtRangeBoundaries() failed");
rv = splitParentsResult.unwrapErr();
break;
}
@ -1122,8 +1135,8 @@ nsresult AutoRangeArray::CollectEditTargetNodes(
HTMLEditUtils::GetInclusiveDeepestFirstChildWhichHasOneChild(
aOutArrayOfContents[0],
{HTMLEditUtils::WalkTreeOption::IgnoreNonEditableNode},
nsGkAtoms::div, nsGkAtoms::blockquote, nsGkAtoms::ul,
nsGkAtoms::ol, nsGkAtoms::dl);
BlockInlineCheck::Unused, nsGkAtoms::div, nsGkAtoms::blockquote,
nsGkAtoms::ul, nsGkAtoms::ol, nsGkAtoms::dl);
if (!deepestDivBlockquoteOrListElement) {
break;
}

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

@ -10,7 +10,8 @@
#include "EditorBase.h" // for EditorBase
#include "EditorDOMPoint.h" // for EditorDOMPoint, EditorDOMRange, etc
#include "EditorForwards.h"
#include "SelectionState.h" // for SelectionState
#include "HTMLEditHelpers.h" // for BlockInlineCheck
#include "SelectionState.h" // for SelectionState
#include "mozilla/ErrorResult.h" // for ErrorResult
#include "mozilla/IntegerRange.h" // for IntegerRange
@ -422,6 +423,8 @@ class MOZ_STACK_CLASS AutoRangeArray final {
* range. Finally, updates ranges to keep edit target ranges as expected.
*
* @param aHTMLEditor The HTMLEditor which will handle the splittings.
* @param aBlockInlineCheck Considering block vs inline with whether the
* computed style or the HTML default style.
* @param aElement The editing host.
* @param aAncestorLimiter A content node which you don't want this to
* split it.
@ -430,7 +433,8 @@ class MOZ_STACK_CLASS AutoRangeArray final {
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries(
HTMLEditor& aHTMLEditor, const dom::Element& aEditingHost,
HTMLEditor& aHTMLEditor, BlockInlineCheck aBlockInlineCheck,
const dom::Element& aEditingHost,
const nsIContent* aAncestorLimiter = nullptr);
/**

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

@ -4060,6 +4060,8 @@ EditorBase::CreateTransactionForCollapsedRange(
// of previous editable content.
nsIContent* previousEditableContent = HTMLEditUtils::GetPreviousContent(
*point.GetContainer(), {WalkTreeOption::IgnoreNonEditableNode},
IsTextEditor() ? BlockInlineCheck::UseHTMLDefaultStyle
: BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost);
if (!previousEditableContent) {
NS_WARNING("There was no editable content before the collapsed range");
@ -4108,6 +4110,8 @@ EditorBase::CreateTransactionForCollapsedRange(
// next editable content.
nsIContent* nextEditableContent = HTMLEditUtils::GetNextContent(
*point.GetContainer(), {WalkTreeOption::IgnoreNonEditableNode},
IsTextEditor() ? BlockInlineCheck::UseHTMLDefaultStyle
: BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost);
if (!nextEditableContent) {
NS_WARNING("There was no editable content after the collapsed range");
@ -4175,9 +4179,11 @@ EditorBase::CreateTransactionForCollapsedRange(
aHowToHandleCollapsedRange == HowToHandleCollapsedRange::ExtendBackward
? HTMLEditUtils::GetPreviousContent(
point, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost)
: HTMLEditUtils::GetNextContent(
point, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost);
if (!editableContent) {
NS_WARNING("There was no editable content around the collapsed range");
@ -4191,9 +4197,11 @@ EditorBase::CreateTransactionForCollapsedRange(
HowToHandleCollapsedRange::ExtendBackward
? HTMLEditUtils::GetPreviousContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost)
: HTMLEditUtils::GetNextContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
anonymousDivOrEditingHost);
}
if (!editableContent) {

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

@ -39,6 +39,7 @@ class Text;
* enum classes
******************************************************************************/
enum class BlockInlineCheck : uint8_t; // HTMLEditHelpers.h
enum class CollectChildrenOption; // HTMLEditUtils.h
enum class EditAction; // mozilla/EditAction.h
enum class EditorCommandParamType : uint16_t; // mozilla/EditorCommands.h

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

@ -15,7 +15,6 @@
#include "EditorDOMPoint.h"
#include "EditorForwards.h"
#include "EditorUtils.h" // for CaretPoint
#include "HTMLEditHelpers.h"
#include "JoinSplitNodeDirection.h"
#include "mozilla/AlreadyAddRefed.h"
@ -40,6 +39,41 @@ class nsISimpleEnumerator;
namespace mozilla {
enum class BlockInlineCheck : uint8_t {
// BlockInlineCheck is not expected by the root caller.
Unused,
// Refer only the HTML default style at considering whether block or inline.
// All non-HTML elements are treated as inline.
UseHTMLDefaultStyle,
// Refer the element's computed style of display-outside at considering
// whether block or inline.
// FYI: If editor.block_inline_check.use_computed_style pref is set to false,
// this is same as HTMLDefaultStyle.
UseComputedDisplayOutsideStyle,
// Refer the element's computed style of display at considering whether block
// or inline. I.e., this is a good value to look for any block boundary.
// E.g., this is proper value when:
// * Checking visibility of collapsible white-spaces or <br>
// * Looking for whether a padding <br> is required
// * Looking for a caret position
// FYI: If editor.block_inline_check.use_computed_style pref is set to false,
// this is same as HTMLDefaultStyle.
UseComputedDisplayStyle,
};
/**
* Even if the caller wants block boundary caused by display-inline: flow-root
* like inline-block, because it's required only when scanning from in it.
* I.e., if scanning needs to go to siblings, we don't want to treat
* inline-block siblings as inline.
*/
[[nodiscard]] inline BlockInlineCheck IgnoreInsideBlockBoundary(
BlockInlineCheck aBlockInlineCheck) {
return aBlockInlineCheck == BlockInlineCheck::UseComputedDisplayStyle
? BlockInlineCheck::UseComputedDisplayOutsideStyle
: aBlockInlineCheck;
}
enum class WithTransaction { No, Yes };
inline std::ostream& operator<<(std::ostream& aStream,
WithTransaction aWithTransaction) {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -15,11 +15,14 @@
#include "HTMLEditHelpers.h" // for EditorInlineStyle
#include "WSRunObject.h" // for WSRunScanner
#include "mozilla/ArrayUtils.h" // for ArrayLength
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
#include "mozilla/RangeUtils.h" // for RangeUtils
#include "mozilla/dom/Element.h" // for Element, nsINode
#include "mozilla/ArrayUtils.h" // for ArrayLength
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc.
#include "mozilla/StaticPrefs_editor.h" // for StaticPrefs::editor_
#include "mozilla/RangeUtils.h" // for RangeUtils
#include "mozilla/dom/DocumentInlines.h" // for GetBodyElement()
#include "mozilla/dom/Element.h" // for Element, nsINode
#include "mozilla/dom/HTMLAnchorElement.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/ServoCSSParser.h" // for ServoCSSParser
#include "mozilla/dom/StaticRange.h"
@ -52,28 +55,28 @@ using EditorType = EditorBase::EditorType;
template nsIContent* HTMLEditUtils::GetPreviousContent(
const EditorDOMPoint& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetPreviousContent(
const EditorRawDOMPoint& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetPreviousContent(
const EditorDOMPointInText& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetPreviousContent(
const EditorRawDOMPointInText& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetNextContent(
const EditorDOMPoint& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetNextContent(
const EditorRawDOMPoint& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetNextContent(
const EditorDOMPointInText& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template nsIContent* HTMLEditUtils::GetNextContent(
const EditorRawDOMPointInText& aPoint, const WalkTreeOptions& aOptions,
const Element* aAncestorLimiter);
BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter);
template EditorDOMPoint HTMLEditUtils::GetPreviousEditablePoint(
nsIContent& aContent, const Element* aAncestorLimiter,
@ -189,12 +192,13 @@ bool HTMLEditUtils::CanContentsBeJoined(const nsIContent& aLeftContent,
*rightStyledElement);
}
bool HTMLEditUtils::IsBlockElement(const nsIContent& aContent) {
if (!aContent.IsElement()) {
static bool IsHTMLBlockElementByDefault(const nsIContent& aContent) {
if (!aContent.IsHTMLElement()) {
return false;
}
if (aContent.IsHTMLElement(nsGkAtoms::br)) { // shortcut for TextEditor
MOZ_ASSERT(!nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(nsGkAtoms::br)));
MOZ_ASSERT(!nsHTMLElement::IsBlock(
nsHTMLTags::CaseSensitiveAtomTagToId(nsGkAtoms::br)));
return false;
}
// We want to treat these as block nodes even though nsHTMLElement says
@ -207,7 +211,90 @@ bool HTMLEditUtils::IsBlockElement(const nsIContent& aContent) {
}
return nsHTMLElement::IsBlock(
nsHTMLTags::AtomTagToId(aContent.NodeInfo()->NameAtom()));
nsHTMLTags::CaseSensitiveAtomTagToId(aContent.NodeInfo()->NameAtom()));
}
bool HTMLEditUtils::IsBlockElement(const nsIContent& aContent,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aBlockInlineCheck != BlockInlineCheck::Unused);
if (MOZ_UNLIKELY(!aContent.IsElement())) {
return false;
}
if (!StaticPrefs::editor_block_inline_check_use_computed_style() ||
aBlockInlineCheck == BlockInlineCheck::UseHTMLDefaultStyle) {
return IsHTMLBlockElementByDefault(aContent);
}
// Let's treat the document element and the body element is a block to avoid
// complicated things which may be detected by fuzzing.
if (aContent.OwnerDoc()->GetDocumentElement() == &aContent ||
(aContent.IsHTMLElement(nsGkAtoms::body) &&
aContent.OwnerDoc()->GetBodyElement() == &aContent)) {
return true;
}
RefPtr<const ComputedStyle> elementStyle =
nsComputedDOMStyle::GetComputedStyleNoFlush(aContent.AsElement());
if (MOZ_UNLIKELY(!elementStyle)) { // If aContent is not in the composed tree
return IsHTMLBlockElementByDefault(aContent);
}
const nsStyleDisplay* styleDisplay = elementStyle->StyleDisplay();
if (MOZ_UNLIKELY(styleDisplay->mDisplay == StyleDisplay::None)) {
// Typically, we should not keep handling editing in invisible nodes, but if
// we reach here, let's fallback to the default style for protecting the
// structure as far as possible.
return IsHTMLBlockElementByDefault(aContent);
}
// Both Blink and WebKit treat ruby style as a block, see IsEnclosingBlock()
// in Chromium or isBlock() in WebKit.
if (styleDisplay->IsRubyDisplayType()) {
return true;
}
// If the outside is not inline, treat it as block.
if (!styleDisplay->IsInlineOutsideStyle()) {
return true;
}
// If we're checking display-inside, inline-block, etc should be a block too.
return aBlockInlineCheck == BlockInlineCheck::UseComputedDisplayStyle &&
styleDisplay->DisplayInside() == StyleDisplayInside::FlowRoot &&
// Treat widgets as inline since they won't hide collapsible
// white-spaces around them.
styleDisplay->EffectiveAppearance() == StyleAppearance::None;
}
bool HTMLEditUtils::IsInlineContent(const nsIContent& aContent,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aBlockInlineCheck != BlockInlineCheck::Unused);
if (!aContent.IsElement()) {
return true;
}
if (!StaticPrefs::editor_block_inline_check_use_computed_style() ||
aBlockInlineCheck == BlockInlineCheck::UseHTMLDefaultStyle) {
return !IsHTMLBlockElementByDefault(aContent);
}
// Let's treat the document element and the body element is a block to avoid
// complicated things which may be detected by fuzzing.
if (aContent.OwnerDoc()->GetDocumentElement() == &aContent ||
(aContent.IsHTMLElement(nsGkAtoms::body) &&
aContent.OwnerDoc()->GetBodyElement() == &aContent)) {
return false;
}
RefPtr<const ComputedStyle> elementStyle =
nsComputedDOMStyle::GetComputedStyleNoFlush(aContent.AsElement());
if (MOZ_UNLIKELY(!elementStyle)) { // If aContent is not in the composed tree
return !IsHTMLBlockElementByDefault(aContent);
}
const nsStyleDisplay* styleDisplay = elementStyle->StyleDisplay();
if (MOZ_UNLIKELY(styleDisplay->mDisplay == StyleDisplay::None)) {
// Similar to IsBlockElement, let's fallback to refer the default style.
// Note that if you change here, you may need to check the parent element
// style if aContent.
return !IsHTMLBlockElementByDefault(aContent);
}
// Different block IsBlockElement, when the display-outside is inline, it's
// simply an inline element.
return styleDisplay->IsInlineOutsideStyle() ||
styleDisplay->IsRubyDisplayType();
}
bool HTMLEditUtils::IsVisibleElementEvenIfLeafNode(const nsIContent& aContent) {
@ -218,7 +305,9 @@ bool HTMLEditUtils::IsVisibleElementEvenIfLeafNode(const nsIContent& aContent) {
if (!aContent.IsHTMLElement()) {
return true;
}
if (HTMLEditUtils::IsBlockElement(aContent)) {
// XXX Should we return false if the element is display:none?
if (HTMLEditUtils::IsBlockElement(
aContent, BlockInlineCheck::UseComputedDisplayStyle)) {
return true;
}
if (aContent.IsAnyOfHTMLElements(nsGkAtoms::applet, nsGkAtoms::iframe,
@ -530,7 +619,8 @@ Element* HTMLEditUtils::GetElementOfImmediateBlockBoundary(
// First, we get a block container. This is not designed for reaching
// no block boundaries in the tree.
Element* maybeNonEditableAncestorBlock = HTMLEditUtils::GetAncestorElement(
aContent, HTMLEditUtils::ClosestBlockElement);
aContent, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!maybeNonEditableAncestorBlock)) {
return nullptr;
}
@ -542,11 +632,13 @@ Element* HTMLEditUtils::GetElementOfImmediateBlockBoundary(
aContent,
{WalkTreeOption::IgnoreDataNodeExceptText,
WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayStyle,
maybeNonEditableAncestorBlock)
: HTMLEditUtils::GetPreviousContent(
aContent,
{WalkTreeOption::IgnoreDataNodeExceptText,
WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayStyle,
maybeNonEditableAncestorBlock);
};
@ -556,7 +648,8 @@ Element* HTMLEditUtils::GetElementOfImmediateBlockBoundary(
nextContent = getNextContent(*nextContent)) {
if (nextContent->IsElement()) {
// Break is right before a child block, it's not visible
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
if (HTMLEditUtils::IsBlockElement(
*nextContent, BlockInlineCheck::UseComputedDisplayStyle)) {
return nextContent->AsElement();
}
@ -646,20 +739,24 @@ nsIContent* HTMLEditUtils::GetUnnecessaryLineBreakContent(
leafNodeOrNonEditableNode)
: HTMLEditUtils::GetPreviousContent(
aBlockElement, onlyPrecedingLine,
BlockInlineCheck::UseComputedDisplayStyle,
aBlockElement.GetParentElement());
content;
content =
aScanLineBreak == ScanLineBreak::AtEndOfBlock
? HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*content, aBlockElement, leafNodeOrNonEditableNode)
*content, aBlockElement, leafNodeOrNonEditableNode,
BlockInlineCheck::UseComputedDisplayStyle)
: HTMLEditUtils::GetPreviousContent(
*content, onlyPrecedingLine,
BlockInlineCheck::UseComputedDisplayStyle,
aBlockElement.GetParentElement())) {
// If we're scanning preceding <br> element of aBlockElement, we don't
// need to look for a line break in another block because the caller
// needs to handle only preceding <br> element of aBlockElement.
if (aScanLineBreak == ScanLineBreak::BeforeBlock &&
HTMLEditUtils::IsBlockElement(*content)) {
HTMLEditUtils::IsBlockElement(
*content, BlockInlineCheck::UseComputedDisplayStyle)) {
return nullptr;
}
if (Text* textNode = Text::FromNode(content)) {
@ -717,15 +814,19 @@ nsIContent* HTMLEditUtils::GetUnnecessaryLineBreakContent(
LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock};
const Element* blockElement = HTMLEditUtils::GetAncestorElement(
*lastLineBreakContent, HTMLEditUtils::ClosestBlockElement);
*lastLineBreakContent, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayStyle);
for (nsIContent* content =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*lastLineBreakContent, *blockElement,
leafNodeOrNonEditableNodeOrChildBlock);
leafNodeOrNonEditableNodeOrChildBlock,
BlockInlineCheck::UseComputedDisplayStyle);
content;
content = HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*content, *blockElement, leafNodeOrNonEditableNodeOrChildBlock)) {
if (HTMLEditUtils::IsBlockElement(*content) ||
*content, *blockElement, leafNodeOrNonEditableNodeOrChildBlock,
BlockInlineCheck::UseComputedDisplayStyle)) {
if (HTMLEditUtils::IsBlockElement(
*content, BlockInlineCheck::UseComputedDisplayStyle) ||
(content->IsElement() && !content->IsHTMLElement())) {
// Now, must found <div>...<div>...</div><br></div>
// ^^^^
@ -907,7 +1008,8 @@ bool HTMLEditUtils::ShouldInsertLinefeedCharacter(
Element* closestEditableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*aPointToInsert.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
// If and only if the nearest block is the editing host or its parent,
// and the outer display value of the editing host is inline, and new
@ -1297,6 +1399,7 @@ bool HTMLEditUtils::IsSingleLineContainer(const nsINode& aNode) {
template <typename PT, typename CT>
nsIContent* HTMLEditUtils::GetPreviousContent(
const EditorDOMPointBase<PT, CT>& aPoint, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
MOZ_ASSERT(aPoint.IsSetAndValid());
NS_WARNING_ASSERTION(
@ -1310,18 +1413,18 @@ nsIContent* HTMLEditUtils::GetPreviousContent(
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
aPoint.IsInContentNode() &&
HTMLEditUtils::IsBlockElement(
*aPoint.template ContainerAs<nsIContent>())) {
*aPoint.template ContainerAs<nsIContent>(), aBlockInlineCheck)) {
// If we aren't allowed to cross blocks, don't look before this block.
return nullptr;
}
return HTMLEditUtils::GetPreviousContent(*aPoint.GetContainer(), aOptions,
aAncestorLimiter);
return HTMLEditUtils::GetPreviousContent(
*aPoint.GetContainer(), aOptions, aBlockInlineCheck, aAncestorLimiter);
}
// else look before the child at 'aOffset'
if (aPoint.GetChild()) {
return HTMLEditUtils::GetPreviousContent(*aPoint.GetChild(), aOptions,
aAncestorLimiter);
return HTMLEditUtils::GetPreviousContent(
*aPoint.GetChild(), aOptions, aBlockInlineCheck, aAncestorLimiter);
}
// unless there isn't one, in which case we are at the end of the node
@ -1330,7 +1433,8 @@ nsIContent* HTMLEditUtils::GetPreviousContent(
*aPoint.GetContainer(),
{aOptions.contains(WalkTreeOption::StopAtBlockBoundary)
? LeafNodeType::LeafNodeOrChildBlock
: LeafNodeType::OnlyLeafNode});
: LeafNodeType::OnlyLeafNode},
aBlockInlineCheck);
if (!lastLeafContent) {
return nullptr;
}
@ -1341,13 +1445,14 @@ nsIContent* HTMLEditUtils::GetPreviousContent(
// restart the search from the non-editable node we just found
return HTMLEditUtils::GetPreviousContent(*lastLeafContent, aOptions,
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
}
// static
template <typename PT, typename CT>
nsIContent* HTMLEditUtils::GetNextContent(
const EditorDOMPointBase<PT, CT>& aPoint, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
MOZ_ASSERT(aPoint.IsSetAndValid());
NS_WARNING_ASSERTION(
@ -1367,7 +1472,7 @@ nsIContent* HTMLEditUtils::GetNextContent(
if (point.GetChild()) {
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*point.GetChild())) {
HTMLEditUtils::IsBlockElement(*point.GetChild(), aBlockInlineCheck)) {
return point.GetChild();
}
@ -1375,7 +1480,8 @@ nsIContent* HTMLEditUtils::GetNextContent(
*point.GetChild(),
{aOptions.contains(WalkTreeOption::StopAtBlockBoundary)
? LeafNodeType::LeafNodeOrChildBlock
: LeafNodeType::OnlyLeafNode});
: LeafNodeType::OnlyLeafNode},
aBlockInlineCheck);
if (!firstLeafContent) {
return point.GetChild();
}
@ -1394,27 +1500,27 @@ nsIContent* HTMLEditUtils::GetNextContent(
// restart the search from the non-editable node we just found
return HTMLEditUtils::GetNextContent(*firstLeafContent, aOptions,
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
}
// unless there isn't one, in which case we are at the end of the node
// and want the next one.
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
point.IsInContentNode() &&
HTMLEditUtils::IsBlockElement(
*point.template ContainerAs<nsIContent>())) {
HTMLEditUtils::IsBlockElement(*point.template ContainerAs<nsIContent>(),
aBlockInlineCheck)) {
// don't cross out of parent block
return nullptr;
}
return HTMLEditUtils::GetNextContent(*point.GetContainer(), aOptions,
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
}
// static
nsIContent* HTMLEditUtils::GetAdjacentLeafContent(
const nsINode& aNode, WalkTreeDirection aWalkTreeDirection,
const WalkTreeOptions& aOptions,
const WalkTreeOptions& aOptions, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
// called only by GetPriorNode so we don't need to check params.
MOZ_ASSERT(&aNode != aAncestorLimiter);
@ -1429,9 +1535,12 @@ nsIContent* HTMLEditUtils::GetAdjacentLeafContent(
? node->GetNextSibling()
: node->GetPreviousSibling();
if (sibling) {
// XXX If `sibling` belongs to siblings of inclusive ancestors of aNode,
// perhaps, we need to use
// IgnoreInsideBlockBoundary(aBlockInlineCheck) here.
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*sibling)) {
// don't look inside prevsib, since it is a block
HTMLEditUtils::IsBlockElement(*sibling, aBlockInlineCheck)) {
// don't look inside previous sibling, since it is a block
return sibling;
}
const LeafNodeTypes leafNodeTypes = {
@ -1440,8 +1549,10 @@ nsIContent* HTMLEditUtils::GetAdjacentLeafContent(
: LeafNodeType::OnlyLeafNode};
nsIContent* leafContent =
aWalkTreeDirection == WalkTreeDirection::Forward
? HTMLEditUtils::GetFirstLeafContent(*sibling, leafNodeTypes)
: HTMLEditUtils::GetLastLeafContent(*sibling, leafNodeTypes);
? HTMLEditUtils::GetFirstLeafContent(*sibling, leafNodeTypes,
aBlockInlineCheck)
: HTMLEditUtils::GetLastLeafContent(*sibling, leafNodeTypes,
aBlockInlineCheck);
return leafContent ? leafContent : sibling;
}
@ -1452,7 +1563,7 @@ nsIContent* HTMLEditUtils::GetAdjacentLeafContent(
if (parent == aAncestorLimiter ||
(aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*parent))) {
HTMLEditUtils::IsBlockElement(*parent, aBlockInlineCheck))) {
return nullptr;
}
@ -1466,7 +1577,7 @@ nsIContent* HTMLEditUtils::GetAdjacentLeafContent(
// static
nsIContent* HTMLEditUtils::GetAdjacentContent(
const nsINode& aNode, WalkTreeDirection aWalkTreeDirection,
const WalkTreeOptions& aOptions,
const WalkTreeOptions& aOptions, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
if (&aNode == aAncestorLimiter) {
// Don't allow traversal above the root node! This helps
@ -1476,7 +1587,7 @@ nsIContent* HTMLEditUtils::GetAdjacentContent(
}
nsIContent* leafContent = HTMLEditUtils::GetAdjacentLeafContent(
aNode, aWalkTreeDirection, aOptions, aAncestorLimiter);
aNode, aWalkTreeDirection, aOptions, aBlockInlineCheck, aAncestorLimiter);
if (!leafContent) {
return nullptr;
}
@ -1486,7 +1597,8 @@ nsIContent* HTMLEditUtils::GetAdjacentContent(
}
return HTMLEditUtils::GetAdjacentContent(*leafContent, aWalkTreeDirection,
aOptions, aAncestorLimiter);
aOptions, aBlockInlineCheck,
aAncestorLimiter);
}
// static
@ -1718,6 +1830,7 @@ EditorDOMPointType HTMLEditUtils::GetNextEditablePoint(
// static
Element* HTMLEditUtils::GetAncestorElement(
const nsIContent& aContent, const AncestorTypes& aAncestorTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
MOZ_ASSERT(
aAncestorTypes.contains(AncestorType::ClosestBlockElement) ||
@ -1751,9 +1864,9 @@ Element* HTMLEditUtils::GetAncestorElement(
return false;
}
return (lookingForClosestBlockElement &&
HTMLEditUtils::IsBlockElement(aContent)) ||
HTMLEditUtils::IsBlockElement(aContent, aBlockInlineCheck)) ||
(lookingForMostDistantInlineElementInBlock &&
HTMLEditUtils::IsInlineElement(aContent)) ||
HTMLEditUtils::IsInlineContent(aContent, aBlockInlineCheck)) ||
(lookingForButtonElement &&
aContent.IsHTMLElement(nsGkAtoms::button));
};
@ -1773,12 +1886,13 @@ Element* HTMLEditUtils::GetAncestorElement(
if (lookingForButtonElement && element->IsHTMLElement(nsGkAtoms::button)) {
return element; // closest button element
}
if (HTMLEditUtils::IsBlockElement(*element)) {
if (HTMLEditUtils::IsBlockElement(*element, aBlockInlineCheck)) {
if (lookingForClosestBlockElement) {
return element; // closest block element
}
MOZ_ASSERT_IF(lastAncestorElement,
HTMLEditUtils::IsInlineElement(*lastAncestorElement));
HTMLEditUtils::IsInlineContent(*lastAncestorElement,
aBlockInlineCheck));
return lastAncestorElement; // the last inline element which we found
}
if (element == aAncestorLimiter || element == theBodyElement ||
@ -1795,6 +1909,7 @@ Element* HTMLEditUtils::GetAncestorElement(
// static
Element* HTMLEditUtils::GetInclusiveAncestorElement(
const nsIContent& aContent, const AncestorTypes& aAncestorTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter /* = nullptr */) {
MOZ_ASSERT(
aAncestorTypes.contains(AncestorType::ClosestBlockElement) ||
@ -1823,9 +1938,9 @@ Element* HTMLEditUtils::GetInclusiveAncestorElement(
return false;
}
return (lookingForClosestBlockElement &&
HTMLEditUtils::IsBlockElement(aContent)) ||
HTMLEditUtils::IsBlockElement(aContent, aBlockInlineCheck)) ||
(lookingForMostDistantInlineElementInBlock &&
HTMLEditUtils::IsInlineElement(aContent)) ||
HTMLEditUtils::IsInlineContent(aContent, aBlockInlineCheck)) ||
(lookingForButtonElement &&
aContent.IsHTMLElement(nsGkAtoms::button));
};
@ -1847,7 +1962,7 @@ Element* HTMLEditUtils::GetInclusiveAncestorElement(
// Consider the result right now.
if ((lookingForClosestBlockElement ||
lookingForMostDistantInlineElementInBlock) &&
HTMLEditUtils::IsBlockElement(aContent) &&
HTMLEditUtils::IsBlockElement(aContent, aBlockInlineCheck) &&
!(ignoreHRElement && aContent.IsHTMLElement(nsGkAtoms::hr))) {
return IsSearchingElementType(aContent)
? const_cast<Element*>(aContent.AsElement())
@ -1861,7 +1976,8 @@ Element* HTMLEditUtils::GetInclusiveAncestorElement(
(editableElementOnly && !EditorUtils::IsEditableContent(
*aContent.GetParent(), EditorType::HTML)) ||
(!lookingForClosestBlockElement &&
HTMLEditUtils::IsBlockElement(*aContent.GetParent()) &&
HTMLEditUtils::IsBlockElement(*aContent.GetParent(),
aBlockInlineCheck) &&
!(ignoreHRElement &&
aContent.GetParent()->IsHTMLElement(nsGkAtoms::hr)))) {
return IsSearchingElementType(aContent)
@ -1874,7 +1990,7 @@ Element* HTMLEditUtils::GetInclusiveAncestorElement(
}
return HTMLEditUtils::GetAncestorElement(aContent, aAncestorTypes,
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
}
// static
@ -2016,7 +2132,9 @@ nsIContent* HTMLEditUtils::GetContentToPreserveInlineStyles(
}
for (auto point = aPoint.template To<EditorRawDOMPoint>(); point.IsSet();) {
WSScanResult nextVisibleThing =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(&aEditingHost, point);
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, point,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (nextVisibleThing.InVisibleOrCollapsibleCharacters()) {
return nextVisibleThing.TextPtr();
}
@ -2058,12 +2176,14 @@ EditorDOMPointType HTMLEditUtils::GetBetterInsertionPointFor(
// If the node to insert is not a block level element, we can insert it
// at any point.
if (!HTMLEditUtils::IsBlockElement(aContentToInsert)) {
if (!HTMLEditUtils::IsBlockElement(
aContentToInsert, BlockInlineCheck::UseComputedDisplayStyle)) {
return pointToInsert;
}
WSRunScanner wsScannerForPointToInsert(const_cast<Element*>(&aEditingHost),
pointToInsert);
WSRunScanner wsScannerForPointToInsert(
const_cast<Element*>(&aEditingHost), pointToInsert,
BlockInlineCheck::UseComputedDisplayStyle);
// If the insertion position is after the last visible item in a line,
// i.e., the insertion position is just before a visible line break <br>,
@ -2116,7 +2236,8 @@ EditorDOMPointType HTMLEditUtils::GetBetterCaretPositionToInsertText(
return EditorDOMPointType(aPoint.GetChild(), 0u);
}
if (aPoint.IsEndOfContainer()) {
WSRunScanner scanner(&aEditingHost, aPoint);
WSRunScanner scanner(&aEditingHost, aPoint,
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult previousThing =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint);
if (previousThing.InVisibleOrCollapsibleCharacters()) {
@ -2265,10 +2386,11 @@ size_t HTMLEditUtils::CollectChildren(
size_t HTMLEditUtils::CollectEmptyInlineContainerDescendants(
const nsINode& aNode,
nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
const EmptyCheckOptions& aOptions) {
const EmptyCheckOptions& aOptions, BlockInlineCheck aBlockInlineCheck) {
size_t numberOfFoundElements = 0;
for (Element* element = aNode.GetFirstElementChild(); element;) {
if (HTMLEditUtils::IsEmptyInlineContainer(*element, aOptions)) {
if (HTMLEditUtils::IsEmptyInlineContainer(*element, aOptions,
aBlockInlineCheck)) {
aOutArrayOfContents.AppendElement(*element);
numberOfFoundElements++;
nsIContent* nextContent = element->GetNextNonChildNode(&aNode);

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

@ -16,6 +16,7 @@
#include "EditorDOMPoint.h"
#include "EditorForwards.h"
#include "EditorUtils.h"
#include "HTMLEditHelpers.h"
#include "mozilla/Attributes.h"
#include "mozilla/EnumSet.h"
@ -153,18 +154,37 @@ class HTMLEditUtils final {
const nsIContent& aRightContent);
/**
* IsBlockElement() returns true if aContent is an element and it should
* be treated as a block. (This does not refer style information.)
* Returns true if aContent is an element and it should be treated as a block.
*
* @param aBlockInlineCheck
* - If UseHTMLDefaultStyle or `editor.block_inline_check.use_computed_style`
* pref is false, this returns true only for HTML elements which are defined
* as a block by the default style. I.e., non-HTML elements are always
* treated as inline.
* - If UseComputedDisplayOutsideStyle, this returns true for element nodes
* whose display-outside is not inline nor ruby. This is useful to get
* inclusive ancestor block element.
* - If UseComputedDisplayStyle, this returns true for element nodes whose
* display-outside is not inline or whose display-inside is flow-root and they
* do not appear as a form control. This is useful to check whether
* collapsible white-spaces at the element edges are visible or invisible or
* whether <br> element at end of the element is visible or invisible.
*/
static bool IsBlockElement(const nsIContent& aContent);
[[nodiscard]] static bool IsBlockElement(const nsIContent& aContent,
BlockInlineCheck aBlockInlineCheck);
/**
* IsInlineElement() returns true if aElement is an element node but
* shouldn't be treated as a block or aElement is not an element.
* XXX This name is wrong. Must be renamed to IsInlineContent() or something.
* This is designed to check elements or non-element nodes which are layed out
* as inline. Therefore, inline-block etc and ruby are treated as inline.
* Note that invisible non-element nodes like comment nodes are also treated
* as inline.
*
* @param aBlockInlineCheck UseComputedDisplayOutsideStyle and
* UseComputedDisplayStyle return same result for
* any elements.
*/
static bool IsInlineElement(const nsIContent& aContent) {
return !IsBlockElement(aContent);
}
[[nodiscard]] static bool IsInlineContent(const nsIContent& aContent,
BlockInlineCheck aBlockInlineCheck);
/**
* IsVisibleElementEvenIfLeafNode() returns true if aContent is an empty block
@ -511,8 +531,9 @@ class HTMLEditUtils final {
* which can have children and does not have meaningful content.
*/
static bool IsEmptyInlineContainer(const nsIContent& aContent,
const EmptyCheckOptions& aOptions) {
return HTMLEditUtils::IsInlineElement(aContent) &&
const EmptyCheckOptions& aOptions,
BlockInlineCheck aBlockInlineCheck) {
return HTMLEditUtils::IsInlineContent(aContent, aBlockInlineCheck) &&
HTMLEditUtils::IsContainerNode(aContent) &&
HTMLEditUtils::IsEmptyNode(aContent, aOptions);
}
@ -522,8 +543,9 @@ class HTMLEditUtils final {
* and it doesn't have any visible content.
*/
static bool IsEmptyBlockElement(const Element& aElement,
const EmptyCheckOptions& aOptions) {
return HTMLEditUtils::IsBlockElement(aElement) &&
const EmptyCheckOptions& aOptions,
BlockInlineCheck aBlockInlineCheck) {
return HTMLEditUtils::IsBlockElement(aElement, aBlockInlineCheck) &&
HTMLEditUtils::IsEmptyNode(aElement, aOptions);
}
@ -603,7 +625,8 @@ class HTMLEditUtils final {
* 2 or more lines and have meaningful content.
*/
static bool IsEmptyOneHardLine(
nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents) {
nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
BlockInlineCheck aBlockInlineCheck) {
if (NS_WARN_IF(aArrayOfContents.IsEmpty())) {
return true;
}
@ -624,7 +647,8 @@ class HTMLEditUtils final {
continue;
}
if (!HTMLEditUtils::IsEmptyInlineContainer(
content, {EmptyCheckOption::TreatSingleBRElementAsVisible})) {
content, {EmptyCheckOption::TreatSingleBRElementAsVisible},
aBlockInlineCheck)) {
return false;
}
}
@ -718,6 +742,8 @@ class HTMLEditUtils final {
* @param aNode The node from which we start to walk the DOM
* tree.
* @param aOptions See WalkTreeOption for the detail.
* @param aBlockInlineCheck Whether considering block vs. inline with the
* computed style or the HTML default style.
* @param aAncestorLimiter Ancestor limiter element which these methods
* never cross its boundary. This is typically
* the editing host.
@ -731,6 +757,7 @@ class HTMLEditUtils final {
using WalkTreeOptions = EnumSet<WalkTreeOption>;
static nsIContent* GetPreviousContent(
const nsINode& aNode, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
if (&aNode == aAncestorLimiter ||
(aAncestorLimiter &&
@ -738,10 +765,12 @@ class HTMLEditUtils final {
return nullptr;
}
return HTMLEditUtils::GetAdjacentContent(aNode, WalkTreeDirection::Backward,
aOptions, aAncestorLimiter);
aOptions, aBlockInlineCheck,
aAncestorLimiter);
}
static nsIContent* GetNextContent(const nsINode& aNode,
const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
if (&aNode == aAncestorLimiter ||
(aAncestorLimiter &&
@ -749,7 +778,8 @@ class HTMLEditUtils final {
return nullptr;
}
return HTMLEditUtils::GetAdjacentContent(aNode, WalkTreeDirection::Forward,
aOptions, aAncestorLimiter);
aOptions, aBlockInlineCheck,
aAncestorLimiter);
}
/**
@ -758,6 +788,7 @@ class HTMLEditUtils final {
template <typename PT, typename CT>
static nsIContent* GetPreviousContent(
const EditorDOMPointBase<PT, CT>& aPoint, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
/**
@ -786,37 +817,26 @@ class HTMLEditUtils final {
template <typename PT, typename CT>
static nsIContent* GetNextContent(const EditorDOMPointBase<PT, CT>& aPoint,
const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
/**
* GetPreviousSibling() and GetNextSibling() return the nearest sibling of
* aContent which does not match with aOption.
* GetPreviousSibling() return the preceding sibling of aContent which matches
* with aOption.
*
* @param aBlockInlineCheck Can be Unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static nsIContent* GetPreviousSibling(const nsIContent& aContent,
const WalkTreeOptions& aOptions) {
static nsIContent* GetPreviousSibling(
const nsIContent& aContent, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
for (nsIContent* sibling = aContent.GetPreviousSibling(); sibling;
sibling = sibling->GetPreviousSibling()) {
if (HTMLEditUtils::IsContentIgnored(*sibling, aOptions)) {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*sibling)) {
return nullptr;
}
return sibling;
}
return nullptr;
}
static nsIContent* GetNextSibling(const nsIContent& aContent,
const WalkTreeOptions& aOptions) {
for (nsIContent* sibling = aContent.GetNextSibling(); sibling;
sibling = sibling->GetNextSibling()) {
if (HTMLEditUtils::IsContentIgnored(*sibling, aOptions)) {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*sibling)) {
HTMLEditUtils::IsBlockElement(*sibling, aBlockInlineCheck)) {
return nullptr;
}
return sibling;
@ -825,18 +845,45 @@ class HTMLEditUtils final {
}
/**
* GetLastChild() and GetFirstChild() return the first or last child of aNode
* which does not match with aOption.
* GetNextSibling() return the following sibling of aContent which matches
* with aOption.
*
* @param aBlockInlineCheck Can be Unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static nsIContent* GetLastChild(const nsINode& aNode,
const WalkTreeOptions& aOptions) {
static nsIContent* GetNextSibling(
const nsIContent& aContent, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
for (nsIContent* sibling = aContent.GetNextSibling(); sibling;
sibling = sibling->GetNextSibling()) {
if (HTMLEditUtils::IsContentIgnored(*sibling, aOptions)) {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*sibling, aBlockInlineCheck)) {
return nullptr;
}
return sibling;
}
return nullptr;
}
/**
* Return the last child of aNode which matches with aOption.
*
* @param aBlockInlineCheck Can be unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static nsIContent* GetLastChild(
const nsINode& aNode, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
for (nsIContent* child = aNode.GetLastChild(); child;
child = child->GetPreviousSibling()) {
if (HTMLEditUtils::IsContentIgnored(*child, aOptions)) {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*child)) {
HTMLEditUtils::IsBlockElement(*child, aBlockInlineCheck)) {
return nullptr;
}
return child;
@ -844,15 +891,22 @@ class HTMLEditUtils final {
return nullptr;
}
static nsIContent* GetFirstChild(const nsINode& aNode,
const WalkTreeOptions& aOptions) {
/**
* Return the first child of aNode which matches with aOption.
*
* @param aBlockInlineCheck Can be unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static nsIContent* GetFirstChild(
const nsINode& aNode, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
for (nsIContent* child = aNode.GetFirstChild(); child;
child = child->GetNextSibling()) {
if (HTMLEditUtils::IsContentIgnored(*child, aOptions)) {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*child)) {
HTMLEditUtils::IsBlockElement(*child, aBlockInlineCheck)) {
return nullptr;
}
return child;
@ -860,22 +914,40 @@ class HTMLEditUtils final {
return nullptr;
}
static bool IsLastChild(const nsIContent& aContent,
const WalkTreeOptions& aOptions) {
/**
* Return true if aContent is the last child of aNode with ignoring all
* children which do not match with aOption.
*
* @param aBlockInlineCheck Can be unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static bool IsLastChild(
const nsIContent& aContent, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
nsINode* parentNode = aContent.GetParentNode();
if (!parentNode) {
return false;
}
return HTMLEditUtils::GetLastChild(*parentNode, aOptions) == &aContent;
return HTMLEditUtils::GetLastChild(*parentNode, aOptions,
aBlockInlineCheck) == &aContent;
}
static bool IsFirstChild(const nsIContent& aContent,
const WalkTreeOptions& aOptions) {
/**
* Return true if aContent is the first child of aNode with ignoring all
* children which do not match with aOption.
*
* @param aBlockInlineCheck Can be unused if aOptions does not contain
* StopAtBlockBoundary.
*/
static bool IsFirstChild(
const nsIContent& aContent, const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused) {
nsINode* parentNode = aContent.GetParentNode();
if (!parentNode) {
return false;
}
return HTMLEditUtils::GetFirstChild(*parentNode, aOptions) == &aContent;
return HTMLEditUtils::GetFirstChild(*parentNode, aOptions,
aBlockInlineCheck) == &aContent;
}
/**
@ -898,13 +970,15 @@ class HTMLEditUtils final {
nsIContent* editableContent = nullptr;
if (aWalkTreeDirection == WalkTreeDirection::Backward) {
editableContent = HTMLEditUtils::GetPreviousContent(
aPoint, {WalkTreeOption::IgnoreNonEditableNode}, &aEditingHost);
aPoint, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayStyle, &aEditingHost);
if (!editableContent) {
return nullptr; // Not illegal.
}
} else {
editableContent = HTMLEditUtils::GetNextContent(
aPoint, {WalkTreeOption::IgnoreNonEditableNode}, &aEditingHost);
aPoint, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::UseComputedDisplayStyle, &aEditingHost);
if (NS_WARN_IF(!editableContent)) {
// Perhaps, illegal because the node pointed by aPoint isn't editable
// and nobody of previous nodes is editable.
@ -922,14 +996,14 @@ class HTMLEditUtils final {
if (aWalkTreeDirection == WalkTreeDirection::Backward) {
editableContent = HTMLEditUtils::GetPreviousContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
&aEditingHost);
BlockInlineCheck::UseComputedDisplayStyle, &aEditingHost);
if (NS_WARN_IF(!editableContent)) {
return nullptr;
}
} else {
editableContent = HTMLEditUtils::GetNextContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
&aEditingHost);
BlockInlineCheck::UseComputedDisplayStyle, &aEditingHost);
if (NS_WARN_IF(!editableContent)) {
return nullptr;
}
@ -950,11 +1024,6 @@ class HTMLEditUtils final {
return editableContent;
}
/**
* GetLastLeafContent() returns rightmost leaf content in aNode. It depends
* on aLeafNodeTypes whether this which types of nodes are treated as leaf
* nodes.
*/
enum class LeafNodeType {
// Even if there is a child block, keep scanning a leaf content in it.
OnlyLeafNode,
@ -968,8 +1037,18 @@ class HTMLEditUtils final {
OnlyEditableLeafNode,
};
using LeafNodeTypes = EnumSet<LeafNodeType>;
/**
* GetLastLeafContent() returns rightmost leaf content in aNode. It depends
* on aLeafNodeTypes whether this which types of nodes are treated as leaf
* nodes.
*
* @param aBlockInlineCheck Can be Unused if aLeafNodeTypes does not contain
* LeafNodeOrCHildBlock.
*/
static nsIContent* GetLastLeafContent(
const nsINode& aNode, const LeafNodeTypes& aLeafNodeTypes,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT_IF(
aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode),
@ -987,11 +1066,11 @@ class HTMLEditUtils final {
EditorUtils::EditorType::HTML)) {
content = HTMLEditUtils::GetPreviousContent(
*content, {WalkTreeOption::IgnoreNonEditableNode},
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
continue;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
HTMLEditUtils::IsBlockElement(*content)) {
HTMLEditUtils::IsBlockElement(*content, aBlockInlineCheck)) {
return content;
}
if (!content->HasChildren() ||
@ -1011,9 +1090,13 @@ class HTMLEditUtils final {
* GetFirstLeafContent() returns leftmost leaf content in aNode. It depends
* on aLeafNodeTypes whether this scans into a block child or treat block as a
* leaf.
*
* @param aBlockInlineCheck Can be Unused if aLeafNodeTypes does not contain
* LeafNodeOrCHildBlock.
*/
static nsIContent* GetFirstLeafContent(
const nsINode& aNode, const LeafNodeTypes& aLeafNodeTypes,
BlockInlineCheck aBlockInlineCheck = BlockInlineCheck::Unused,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT_IF(
aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode),
@ -1031,11 +1114,11 @@ class HTMLEditUtils final {
EditorUtils::EditorType::HTML)) {
content = HTMLEditUtils::GetNextContent(
*content, {WalkTreeOption::IgnoreNonEditableNode},
aAncestorLimiter);
aBlockInlineCheck, aAncestorLimiter);
continue;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
HTMLEditUtils::IsBlockElement(*content)) {
HTMLEditUtils::IsBlockElement(*content, aBlockInlineCheck)) {
return content;
}
if (!content->HasChildren() ||
@ -1068,7 +1151,7 @@ class HTMLEditUtils final {
*/
static nsIContent* GetNextLeafContentOrNextBlockElement(
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
const LeafNodeTypes& aLeafNodeTypes,
const LeafNodeTypes& aLeafNodeTypes, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT_IF(
aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode),
@ -1102,10 +1185,11 @@ class HTMLEditUtils final {
}
}
MOZ_ASSERT(nextContent);
aBlockInlineCheck = IgnoreInsideBlockBoundary(aBlockInlineCheck);
}
// We have a next content. If it's a block, return it.
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
if (HTMLEditUtils::IsBlockElement(*nextContent, aBlockInlineCheck)) {
return nextContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
@ -1115,7 +1199,7 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
// Else if it's a container, get deep leftmost child
if (nsIContent* child = HTMLEditUtils::GetFirstLeafContent(
*nextContent, aLeafNodeTypes)) {
*nextContent, aLeafNodeTypes, aBlockInlineCheck)) {
return child;
}
}
@ -1131,6 +1215,7 @@ class HTMLEditUtils final {
static nsIContent* GetNextLeafContentOrNextBlockElement(
const EditorDOMPointBase<PT, CT>& aStartPoint,
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT(aStartPoint.IsSet());
MOZ_ASSERT_IF(
@ -1145,13 +1230,13 @@ class HTMLEditUtils final {
if (aStartPoint.IsInTextNode()) {
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.template ContainerAs<Text>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter);
}
if (!HTMLEditUtils::IsContainerNode(
*aStartPoint.template ContainerAs<nsIContent>())) {
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.template ContainerAs<nsIContent>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter);
}
nsCOMPtr<nsIContent> nextContent = aStartPoint.GetChild();
@ -1164,11 +1249,12 @@ class HTMLEditUtils final {
// We are at end of non-block container
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*aStartPoint.template ContainerAs<nsIContent>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, IgnoreInsideBlockBoundary(aBlockInlineCheck),
aAncestorLimiter);
}
// We have a next node. If it's a block, return it.
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
if (HTMLEditUtils::IsBlockElement(*nextContent, aBlockInlineCheck)) {
return nextContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
@ -1179,7 +1265,8 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
// else if it's a container, get deep leftmost child
if (nsIContent* child = HTMLEditUtils::GetFirstLeafContent(
*nextContent, aLeafNodeTypes)) {
*nextContent, aLeafNodeTypes,
IgnoreInsideBlockBoundary(aBlockInlineCheck))) {
return child;
}
}
@ -1191,11 +1278,11 @@ class HTMLEditUtils final {
* GetPreviousLeafContentOrPreviousBlockElement() returns previous leaf
* content or previous block element of aStartContent inside
* aAncestorLimiter.
* Note that the result may be a contet outside aCurrentBlock if
* Note that the result may be a content outside aCurrentBlock if
* aStartContent equals aCurrentBlock.
*
* @param aStartContent The start content to scan previous content.
* @param aCurrentBlock Must be ancestor of aStartContent. Dispite
* @param aCurrentBlock Must be ancestor of aStartContent. Despite
* the name, inline content is allowed if
* aStartContent is in an inline editing host.
* @param aLeafNodeTypes See LeafNodeType.
@ -1205,7 +1292,7 @@ class HTMLEditUtils final {
*/
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
const LeafNodeTypes& aLeafNodeTypes,
const LeafNodeTypes& aLeafNodeTypes, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT_IF(
aLeafNodeTypes.contains(LeafNodeType::OnlyEditableLeafNode),
@ -1241,10 +1328,11 @@ class HTMLEditUtils final {
}
}
MOZ_ASSERT(previousContent);
aBlockInlineCheck = IgnoreInsideBlockBoundary(aBlockInlineCheck);
}
// We have a next content. If it's a block, return it.
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
if (HTMLEditUtils::IsBlockElement(*previousContent, aBlockInlineCheck)) {
return previousContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
@ -1254,7 +1342,7 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
// Else if it's a container, get deep rightmost child
if (nsIContent* child = HTMLEditUtils::GetLastLeafContent(
*previousContent, aLeafNodeTypes)) {
*previousContent, aLeafNodeTypes, aBlockInlineCheck)) {
return child;
}
}
@ -1270,6 +1358,7 @@ class HTMLEditUtils final {
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
const EditorDOMPointBase<PT, CT>& aStartPoint,
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr) {
MOZ_ASSERT(aStartPoint.IsSet());
MOZ_ASSERT_IF(
@ -1284,13 +1373,13 @@ class HTMLEditUtils final {
if (aStartPoint.IsInTextNode()) {
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.template ContainerAs<Text>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter);
}
if (!HTMLEditUtils::IsContainerNode(
*aStartPoint.template ContainerAs<nsIContent>())) {
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.template ContainerAs<nsIContent>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter);
}
if (aStartPoint.IsStartOfContainer()) {
@ -1302,7 +1391,8 @@ class HTMLEditUtils final {
// We are at start of non-block container
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*aStartPoint.template ContainerAs<nsIContent>(), aCurrentBlock,
aLeafNodeTypes, aAncestorLimiter);
aLeafNodeTypes, IgnoreInsideBlockBoundary(aBlockInlineCheck),
aAncestorLimiter);
}
nsCOMPtr<nsIContent> previousContent =
@ -1312,7 +1402,7 @@ class HTMLEditUtils final {
}
// We have a prior node. If it's a block, return it.
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
if (HTMLEditUtils::IsBlockElement(*previousContent, aBlockInlineCheck)) {
return previousContent;
}
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
@ -1323,7 +1413,8 @@ class HTMLEditUtils final {
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
// Else if it's a container, get deep rightmost child
if (nsIContent* child = HTMLEditUtils::GetLastLeafContent(
*previousContent, aLeafNodeTypes)) {
*previousContent, aLeafNodeTypes,
IgnoreInsideBlockBoundary(aBlockInlineCheck))) {
return child;
}
}
@ -1396,9 +1487,11 @@ class HTMLEditUtils final {
AncestorType::ButtonElement};
static Element* GetAncestorElement(const nsIContent& aContent,
const AncestorTypes& aAncestorTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
static Element* GetInclusiveAncestorElement(
const nsIContent& aContent, const AncestorTypes& aAncestorTypes,
BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
/**
@ -1595,9 +1688,10 @@ class HTMLEditUtils final {
* descendant of aAncestorLimiter.
*/
static nsIContent* GetMostDistantAncestorInlineElement(
const nsIContent& aContent, const Element* aEditingHost = nullptr,
const nsIContent& aContent, BlockInlineCheck aBlockInlineCheck,
const Element* aEditingHost = nullptr,
const nsIContent* aAncestorLimiter = nullptr) {
if (HTMLEditUtils::IsBlockElement(aContent)) {
if (HTMLEditUtils::IsBlockElement(aContent, aBlockInlineCheck)) {
return nullptr;
}
@ -1623,7 +1717,7 @@ class HTMLEditUtils final {
nsIContent* topMostInlineContent = const_cast<nsIContent*>(&aContent);
for (Element* element : aContent.AncestorsOfType<Element>()) {
if (element == aEditingHost || element == aAncestorLimiter ||
!HTMLEditUtils::IsInlineElement(*element)) {
HTMLEditUtils::IsBlockElement(*element, aBlockInlineCheck)) {
break;
}
topMostInlineContent = element;
@ -1637,7 +1731,8 @@ class HTMLEditUtils final {
* inline element.
*/
static Element* GetMostDistantAncestorEditableEmptyInlineElement(
const nsIContent& aEmptyContent, const Element* aEditingHost = nullptr,
const nsIContent& aEmptyContent, BlockInlineCheck aBlockInlineCheck,
const Element* aEditingHost = nullptr,
const nsIContent* aAncestorLimiter = nullptr) {
if (&aEmptyContent == aEditingHost || &aEmptyContent == aAncestorLimiter) {
return nullptr;
@ -1647,7 +1742,7 @@ class HTMLEditUtils final {
if (element == aEditingHost || element == aAncestorLimiter) {
break;
}
if (!HTMLEditUtils::IsInlineElement(*element) ||
if (!HTMLEditUtils::IsInlineContent(*element, aBlockInlineCheck) ||
!HTMLEditUtils::IsSimplyEditableNode(*element)) {
break;
}
@ -1742,7 +1837,7 @@ class HTMLEditUtils final {
template <typename FirstElementName, typename... OtherElementNames>
static Element* GetInclusiveDeepestFirstChildWhichHasOneChild(
const nsINode& aNode, const WalkTreeOptions& aOptions,
FirstElementName aFirstElementName,
BlockInlineCheck aBlockInlineCheck, FirstElementName aFirstElementName,
OtherElementNames... aOtherElementNames) {
if (!aNode.IsElement()) {
return nullptr;
@ -1754,7 +1849,8 @@ class HTMLEditUtils final {
// XXX Why do we scan only the first child of every element? If it's
// not editable, why do we ignore it when aOptions specifies so.
content = content->GetFirstChild()) {
if (HTMLEditUtils::CountChildren(*content, aOptions) != 1) {
if (HTMLEditUtils::CountChildren(*content, aOptions, aBlockInlineCheck) !=
1) {
return content->AsElement();
}
parentElement = content->AsElement();
@ -1776,7 +1872,7 @@ class HTMLEditUtils final {
*content,
{WalkTreeOption::IgnoreDataNodeExceptText,
WalkTreeOption::IgnoreWhiteSpaceOnlyText},
&aElement)) {
BlockInlineCheck::Unused, &aElement)) {
if (auto* brElement = dom::HTMLBRElement::FromNode(*content)) {
return brElement;
}
@ -2189,12 +2285,14 @@ class HTMLEditUtils final {
* into this array.
* @param aOptions The option which element should be treated as
* empty.
* @param aBlockInlineCheck Whether use computed style or HTML default style
* when consider block vs. inline.
* @return Number of found elements.
*/
static size_t CollectEmptyInlineContainerDescendants(
const nsINode& aNode,
nsTArray<OwningNonNull<nsIContent>>& aOutArrayOfContents,
const EmptyCheckOptions& aOptions);
const EmptyCheckOptions& aOptions, BlockInlineCheck aBlockInlineCheck);
/**
* Check whether aElement has attributes except the name aAttribute and
@ -2437,7 +2535,8 @@ class HTMLEditUtils final {
}
static uint32_t CountChildren(const nsINode& aNode,
const WalkTreeOptions& aOptions) {
const WalkTreeOptions& aOptions,
BlockInlineCheck aBlockInlineCheck) {
uint32_t count = 0;
for (nsIContent* child = aNode.GetFirstChild(); child;
child = child->GetNextSibling()) {
@ -2445,7 +2544,7 @@ class HTMLEditUtils final {
continue;
}
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
HTMLEditUtils::IsBlockElement(*child)) {
HTMLEditUtils::IsBlockElement(*child, aBlockInlineCheck)) {
break;
}
++count;
@ -2458,11 +2557,11 @@ class HTMLEditUtils final {
*/
static nsIContent* GetAdjacentLeafContent(
const nsINode& aNode, WalkTreeDirection aWalkTreeDirection,
const WalkTreeOptions& aOptions,
const WalkTreeOptions& aOptions, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
static nsIContent* GetAdjacentContent(
const nsINode& aNode, WalkTreeDirection aWalkTreeDirection,
const WalkTreeOptions& aOptions,
const WalkTreeOptions& aOptions, BlockInlineCheck aBlockInlineCheck,
const Element* aAncestorLimiter = nullptr);
/**

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

@ -30,6 +30,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/EditorForwards.h"
#include "mozilla/Encoding.h" // for Encoding
#include "mozilla/FlushType.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/IntegerRange.h" // for IntegerRange
#include "mozilla/InternalMutationEvent.h"
@ -1104,7 +1105,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
*editingHost,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
editingHost);
BlockInlineCheck::UseComputedDisplayStyle, editingHost);
leafContent;) {
// If we meet a non-editable node first, we should move caret to start
// of the container block or editing host.
@ -1115,8 +1116,8 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
if (const Element* editableBlockElementOrInlineEditingHost =
HTMLEditUtils::GetAncestorElement(
*leafContent,
HTMLEditUtils::
ClosestEditableBlockElementOrInlineEditingHost)) {
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
BlockInlineCheck::UseComputedDisplayStyle)) {
nsresult rv = CollapseSelectionTo(
EditorDOMPoint(editableBlockElementOrInlineEditingHost, 0));
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
@ -1132,18 +1133,21 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
// <div contenteditable><span></span><b><br></b></div>
// then, we should put caret at the <br> element. So, let's check if found
// node is an empty inline container element.
if (leafContent->IsElement() &&
HTMLEditUtils::IsInlineElement(*leafContent) &&
!HTMLEditUtils::IsNeverElementContentsEditableByUser(*leafContent) &&
HTMLEditUtils::CanNodeContain(*leafContent, *nsGkAtoms::textTagName)) {
// Chromium collaps selection to start of the editing host when this is
// the last leaf content. So, we don't need special handling here.
leafContent = HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*leafContent, *editingHost,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
editingHost);
continue;
if (Element* leafElement = Element::FromNode(leafContent)) {
if (HTMLEditUtils::IsInlineContent(
*leafElement, BlockInlineCheck::UseComputedDisplayStyle) &&
!HTMLEditUtils::IsNeverElementContentsEditableByUser(*leafElement) &&
HTMLEditUtils::CanNodeContain(*leafElement,
*nsGkAtoms::textTagName)) {
// Chromium collapses selection to start of the editing host when this
// is the last leaf content. So, we don't need special handling here.
leafContent = HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*leafElement, *editingHost,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
BlockInlineCheck::UseComputedDisplayStyle, editingHost);
continue;
}
}
if (Text* text = leafContent->GetAsText()) {
@ -1151,7 +1155,8 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
// the visible character.
WSScanResult scanResultInTextNode =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
editingHost, EditorRawDOMPoint(text, 0));
editingHost, EditorRawDOMPoint(text, 0),
BlockInlineCheck::UseComputedDisplayStyle);
if ((scanResultInTextNode.InVisibleOrCollapsibleCharacters() ||
scanResultInTextNode.ReachedPreformattedLineBreak()) &&
scanResultInTextNode.TextPtr() == text) {
@ -1166,7 +1171,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
*leafContent, *editingHost,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
editingHost);
BlockInlineCheck::UseComputedDisplayStyle, editingHost);
continue;
}
@ -1192,7 +1197,8 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
}
// If we meet non-empty block element, we need to scan its child too.
if (HTMLEditUtils::IsBlockElement(*leafContent) &&
if (HTMLEditUtils::IsBlockElement(
*leafContent, BlockInlineCheck::UseComputedDisplayStyle) &&
!HTMLEditUtils::IsEmptyNode(
*leafContent, {EmptyCheckOption::TreatSingleBRElementAsVisible}) &&
!HTMLEditUtils::IsNeverElementContentsEditableByUser(*leafContent)) {
@ -1200,7 +1206,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
*leafContent,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
editingHost);
BlockInlineCheck::UseComputedDisplayStyle, editingHost);
continue;
}
@ -1210,7 +1216,7 @@ nsresult HTMLEditor::MaybeCollapseSelectionAtFirstEditableNode(
*leafContent, *editingHost,
{LeafNodeType::LeafNodeOrNonEditableNode,
LeafNodeType::LeafNodeOrChildBlock},
editingHost);
BlockInlineCheck::UseComputedDisplayStyle, editingHost);
}
// If there is no visible/editable node except another block element in
@ -1239,7 +1245,7 @@ nsresult HTMLEditor::RestorePreservedSelection() {
MOZ_ASSERT(IsEditActionDataAvailable());
if (!SavedSelectionRef().RangeCount()) {
// XXX Returing error when it does not store is odd because no selection
// XXX Returning error when it does not store is odd because no selection
// ranges is not illegal case in general.
return NS_ERROR_FAILURE;
}
@ -1374,7 +1380,8 @@ nsresult HTMLEditor::HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) {
const Element* editableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*startContainer->AsContent(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!editableBlockElement) {
break;
}
@ -1469,8 +1476,23 @@ nsresult HTMLEditor::HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent) {
}
NS_IMETHODIMP HTMLEditor::NodeIsBlock(nsINode* aNode, bool* aIsBlock) {
*aIsBlock = aNode && aNode->IsContent() &&
HTMLEditUtils::IsBlockElement(*aNode->AsContent());
if (NS_WARN_IF(!aNode)) {
return NS_ERROR_INVALID_ARG;
}
if (MOZ_UNLIKELY(!aNode->IsElement())) {
*aIsBlock = false;
return NS_OK;
}
// If the node is in composed doc, we'll refer its style. If we don't flush
// pending style here, another API call may change the style. Therefore,
// let's flush the pending style changes right now.
if (aNode->IsInComposedDoc()) {
if (RefPtr<PresShell> presShell = GetPresShell()) {
presShell->FlushPendingNotifications(FlushType::Style);
}
}
*aIsBlock = HTMLEditUtils::IsBlockElement(
*aNode->AsElement(), BlockInlineCheck::UseComputedDisplayOutsideStyle);
return NS_OK;
}
@ -2136,7 +2158,8 @@ nsresult HTMLEditor::InsertElementAtSelectionAsAction(
}
if (aDeleteSelection) {
if (!HTMLEditUtils::IsBlockElement(*aElement)) {
if (!HTMLEditUtils::IsBlockElement(
*aElement, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
// E.g., inserting an image. In this case we don't need to delete any
// inline wrappers before we do the insertion. Otherwise we let
// DeleteSelectionAndPrepareToCreateNode do the deletion for us, which
@ -2585,14 +2608,16 @@ nsresult HTMLEditor::GetCSSBackgroundColorState(bool* aMixed,
// should ignore the editing host boundaries.
Element* const closestBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*contentToExamine, HTMLEditUtils::ClosestBlockElement);
*contentToExamine, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (NS_WARN_IF(!closestBlockElement)) {
return NS_OK;
}
for (RefPtr<Element> blockElement = closestBlockElement; blockElement;) {
RefPtr<Element> nextBlockElement = HTMLEditUtils::GetAncestorElement(
*blockElement, HTMLEditUtils::ClosestBlockElement);
*blockElement, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
DebugOnly<nsresult> rvIgnored = CSSEditUtils::GetComputedProperty(
*blockElement, *nsGkAtoms::backgroundColor, aOutColor);
if (NS_WARN_IF(Destroyed())) {
@ -2601,7 +2626,8 @@ nsresult HTMLEditor::GetCSSBackgroundColorState(bool* aMixed,
if (MayHaveMutationEventListeners() &&
NS_WARN_IF(nextBlockElement !=
HTMLEditUtils::GetAncestorElement(
*blockElement, HTMLEditUtils::ClosestBlockElement))) {
*blockElement, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle))) {
return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
@ -2638,7 +2664,8 @@ nsresult HTMLEditor::GetCSSBackgroundColorState(bool* aMixed,
contentToExamine->GetAsElementOrParentElement();
element; element = element->GetParentElement()) {
// is the node to examine a block ?
if (HTMLEditUtils::IsBlockElement(*element)) {
if (HTMLEditUtils::IsBlockElement(
*element, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
// yes it is a block; in that case, the text background color is
// transparent
aOutColor.AssignLiteral("transparent");
@ -3817,7 +3844,9 @@ nsresult HTMLEditor::RemoveEmptyInclusiveAncestorInlineElements(
return NS_ERROR_FAILURE;
}
if (&aContent == editingHost || HTMLEditUtils::IsBlockElement(aContent) ||
if (&aContent == editingHost ||
HTMLEditUtils::IsBlockElement(
aContent, BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
!EditorUtils::IsEditableContent(aContent, EditorType::HTML) ||
!aContent.GetParent()) {
return NS_OK;
@ -3829,7 +3858,8 @@ nsresult HTMLEditor::RemoveEmptyInclusiveAncestorInlineElements(
// even if it's only child of the block element.
{
const Element* editableBlockElement = HTMLEditUtils::GetAncestorElement(
aContent, HTMLEditUtils::ClosestEditableBlockElement);
aContent, HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!editableBlockElement ||
HTMLEditUtils::IsEmptyNode(
*editableBlockElement,
@ -3840,7 +3870,8 @@ nsresult HTMLEditor::RemoveEmptyInclusiveAncestorInlineElements(
OwningNonNull<nsIContent> content = aContent;
for (nsIContent* parentContent : aContent.AncestorsOfType<nsIContent>()) {
if (HTMLEditUtils::IsBlockElement(*parentContent) ||
if (HTMLEditUtils::IsBlockElement(
*parentContent, BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
parentContent->Length() != 1 ||
!EditorUtils::IsEditableContent(*parentContent, EditorType::HTML) ||
parentContent == editingHost) {
@ -4829,9 +4860,12 @@ HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
if (nsIContent* previousSibling = HTMLEditUtils::GetPreviousSibling(
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
if (!HTMLEditUtils::IsBlockElement(*previousSibling) &&
if (!HTMLEditUtils::IsBlockElement(
*previousSibling,
BlockInlineCheck::UseComputedDisplayOutsideStyle) &&
!previousSibling->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsBlockElement(*child)) {
!HTMLEditUtils::IsBlockElement(
*child, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
// Insert br node
Result<CreateElementResult, nsresult> insertBRElementResult =
InsertBRElement(WithTransaction::Yes,
@ -4857,10 +4891,14 @@ HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
if (nsIContent* nextSibling = HTMLEditUtils::GetNextSibling(
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
if (nextSibling && !HTMLEditUtils::IsBlockElement(*nextSibling)) {
if (nextSibling &&
!HTMLEditUtils::IsBlockElement(
*nextSibling, BlockInlineCheck::UseComputedDisplayStyle)) {
if (nsIContent* lastChild = HTMLEditUtils::GetLastChild(
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
if (!HTMLEditUtils::IsBlockElement(*lastChild) &&
aElement, {WalkTreeOption::IgnoreNonEditableNode},
BlockInlineCheck::Unused)) {
if (!HTMLEditUtils::IsBlockElement(
*lastChild, BlockInlineCheck::UseComputedDisplayStyle) &&
!lastChild->IsHTMLElement(nsGkAtoms::br)) {
Result<CreateElementResult, nsresult> insertBRElementResult =
InsertBRElement(WithTransaction::Yes,
@ -4887,11 +4925,13 @@ HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
// 3) following sibling of aNode is a block, OR
// 4) following sibling of aNode is a br OR
// 5) either is null
if (!HTMLEditUtils::IsBlockElement(*previousSibling) &&
if (!HTMLEditUtils::IsBlockElement(
*previousSibling, BlockInlineCheck::UseComputedDisplayStyle) &&
!previousSibling->IsHTMLElement(nsGkAtoms::br)) {
if (nsIContent* nextSibling = HTMLEditUtils::GetNextSibling(
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
if (!HTMLEditUtils::IsBlockElement(*nextSibling) &&
if (!HTMLEditUtils::IsBlockElement(
*nextSibling, BlockInlineCheck::UseComputedDisplayStyle) &&
!nextSibling->IsHTMLElement(nsGkAtoms::br)) {
Result<CreateElementResult, nsresult> insertBRElementResult =
InsertBRElement(WithTransaction::Yes,
@ -6212,7 +6252,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction(
const RefPtr<nsStyledElement> editableBlockStyledElement =
nsStyledElement::FromNodeOrNull(HTMLEditUtils::GetAncestorElement(
*range.StartRef().ContainerAs<Text>(),
HTMLEditUtils::ClosestEditableBlockElement));
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle));
if (!editableBlockStyledElement ||
!EditorElementStyle::BGColor().IsCSSSettable(
*editableBlockStyledElement)) {
@ -6268,7 +6309,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction(
nsStyledElement::FromNodeOrNull(
HTMLEditUtils::GetInclusiveAncestorElement(
*range.StartRef().GetChild(),
HTMLEditUtils::ClosestEditableBlockElement));
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle));
if (!editableBlockStyledElement ||
!EditorElementStyle::BGColor().IsCSSSettable(
*editableBlockStyledElement)) {
@ -6325,7 +6367,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction(
EditorType::HTML)) {
Element* const editableBlockElement = HTMLEditUtils::GetAncestorElement(
*range.StartRef().ContainerAs<Text>(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (editableBlockElement && handledBlockParent != editableBlockElement) {
handledBlockParent = editableBlockElement;
nsStyledElement* const blockStyledElement =
@ -6356,7 +6399,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction(
for (OwningNonNull<nsIContent>& content : arrayOfContents) {
Element* const editableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
content, HTMLEditUtils::ClosestEditableBlockElement);
content, HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (editableBlockElement && handledBlockParent != editableBlockElement) {
handledBlockParent = editableBlockElement;
nsStyledElement* const blockStyledElement =
@ -6389,7 +6433,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction(
EditorType::HTML)) {
Element* const editableBlockElement = HTMLEditUtils::GetAncestorElement(
*range.EndRef().ContainerAs<Text>(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (editableBlockElement && handledBlockParent != editableBlockElement) {
const RefPtr<nsStyledElement> blockStyledElement =
nsStyledElement::FromNode(editableBlockElement);
@ -6495,7 +6540,7 @@ HTMLEditor::CopyLastEditableChildStylesWithTransaction(
deepestEditableContent->IsHTMLElement(nsGkAtoms::br)) {
deepestEditableContent = HTMLEditUtils::GetPreviousContent(
*deepestEditableContent, {WalkTreeOption::IgnoreNonEditableNode},
&aEditingHost);
BlockInlineCheck::UseComputedDisplayOutsideStyle, &aEditingHost);
}
if (!deepestEditableContent) {
return EditorDOMPoint(&aNewBlock, 0u);

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

@ -1203,13 +1203,15 @@ class HTMLEditor final : public EditorBase,
const Element& aEditingHost);
/**
* Splits parent inline nodes at both start and end of aRangeItem. If this
* splits at every point, this modifies aRangeItem to point each split point
* (typically, at right node).
* Splits inclusive inline ancestors at both start and end of aRangeItem. If
* this splits at every point, this modifies aRangeItem to point each split
* point (typically, at right node).
*
* @param aRangeItem [in/out] One or two DOM points where should be
* split. Will be modified to split point if
* they're split.
* @param aBlockInlineCheck [in] Whether this method considers block vs.
* inline with computed style or the default style.
* @param aEditingHost [in] The editing host.
* @param aAncestorLimiter [in/optional] If specified, this stops splitting
* ancestors when meets this node.
@ -1217,8 +1219,9 @@ class HTMLEditor final : public EditorBase,
* it may be unset.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
SplitParentInlineElementsAtRangeBoundaries(
RangeItem& aRangeItem, const Element& aEditingHost,
SplitInlineAncestorsAtRangeBoundaries(
RangeItem& aRangeItem, BlockInlineCheck aBlockInlineCheck,
const Element& aEditingHost,
const nsIContent* aAncestorLimiter = nullptr);
/**
@ -1433,18 +1436,18 @@ class HTMLEditor final : public EditorBase,
const InitializeInsertingElement& aInitializer = DoNothingForNewElement);
/**
* SplitRangeOffFromBlock() splits aBlockElement at two points, before
* aStartOfMiddleElement and after aEndOfMiddleElement. If they are very
* start or very end of aBlockElement, this won't create empty block.
* Split aElementToSplit at two points, before aStartOfMiddleElement and after
* aEndOfMiddleElement. If they are very start or very end of aBlockElement,
* this won't create empty block.
*
* @param aBlockElement A block element which will be split.
* @param aElementToSplit An element which will be split.
* @param aStartOfMiddleElement Start node of middle block element.
* @param aEndOfMiddleElement End node of middle block element.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
SplitRangeOffFromBlock(Element& aBlockElement,
nsIContent& aStartOfMiddleElement,
nsIContent& aEndOfMiddleElement);
SplitRangeOffFromElement(Element& aElementToSplit,
nsIContent& aStartOfMiddleElement,
nsIContent& aEndOfMiddleElement);
/**
* RemoveBlockContainerElementWithTransactionBetween() splits the nodes
@ -1459,6 +1462,9 @@ class HTMLEditor final : public EditorBase,
* from aBlockContainerElement.
* @param aEndOfRange The last node which will be unwrapped from
* aBlockContainerElement.
* @param aBlockInlineCheck Whether this method considers block vs.
* inline with computed style or the default
* style.
* @return The left content is new created left
* element of aBlockContainerElement.
* The right content is split element,
@ -1469,7 +1475,7 @@ class HTMLEditor final : public EditorBase,
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<SplitRangeOffFromNodeResult, nsresult>
RemoveBlockContainerElementWithTransactionBetween(
Element& aBlockContainerElement, nsIContent& aStartOfRange,
nsIContent& aEndOfRange);
nsIContent& aEndOfRange, BlockInlineCheck aBlockInlineCheck);
/**
* WrapContentsInBlockquoteElementsWithTransaction() inserts at least one
@ -1504,7 +1510,8 @@ class HTMLEditor final : public EditorBase,
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
RemoveBlockContainerElementsWithTransaction(
const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents);
const nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
BlockInlineCheck aBlockInlineCheck);
/**
* CreateOrChangeBlockContainerElement() formats all nodes in aArrayOfContents
@ -4502,7 +4509,7 @@ class HTMLEditor final : public EditorBase,
friend class AlignStateAtSelection; // CollectEditableTargetNodes,
// CollectNonEditableNodes
friend class AutoRangeArray; // RangeUpdaterRef, SplitNodeWithTransaction,
// SplitParentInlineElementsAtRangeBoundaries
// SplitInlineAncestorsAtRangeBoundaries
friend class AutoSelectionSetterAfterTableEdit; // SetSelectionAfterEdit
friend class
AutoSetTemporaryAncestorLimiter; // InitializeSelectionAncestorLimit

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

@ -433,8 +433,9 @@ class MOZ_STACK_CLASS
HTMLBRElement*
HTMLEditor::HTMLWithContextInserter::GetInvisibleBRElementAtPoint(
const EditorDOMPoint& aPointToInsert) const {
WSRunScanner wsRunScannerAtInsertionPoint(mHTMLEditor.ComputeEditingHost(),
aPointToInsert);
WSRunScanner wsRunScannerAtInsertionPoint(
mHTMLEditor.ComputeEditingHost(), aPointToInsert,
BlockInlineCheck::UseComputedDisplayStyle);
if (wsRunScannerAtInsertionPoint.EndsByInvisibleBRElement()) {
return wsRunScannerAtInsertionPoint.EndReasonBRElementPtr();
}
@ -451,6 +452,7 @@ HTMLEditor::HTMLWithContextInserter::GetNewCaretPointAfterInsertingHTML(
if (!HTMLEditUtils::IsTable(aLastInsertedPoint.GetChild())) {
containerContent = HTMLEditUtils::GetLastLeafContent(
*aLastInsertedPoint.GetChild(), {LeafNodeType::OnlyEditableLeafNode},
BlockInlineCheck::Unused,
aLastInsertedPoint.GetChild()->GetAsElementOrParentElement());
if (containerContent) {
Element* mostDistantInclusiveAncestorTableElement = nullptr;
@ -494,13 +496,15 @@ HTMLEditor::HTMLWithContextInserter::GetNewCaretPointAfterInsertingHTML(
// Make sure we don't end up with selection collapsed after an invisible
// `<br>` element.
Element* editingHost = mHTMLEditor.ComputeEditingHost();
WSRunScanner wsRunScannerAtCaret(editingHost, pointToPutCaret);
WSRunScanner wsRunScannerAtCaret(editingHost, pointToPutCaret,
BlockInlineCheck::UseComputedDisplayStyle);
if (wsRunScannerAtCaret
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(pointToPutCaret)
.ReachedInvisibleBRElement()) {
WSRunScanner wsRunScannerAtStartReason(
editingHost,
EditorDOMPoint(wsRunScannerAtCaret.GetStartReasonContent()));
EditorDOMPoint(wsRunScannerAtCaret.GetStartReasonContent()),
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult backwardScanFromPointToCaretResult =
wsRunScannerAtStartReason.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
pointToPutCaret);
@ -884,7 +888,8 @@ HTMLEditor::HTMLWithContextInserter::InsertContents(
pointToInsert.IsInContentNode()
? HTMLEditUtils::GetInclusiveAncestorElement(
*pointToInsert.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestBlockElement)
HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle)
: nullptr;
EditorDOMPoint lastInsertedPoint;

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

@ -1305,7 +1305,9 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDelete(
EditorType::HTML)) {
return NS_SUCCESS_DOM_NO_OPERATION;
}
WSRunScanner wsRunScannerAtCaret(editingHost, caretPoint);
WSRunScanner wsRunScannerAtCaret(
editingHost, caretPoint,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
@ -1602,7 +1604,9 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
*caretPoint.ref().ContainerAs<nsIContent>(), EditorType::HTML)) {
return EditActionResult::CanceledResult();
}
WSRunScanner wsRunScannerAtCaret(&aEditingHost, caretPoint.ref());
WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret.ScanNextVisibleNodeOrBlockBoundaryFrom(
@ -1658,7 +1662,9 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::Run(
NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT)) {
// Let's check whether there is new invisible `<br>` element
// for avoiding infinite recursive calls.
WSRunScanner wsRunScannerAtCaret(&aEditingHost, caretPoint.ref());
WSRunScanner wsRunScannerAtCaret(
&aEditingHost, caretPoint.ref(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult scanFromCaretPointResult =
aDirectionAndAmount == nsIEditor::eNext
? wsRunScannerAtCaret
@ -2397,13 +2403,13 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
if (aDirectionAndAmount == nsIEditor::ePrevious) {
mLeafContentInOtherBlock = HTMLEditUtils::GetLastLeafContent(
aOtherBlockElement, {LeafNodeType::OnlyEditableLeafNode},
&aOtherBlockElement);
BlockInlineCheck::Unused, &aOtherBlockElement);
mLeftContent = mLeafContentInOtherBlock;
mRightContent = aCaretPoint.GetContainerAs<nsIContent>();
} else {
mLeafContentInOtherBlock = HTMLEditUtils::GetFirstLeafContent(
aOtherBlockElement, {LeafNodeType::OnlyEditableLeafNode},
&aOtherBlockElement);
BlockInlineCheck::Unused, &aOtherBlockElement);
mLeftContent = aCaretPoint.GetContainerAs<nsIContent>();
mRightContent = mLeafContentInOtherBlock;
}
@ -2453,7 +2459,8 @@ HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::DeleteBRElement(
aHTMLEditor.GetEditAction())) {
return EditorDOMPoint();
}
WSRunScanner scanner(&aEditingHost, EditorRawDOMPoint(mBRElement));
WSRunScanner scanner(&aEditingHost, EditorRawDOMPoint(mBRElement),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(
EditorRawDOMPoint(mBRElement));
@ -2846,10 +2853,10 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
aDirectionAndAmount == nsIEditor::ePrevious
? HTMLEditUtils::GetPreviousContent(
aCurrentBlockElement, {WalkTreeOption::IgnoreNonEditableNode},
editingHost)
BlockInlineCheck::Unused, editingHost)
: HTMLEditUtils::GetNextContent(
aCurrentBlockElement, {WalkTreeOption::IgnoreNonEditableNode},
editingHost);
BlockInlineCheck::Unused, editingHost);
// If found content is an invisible text node, let's scan visible things.
auto IsIgnorableDataNode = [](nsIContent* aContent) {
return aContent && HTMLEditUtils::IsRemovableNode(*aContent) &&
@ -2866,18 +2873,22 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
aDirectionAndAmount == nsIEditor::ePrevious
? HTMLEditUtils::GetPreviousContent(
*targetContent, {WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost)
: HTMLEditUtils::GetNextContent(
*targetContent, {WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost);
adjacentContent;
adjacentContent =
aDirectionAndAmount == nsIEditor::ePrevious
? HTMLEditUtils::GetPreviousContent(
*adjacentContent, {WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost)
: HTMLEditUtils::GetNextContent(
*adjacentContent, {WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost)) {
// If non-editable element is found, we should not skip it to avoid
// joining too far nodes.
@ -2885,7 +2896,9 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
break;
}
// If block element is found, we should join last leaf content in it.
if (HTMLEditUtils::IsBlockElement(*adjacentContent)) {
if (HTMLEditUtils::IsBlockElement(
*adjacentContent,
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
nsIContent* leafContent =
aDirectionAndAmount == nsIEditor::ePrevious
? HTMLEditUtils::GetLastLeafContent(
@ -3353,10 +3366,12 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
mLeftContent = HTMLEditUtils::GetInclusiveAncestorElement(
*aRangesToDelete.FirstRangeRef()->GetStartContainer()->AsContent(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
mRightContent = HTMLEditUtils::GetInclusiveAncestorElement(
*aRangesToDelete.FirstRangeRef()->GetEndContainer()->AsContent(),
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
// Note that mLeftContent and/or mRightContent can be nullptr if editing host
// is an inline element. If both editable ancestor block is exactly same
// one or one reaches an inline editing host, we can just delete the content
@ -3374,7 +3389,7 @@ bool HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
return true;
}
// If left block and right block are adjuscent siblings and they are same
// If left block and right block are adjacent siblings and they are same
// type of elements, we can merge them after deleting the selected contents.
// MOOSE: this could conceivably screw up a table.. fix me.
if (mLeftContent->GetParentNode() == mRightContent->GetParentNode() &&
@ -3420,10 +3435,12 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
->GetEndContainer()
->IsInclusiveDescendantOf(mRightContent));
MOZ_ASSERT_IF(!mLeftContent,
HTMLEditUtils::IsInlineElement(*aRangesToDelete.FirstRangeRef()
->GetStartContainer()
->AsContent()
->GetEditingHost()));
HTMLEditUtils::IsInlineContent(
*aRangesToDelete.FirstRangeRef()
->GetStartContainer()
->AsContent()
->GetEditingHost(),
BlockInlineCheck::UseComputedDisplayOutsideStyle));
nsresult rv =
mDeleteRangesHandlerConst.ComputeRangesToDeleteRangesWithTransaction(
@ -3463,10 +3480,12 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
->GetEndContainer()
->IsInclusiveDescendantOf(mRightContent));
MOZ_ASSERT_IF(!mLeftContent,
HTMLEditUtils::IsInlineElement(*aRangesToDelete.FirstRangeRef()
->GetStartContainer()
->AsContent()
->GetEditingHost()));
HTMLEditUtils::IsInlineContent(
*aRangesToDelete.FirstRangeRef()
->GetStartContainer()
->AsContent()
->GetEditingHost(),
BlockInlineCheck::UseComputedDisplayOutsideStyle));
// XXX This is also odd. We do we simply use
// `DeleteRangesWithTransaction()` only when **first** range is in
@ -3622,7 +3641,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
// node because the other browsers insert following inputs into there.
if (MayEditActionDeleteAroundCollapsedSelection(
aHTMLEditor.GetEditAction())) {
WSRunScanner scanner(&aEditingHost, startOfRightContent);
WSRunScanner scanner(&aEditingHost, startOfRightContent,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent);
if (maybePreviousText.IsContentEditable() &&
@ -4184,7 +4204,8 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
// First, check there is visible contents before the point in current block.
RefPtr<Element> editingHost = aHTMLEditor.ComputeEditingHost();
WSRunScanner wsScannerForPoint(editingHost, aPoint);
WSRunScanner wsScannerForPoint(
editingHost, aPoint, BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!wsScannerForPoint.StartsFromCurrentBlockBoundary()) {
// If there is visible node before the point, we shouldn't remove the
// parent block.
@ -4230,8 +4251,10 @@ HTMLEditor::AutoDeleteRangesHandler::DeleteParentBlocksWithTransactionIfEmpty(
if (wsScannerForPoint.GetEndReasonContent()->GetNextSibling()) {
WSScanResult scanResult =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
editingHost, EditorRawDOMPoint::After(
*wsScannerForPoint.GetEndReasonContent()));
editingHost,
EditorRawDOMPoint::After(
*wsScannerForPoint.GetEndReasonContent()),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (scanResult.Failed()) {
NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundary() failed");
return NS_ERROR_FAILURE;
@ -4371,7 +4394,7 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteRangesWithTransaction(
caretPoint.IsStartOfContainer()) {
nsIContent* previousEditableContent = HTMLEditUtils::GetPreviousContent(
*caretPoint.GetContainer(), {WalkTreeOption::IgnoreNonEditableNode},
editingHost);
BlockInlineCheck::Unused, editingHost);
if (!previousEditableContent) {
continue;
}
@ -4394,7 +4417,7 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteRangesWithTransaction(
caretPoint.IsEndOfContainer()) {
nsIContent* nextEditableContent = HTMLEditUtils::GetNextContent(
*caretPoint.GetContainer(), {WalkTreeOption::IgnoreNonEditableNode},
editingHost);
BlockInlineCheck::Unused, editingHost);
if (!nextEditableContent) {
continue;
}
@ -4431,10 +4454,10 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteRangesWithTransaction(
EditorBase::HowToHandleCollapsedRange::ExtendBackward
? HTMLEditUtils::GetPreviousContent(
caretPoint, {WalkTreeOption::IgnoreNonEditableNode},
editingHost)
BlockInlineCheck::Unused, editingHost)
: HTMLEditUtils::GetNextContent(
caretPoint, {WalkTreeOption::IgnoreNonEditableNode},
editingHost);
BlockInlineCheck::Unused, editingHost);
if (!editableContent) {
continue;
}
@ -4445,10 +4468,10 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteRangesWithTransaction(
EditorBase::HowToHandleCollapsedRange::ExtendBackward
? HTMLEditUtils::GetPreviousContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
editingHost)
BlockInlineCheck::Unused, editingHost)
: HTMLEditUtils::GetNextContent(
*editableContent, {WalkTreeOption::IgnoreNonEditableNode},
editingHost);
BlockInlineCheck::Unused, editingHost);
}
if (!editableContent) {
continue;
@ -4500,7 +4523,8 @@ Result<CaretPoint, nsresult> HTMLEditor::DeleteTextAndTextNodesWithTransaction(
TreatEmptyTextNodes::RemoveAllEmptyInlineAncestors) {
Element* emptyParentElementToRemove =
HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement(
nodeToRemove, editingHost);
nodeToRemove, BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost);
if (emptyParentElementToRemove) {
nodeToRemove = *emptyParentElementToRemove;
}
@ -4702,10 +4726,12 @@ Result<bool, nsresult> HTMLEditor::AutoDeleteRangesHandler::
const HTMLEditor& aHTMLEditor, const Element& aEditingHost) {
mLeftBlockElement = HTMLEditUtils::GetInclusiveAncestorElement(
mInclusiveDescendantOfLeftBlockElement,
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement);
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
mRightBlockElement = HTMLEditUtils::GetInclusiveAncestorElement(
mInclusiveDescendantOfRightBlockElement,
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement);
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (NS_WARN_IF(!IsSet())) {
mCanJoinBlocks = false;
@ -4782,7 +4808,8 @@ Result<bool, nsresult> HTMLEditor::AutoDeleteRangesHandler::
mPrecedingInvisibleBRElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(),
EditorDOMPoint::AtEndOf(mLeftBlockElement));
EditorDOMPoint::AtEndOf(mLeftBlockElement),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
// `WhiteSpaceVisibilityKeeper::
// MergeFirstLineOfRightBlockElementIntoDescendantLeftBlockElement()`
// returns ignored when:
@ -4812,7 +4839,8 @@ Result<bool, nsresult> HTMLEditor::AutoDeleteRangesHandler::
mPrecedingInvisibleBRElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(),
mPointContainingTheOtherBlockElement);
mPointContainingTheOtherBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
// `WhiteSpaceVisibilityKeeper::
// MergeFirstLineOfRightBlockElementIntoAncestorLeftBlockElement()`
// returns ignored when:
@ -4847,7 +4875,8 @@ Result<bool, nsresult> HTMLEditor::AutoDeleteRangesHandler::
mPrecedingInvisibleBRElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(),
EditorDOMPoint::AtEndOf(mLeftBlockElement));
EditorDOMPoint::AtEndOf(mLeftBlockElement),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
// `WhiteSpaceVisibilityKeeper::
// MergeFirstLineOfRightBlockElementIntoLeftBlockElement()` always
// return "handled".
@ -4909,6 +4938,7 @@ nsresult HTMLEditor::AutoDeleteRangesHandler::AutoBlockElementsJoiner::
*atStart.ContainerAs<nsIContent>(),
{WalkTreeOption::IgnoreDataNodeExceptText,
WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
editingHost)
: nullptr;
if (!nextContent || nextContent != range.StartRef().GetChild()) {
@ -5057,7 +5087,8 @@ Result<EditActionResult, nsresult> HTMLEditor::AutoDeleteRangesHandler::
// Then, users can type text into it like the other browsers.
if (MayEditActionDeleteAroundCollapsedSelection(
aHTMLEditor.GetEditAction())) {
WSRunScanner scanner(&aEditingHost, startOfRightContent);
WSRunScanner scanner(&aEditingHost, startOfRightContent,
BlockInlineCheck::UseComputedDisplayStyle);
WSScanResult maybePreviousText =
scanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(startOfRightContent);
if (maybePreviousText.IsContentEditable() &&
@ -5099,7 +5130,8 @@ HTMLEditor::AutoMoveOneLineHandler::CanMoveOrDeleteSomethingInLine(
if (const Element* blockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*childContent->GetParent(),
HTMLEditUtils::ClosestBlockElement)) {
HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
if (HTMLEditUtils::IsEmptyNode(*blockElement)) {
return false;
}
@ -5168,13 +5200,15 @@ nsresult HTMLEditor::AutoMoveOneLineHandler::Prepare(
aPointInHardLine.IsInContentNode()
? HTMLEditUtils::GetInclusiveAncestorElement(
*aPointInHardLine.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestBlockElement)
HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle)
: nullptr;
mDestInclusiveAncestorBlock =
mPointToInsert.IsInContentNode()
? HTMLEditUtils::GetInclusiveAncestorElement(
*mPointToInsert.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestBlockElement)
HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle)
: nullptr;
mMovingToParentBlock =
mDestInclusiveAncestorBlock && mSrcInclusiveAncestorBlock &&
@ -5211,7 +5245,8 @@ HTMLEditor::AutoMoveOneLineHandler::SplitToMakeTheLineIsolated(
Result<EditorDOMPoint, nsresult> splitResult =
rangesToWrapTheLine
.SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries(
aHTMLEditor, aEditingHost, &aNewContainer);
aHTMLEditor, BlockInlineCheck::UseComputedDisplayOutsideStyle,
aEditingHost, &aNewContainer);
if (MOZ_UNLIKELY(splitResult.isErr())) {
NS_WARNING(
"AutoRangeArray::"
@ -5239,7 +5274,8 @@ Element* HTMLEditor::AutoMoveOneLineHandler::
GetMostDistantInclusiveAncestorBlockInSpecificAncestorElement(
Element& aBlockElement, const Element& aAncestorElement) {
MOZ_ASSERT(aBlockElement.IsInclusiveDescendantOf(&aAncestorElement));
MOZ_ASSERT(HTMLEditUtils::IsBlockElement(aBlockElement));
MOZ_ASSERT(HTMLEditUtils::IsBlockElement(
aBlockElement, BlockInlineCheck::UseComputedDisplayOutsideStyle));
if (&aBlockElement == &aAncestorElement) {
return nullptr;
@ -5250,7 +5286,9 @@ Element* HTMLEditor::AutoMoveOneLineHandler::
if (element == &aAncestorElement) {
return lastBlockAncestor;
}
if (HTMLEditUtils::IsBlockElement(*lastBlockAncestor)) {
if (HTMLEditUtils::IsBlockElement(
*lastBlockAncestor,
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
lastBlockAncestor = element;
}
}
@ -5363,7 +5401,8 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
AutoEditorDOMRangeChildrenInvalidator lockOffsets(movedContentRange);
// If the content is a block element, move all children of it to the
// new container, and then, remove the (probably) empty block element.
if (HTMLEditUtils::IsBlockElement(content)) {
if (HTMLEditUtils::IsBlockElement(
content, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
Result<MoveNodeResult, nsresult> moveChildrenResult =
aHTMLEditor.MoveChildrenWithTransaction(
MOZ_KnownLive(*content->AsElement()), pointToInsert,
@ -5390,13 +5429,15 @@ Result<MoveNodeResult, nsresult> HTMLEditor::AutoMoveOneLineHandler::Run(
// don't want it to appear in the dist paragraph.
else if (content->IsComment() ||
HTMLEditUtils::IsEmptyInlineContainer(
content, {EmptyCheckOption::TreatSingleBRElementAsVisible,
EmptyCheckOption::TreatListItemAsVisible,
EmptyCheckOption::TreatTableCellAsVisible})) {
content,
{EmptyCheckOption::TreatSingleBRElementAsVisible,
EmptyCheckOption::TreatListItemAsVisible,
EmptyCheckOption::TreatTableCellAsVisible},
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
nsCOMPtr<nsIContent> emptyContent =
HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement(
content, &aEditingHost,
pointToInsert.ContainerAs<nsIContent>());
content, BlockInlineCheck::UseComputedDisplayOutsideStyle,
&aEditingHost, pointToInsert.ContainerAs<nsIContent>());
if (!emptyContent) {
emptyContent = content;
}
@ -5491,6 +5532,7 @@ nsresult HTMLEditor::AutoMoveOneLineHandler::
? HTMLEditUtils::GetPreviousContent(
*mTopmostSrcAncestorBlockInDestBlock,
{WalkTreeOption::StopAtBlockBoundary},
BlockInlineCheck::UseComputedDisplayOutsideStyle,
mDestInclusiveAncestorBlock)
: HTMLEditUtils::GetLastLeafContent(
*mDestInclusiveAncestorBlock,
@ -5513,7 +5555,9 @@ nsresult HTMLEditor::AutoMoveOneLineHandler::
if (textNodeEndingWithUnnecessaryLineBreak->TextDataLength() == 1u) {
const RefPtr<Element> inlineElement =
HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement(
*textNodeEndingWithUnnecessaryLineBreak, &aEditingHost);
*textNodeEndingWithUnnecessaryLineBreak,
BlockInlineCheck::UseComputedDisplayOutsideStyle,
&aEditingHost);
nsresult rv = aHTMLEditor.DeleteNodeWithTransaction(
inlineElement ? static_cast<nsIContent&>(*inlineElement)
: static_cast<nsIContent&>(
@ -5593,7 +5637,9 @@ nsresult HTMLEditor::AutoMoveOneLineHandler::
// should remove the parent too.
if (const RefPtr<Element> inlineElement =
HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement(
*lastLineBreakContent, &aEditingHost)) {
*lastLineBreakContent,
BlockInlineCheck::UseComputedDisplayOutsideStyle,
&aEditingHost)) {
nsresult rv = aHTMLEditor.DeleteNodeWithTransaction(*inlineElement);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"EditorBase::DeleteNodeWithTransaction() failed");
@ -6083,7 +6129,8 @@ Element* HTMLEditor::AutoDeleteRangesHandler::AutoEmptyBlockAncestorDeleter::
// Note: do NOT delete table elements this way.
// Note: do NOT delete non-editable block element.
Element* editableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement(
aStartContent, HTMLEditUtils::ClosestEditableBlockElement);
aStartContent, HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!editableBlockElement) {
return nullptr;
}
@ -6108,7 +6155,8 @@ Element* HTMLEditor::AutoDeleteRangesHandler::AutoEmptyBlockAncestorDeleter::
mEmptyInclusiveAncestorBlockElement = editableBlockElement;
editableBlockElement = HTMLEditUtils::GetAncestorElement(
*mEmptyInclusiveAncestorBlockElement,
HTMLEditUtils::ClosestEditableBlockElement);
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
}
if (!mEmptyInclusiveAncestorBlockElement) {
return nullptr;
@ -6268,7 +6316,8 @@ Result<CaretPoint, nsresult> HTMLEditor::AutoDeleteRangesHandler::
EditorDOMPoint::After(mEmptyInclusiveAncestorBlockElement));
MOZ_ASSERT(afterEmptyBlock.IsSet());
if (nsIContent* nextContentOfEmptyBlock = HTMLEditUtils::GetNextContent(
afterEmptyBlock, {}, aHTMLEditor.ComputeEditingHost())) {
afterEmptyBlock, {}, BlockInlineCheck::Unused,
aHTMLEditor.ComputeEditingHost())) {
EditorDOMPoint pt = HTMLEditUtils::GetGoodCaretPointFor<EditorDOMPoint>(
*nextContentOfEmptyBlock, aDirectionAndAmount);
if (!pt.IsSet()) {
@ -6291,7 +6340,7 @@ Result<CaretPoint, nsresult> HTMLEditor::AutoDeleteRangesHandler::
if (nsIContent* previousContentOfEmptyBlock =
HTMLEditUtils::GetPreviousContent(
atEmptyBlock, {WalkTreeOption::IgnoreNonEditableNode},
aHTMLEditor.ComputeEditingHost())) {
BlockInlineCheck::Unused, aHTMLEditor.ComputeEditingHost())) {
EditorDOMPoint pt = HTMLEditUtils::GetGoodCaretPointFor<EditorDOMPoint>(
*previousContentOfEmptyBlock, aDirectionAndAmount);
if (!pt.IsSet()) {
@ -6471,7 +6520,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
// because the following code checks editing host too.
const Element* const maybeNonEditableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*commonAncestor, HTMLEditUtils::ClosestBlockElement);
*commonAncestor, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (NS_WARN_IF(!maybeNonEditableBlockElement)) {
return Err(NS_ERROR_FAILURE);
}
@ -6516,12 +6566,14 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
for (;;) {
WSScanResult backwardScanFromStartResult =
WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary(
editingHost, rangeToDelete.StartRef());
editingHost, rangeToDelete.StartRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (!backwardScanFromStartResult.ReachedCurrentBlockBoundary()) {
break;
}
MOZ_ASSERT(backwardScanFromStartResult.GetContent() ==
WSRunScanner(editingHost, rangeToDelete.StartRef())
WSRunScanner(editingHost, rangeToDelete.StartRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle)
.GetStartReasonContent());
// We want to keep looking up. But stop if we are crossing table
// element boundaries, or if we hit the root.
@ -6559,7 +6611,9 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
if (rangeToDelete.EndRef().GetContainer() != maybeNonEditableBlockElement &&
rangeToDelete.EndRef().GetContainer() != editingHost) {
for (;;) {
WSRunScanner wsScannerAtEnd(editingHost, rangeToDelete.EndRef());
WSRunScanner wsScannerAtEnd(
editingHost, rangeToDelete.EndRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
WSScanResult forwardScanFromEndResult =
wsScannerAtEnd.ScanNextVisibleNodeOrBlockBoundaryFrom(
rangeToDelete.EndRef());
@ -6630,7 +6684,8 @@ HTMLEditor::AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete(
if (const RefPtr<const Element> editableBlockContainingBRElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*atFirstInvisibleBRElement.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElement)) {
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
if (rangeToDelete.Contains(
EditorRawDOMPoint(editableBlockContainingBRElement))) {
return rangeToDelete;

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

@ -283,14 +283,14 @@ AlignStateAtSelection::AlignStateAtSelection(HTMLEditor& aHTMLEditor,
atStartOfSelection.Offset() == atBodyOrDocumentElement.Offset()) {
editTargetContent = HTMLEditUtils::GetNextContent(
atStartOfSelection, {WalkTreeOption::IgnoreNonEditableNode},
aHTMLEditor.ComputeEditingHost());
BlockInlineCheck::Unused, aHTMLEditor.ComputeEditingHost());
if (NS_WARN_IF(!editTargetContent)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
// Otherwise, use first selected node.
// XXX Only for retreiving it, the following block treats all selected
// XXX Only for retrieving it, the following block treats all selected
// ranges. `HTMLEditor` should have
// `GetFirstSelectionRangeExtendedToHardLineStartAndEnd()`.
else {
@ -330,7 +330,8 @@ AlignStateAtSelection::AlignStateAtSelection(HTMLEditor& aHTMLEditor,
const RefPtr<dom::Element> maybeNonEditableBlockElement =
HTMLEditUtils::GetInclusiveAncestorElement(
*editTargetContent, HTMLEditUtils::ClosestBlockElement);
*editTargetContent, HTMLEditUtils::ClosestBlockElement,
BlockInlineCheck::UseHTMLDefaultStyle);
if (NS_WARN_IF(!maybeNonEditableBlockElement)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -487,10 +488,10 @@ ParagraphStateAtSelection::ParagraphStateAtSelection(HTMLEditor& aHTMLEditor,
// We need to append descendant format block if block nodes are not format
// block. This is so we only have to look "up" the hierarchy to find
// format nodes, instead of both up and down.
for (int32_t i = arrayOfContents.Length() - 1; i >= 0; i--) {
auto& content = arrayOfContents[i];
nsAutoString format;
if (HTMLEditUtils::IsBlockElement(content) &&
for (size_t index : Reversed(IntegerRange(arrayOfContents.Length()))) {
OwningNonNull<nsIContent>& content = arrayOfContents[index];
if (HTMLEditUtils::IsBlockElement(content,
BlockInlineCheck::UseHTMLDefaultStyle) &&
!HTMLEditUtils::IsFormatNode(content)) {
// XXX This RemoveObject() call has already been commented out and
// the above comment explained we're trying to replace non-format
@ -527,9 +528,10 @@ ParagraphStateAtSelection::ParagraphStateAtSelection(HTMLEditor& aHTMLEditor,
MOZ_ASSERT(content->NodeInfo()->NameAtom());
paragraphStateOfNode = content->NodeInfo()->NameAtom();
}
// Ignore non-format block node since its children have been appended
// Ignore inline contents since its children have been appended
// the list above so that we'll handle this descendants later.
else if (HTMLEditUtils::IsBlockElement(content)) {
else if (HTMLEditUtils::IsBlockElement(
content, BlockInlineCheck::UseHTMLDefaultStyle)) {
continue;
}
// If we meet an inline node, let's get its parent format.
@ -566,7 +568,8 @@ ParagraphStateAtSelection::ParagraphStateAtSelection(HTMLEditor& aHTMLEditor,
void ParagraphStateAtSelection::AppendDescendantFormatNodesAndFirstInlineNode(
nsTArray<OwningNonNull<nsIContent>>& aArrayOfContents,
dom::Element& aNonFormatBlockElement) {
MOZ_ASSERT(HTMLEditUtils::IsBlockElement(aNonFormatBlockElement));
MOZ_ASSERT(HTMLEditUtils::IsBlockElement(
aNonFormatBlockElement, BlockInlineCheck::UseHTMLDefaultStyle));
MOZ_ASSERT(!HTMLEditUtils::IsFormatNode(&aNonFormatBlockElement));
// We only need to place any one inline inside this node onto
@ -576,8 +579,9 @@ void ParagraphStateAtSelection::AppendDescendantFormatNodesAndFirstInlineNode(
bool foundInline = false;
for (nsIContent* childContent = aNonFormatBlockElement.GetFirstChild();
childContent; childContent = childContent->GetNextSibling()) {
bool isBlock = HTMLEditUtils::IsBlockElement(*childContent);
bool isFormat = HTMLEditUtils::IsFormatNode(childContent);
const bool isBlock = HTMLEditUtils::IsBlockElement(
*childContent, BlockInlineCheck::UseHTMLDefaultStyle);
const bool isFormat = HTMLEditUtils::IsFormatNode(childContent);
// If the child is a non-format block element, let's check its children
// recursively.
if (isBlock && !isFormat) {
@ -627,12 +631,12 @@ nsresult ParagraphStateAtSelection::CollectEditableFormatNodesInSelection(
}
// Pre-process our list of nodes
for (int32_t i = aArrayOfContents.Length() - 1; i >= 0; i--) {
OwningNonNull<nsIContent> content = aArrayOfContents[i];
for (size_t index : Reversed(IntegerRange(aArrayOfContents.Length()))) {
OwningNonNull<nsIContent> content = aArrayOfContents[index];
// Remove all non-editable nodes. Leave them be.
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
aArrayOfContents.RemoveElementAt(i);
aArrayOfContents.RemoveElementAt(index);
continue;
}
@ -642,9 +646,9 @@ nsresult ParagraphStateAtSelection::CollectEditableFormatNodesInSelection(
if (HTMLEditUtils::IsAnyTableElement(content) ||
HTMLEditUtils::IsAnyListElement(content) ||
HTMLEditUtils::IsListItem(content)) {
aArrayOfContents.RemoveElementAt(i);
aArrayOfContents.RemoveElementAt(index);
HTMLEditUtils::CollectChildren(
content, aArrayOfContents, i,
content, aArrayOfContents, index,
{CollectChildrenOption::CollectListChildren,
CollectChildrenOption::CollectTableChildren});
}

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

@ -768,7 +768,9 @@ bool HTMLEditor::AutoInlineStyleSetter::ElementIsGoodContainerToSetStyle(
// E.g., we don't want to create new <span> when
// `<p>{ <span>abc</span> }</p>`.
if (aStyledElement.GetParentElement() &&
HTMLEditUtils::IsBlockElement(*aStyledElement.GetParentElement())) {
HTMLEditUtils::IsBlockElement(
*aStyledElement.GetParentElement(),
BlockInlineCheck::UseComputedDisplayStyle)) {
for (nsIContent* previousSibling = aStyledElement.GetPreviousSibling();
previousSibling;
previousSibling = previousSibling->GetPreviousSibling()) {
@ -1499,7 +1501,9 @@ nsIContent* HTMLEditor::AutoInlineStyleSetter::GetNextEditableInlineContent(
if (parent == aLimiter ||
!EditorUtils::IsEditableContent(*parent, EditorType::HTML) ||
(parent->IsElement() &&
(HTMLEditUtils::IsBlockElement(*parent->AsElement()) ||
(HTMLEditUtils::IsBlockElement(
*parent->AsElement(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(*parent->AsElement())))) {
return nullptr;
}
@ -1512,7 +1516,9 @@ nsIContent* HTMLEditor::AutoInlineStyleSetter::GetNextEditableInlineContent(
return nextContentInRange &&
EditorUtils::IsEditableContent(*nextContentInRange,
EditorType::HTML) &&
!HTMLEditUtils::IsBlockElement(*nextContentInRange)
!HTMLEditUtils::IsBlockElement(
*nextContentInRange,
BlockInlineCheck::UseComputedDisplayOutsideStyle)
? nextContentInRange
: nullptr;
}
@ -1525,7 +1531,9 @@ nsIContent* HTMLEditor::AutoInlineStyleSetter::GetPreviousEditableInlineContent(
if (parent == aLimiter ||
!EditorUtils::IsEditableContent(*parent, EditorType::HTML) ||
(parent->IsElement() &&
(HTMLEditUtils::IsBlockElement(*parent->AsElement()) ||
(HTMLEditUtils::IsBlockElement(
*parent->AsElement(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(*parent->AsElement())))) {
return nullptr;
}
@ -1538,7 +1546,9 @@ nsIContent* HTMLEditor::AutoInlineStyleSetter::GetPreviousEditableInlineContent(
return previousContentInRange &&
EditorUtils::IsEditableContent(*previousContentInRange,
EditorType::HTML) &&
!HTMLEditUtils::IsBlockElement(*previousContentInRange)
!HTMLEditUtils::IsBlockElement(
*previousContentInRange,
BlockInlineCheck::UseComputedDisplayOutsideStyle)
? previousContentInRange
: nullptr;
}
@ -1581,7 +1591,8 @@ EditorRawDOMPoint HTMLEditor::AutoInlineStyleSetter::GetShrunkenRangeStart(
while (nsIContent* child = startPoint.GetChild()) {
// We shouldn't cross editable and block boundary.
if (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
HTMLEditUtils::IsBlockElement(*child)) {
HTMLEditUtils::IsBlockElement(
*child, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
break;
}
// If we reach a text node, the minimized range starts from start of it.
@ -1654,7 +1665,8 @@ EditorRawDOMPoint HTMLEditor::AutoInlineStyleSetter::GetShrunkenRangeEnd(
while (nsIContent* child = endPoint.GetPreviousSiblingOfChild()) {
// We shouldn't cross editable and block boundary.
if (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
HTMLEditUtils::IsBlockElement(*child)) {
HTMLEditUtils::IsBlockElement(
*child, BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
break;
}
// If we reach a text node, the minimized range starts from start of it.
@ -1712,7 +1724,8 @@ EditorRawDOMPoint HTMLEditor::AutoInlineStyleSetter::
for (Element* parent :
startPoint.GetContainer()->InclusiveAncestorsOfType<Element>()) {
if (!EditorUtils::IsEditableContent(*parent, EditorType::HTML) ||
HTMLEditUtils::IsBlockElement(*parent) ||
HTMLEditUtils::IsBlockElement(
*parent, BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(*parent)) {
break;
}
@ -1757,7 +1770,8 @@ EditorRawDOMPoint HTMLEditor::AutoInlineStyleSetter::
for (Element* parent :
endPoint.GetContainer()->InclusiveAncestorsOfType<Element>()) {
if (!EditorUtils::IsEditableContent(*parent, EditorType::HTML) ||
HTMLEditUtils::IsBlockElement(*parent) ||
HTMLEditUtils::IsBlockElement(
*parent, BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(*parent)) {
break;
}
@ -1800,7 +1814,8 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter::
*aStartPoint.ContainerAs<nsIContent>(), EditorType::HTML) ||
(aStartPoint.ContainerAs<nsIContent>()->IsElement() &&
(HTMLEditUtils::IsBlockElement(
*aStartPoint.ContainerAs<Element>()) ||
*aStartPoint.ContainerAs<Element>(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(
*aStartPoint.ContainerAs<Element>())))) {
break;
@ -1813,7 +1828,9 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter::
if (!EditorUtils::IsEditableContent(*aEndPoint.ContainerAs<nsIContent>(),
EditorType::HTML) ||
(aEndPoint.ContainerAs<nsIContent>()->IsElement() &&
(HTMLEditUtils::IsBlockElement(*aEndPoint.ContainerAs<Element>()) ||
(HTMLEditUtils::IsBlockElement(
*aEndPoint.ContainerAs<Element>(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
HTMLEditUtils::IsDisplayInsideFlowRoot(
*aEndPoint.ContainerAs<Element>())))) {
break;
@ -1862,7 +1879,8 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter::
*aStartPoint.ChildAs<nsStyledElement>())) &&
// but don't cross block boundary at climbing up the tree
!HTMLEditUtils::IsBlockElement(
*aStartPoint.ContainerAs<nsIContent>()) &&
*aStartPoint.ContainerAs<nsIContent>(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) &&
// and the container is a good editable element to set CSS style
aStartPoint.GetContainerAs<nsStyledElement>() &&
ElementIsGoodContainerToSetStyle(
@ -1879,7 +1897,9 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter::
!ElementIsGoodContainerToSetStyle(
*aEndPoint.GetPreviousSiblingOfChildAs<nsStyledElement>())) &&
// but don't cross block boundary at climbing up the tree
!HTMLEditUtils::IsBlockElement(*aEndPoint.ContainerAs<nsIContent>()) &&
!HTMLEditUtils::IsBlockElement(
*aEndPoint.ContainerAs<nsIContent>(),
BlockInlineCheck::UseComputedDisplayOutsideStyle) &&
// and the container is a good editable element to set CSS style
aEndPoint.GetContainerAs<nsStyledElement>() &&
ElementIsGoodContainerToSetStyle(
@ -1913,12 +1933,14 @@ HTMLEditor::AutoInlineStyleSetter::ExtendOrShrinkRangeToApplyTheStyle(
EditorDOMRange range(aRange);
if (range.EndRef().IsInContentNode()) {
WSScanResult nextContentData =
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(&aEditingHost,
range.EndRef());
WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(
&aEditingHost, range.EndRef(),
BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (nextContentData.ReachedInvisibleBRElement() &&
nextContentData.BRElementPtr()->GetParentElement() &&
HTMLEditUtils::IsInlineElement(
*nextContentData.BRElementPtr()->GetParentElement())) {
HTMLEditUtils::IsInlineContent(
*nextContentData.BRElementPtr()->GetParentElement(),
BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
range.SetEnd(EditorDOMPoint::After(*nextContentData.BRElementPtr()));
MOZ_ASSERT(range.EndRef().IsSet());
}
@ -2123,7 +2145,9 @@ HTMLEditor::SplitAncestorStyledInlineElementsAt(
AutoTArray<OwningNonNull<Element>, 24> arrayOfParents;
for (Element* element :
aPointToSplit.GetContainer()->InclusiveAncestorsOfType<Element>()) {
if (HTMLEditUtils::IsBlockElement(*element) || !element->GetParent() ||
if (HTMLEditUtils::IsBlockElement(
*element, BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
!element->GetParent() ||
!EditorUtils::IsEditableContent(*element->GetParent(),
EditorType::HTML)) {
break;
@ -2529,7 +2553,8 @@ Result<EditorDOMPoint, nsresult> HTMLEditor::ClearStyleAt(
emptyInlineContainerElements,
{EmptyCheckOption::TreatSingleBRElementAsVisible,
EmptyCheckOption::TreatListItemAsVisible,
EmptyCheckOption::TreatTableCellAsVisible});
EmptyCheckOption::TreatTableCellAsVisible},
BlockInlineCheck::UseComputedDisplayOutsideStyle);
for (const OwningNonNull<nsIContent>& emptyInlineContainerElement :
emptyInlineContainerElements) {
// MOZ_KnownLive(emptyInlineContainerElement) due to bug 1622253.

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

@ -68,11 +68,14 @@ template nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
HTMLEditor& aHTMLEditor, const EditorDOMPointInText& aScanStartPoint);
template WSRunScanner::TextFragmentData::TextFragmentData(
const EditorDOMPoint& aPoint, const Element* aEditingHost);
const EditorDOMPoint& aPoint, const Element* aEditingHost,
BlockInlineCheck aBlockInlineCheck);
template WSRunScanner::TextFragmentData::TextFragmentData(
const EditorRawDOMPoint& aPoint, const Element* aEditingHost);
const EditorRawDOMPoint& aPoint, const Element* aEditingHost,
BlockInlineCheck aBlockInlineCheck);
template WSRunScanner::TextFragmentData::TextFragmentData(
const EditorDOMPointInText& aPoint, const Element* aEditingHost);
const EditorDOMPointInText& aPoint, const Element* aEditingHost,
BlockInlineCheck aBlockInlineCheck);
NS_INSTANTIATE_CONST_METHOD_RETURNING_ANY_EDITOR_DOM_POINT(
WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint,
@ -266,7 +269,8 @@ Result<EditActionResult, nsresult> WhiteSpaceVisibilityKeeper::
RefPtr<HTMLBRElement> invisibleBRElementAtEndOfLeftBlockElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(),
EditorDOMPoint::AtEndOf(aLeftBlockElement));
EditorDOMPoint::AtEndOf(aLeftBlockElement),
BlockInlineCheck::UseComputedDisplayStyle);
NS_ASSERTION(
aPrecedingInvisibleBRElement == invisibleBRElementAtEndOfLeftBlockElement,
"The preceding invisible BR element computation was different");
@ -470,7 +474,8 @@ Result<EditActionResult, nsresult> WhiteSpaceVisibilityKeeper::
// Do br adjustment.
RefPtr<HTMLBRElement> invisibleBRElementBeforeLeftBlockElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(), atLeftBlockChild);
aHTMLEditor.ComputeEditingHost(), atLeftBlockChild,
BlockInlineCheck::UseComputedDisplayStyle);
NS_ASSERTION(
aPrecedingInvisibleBRElement == invisibleBRElementBeforeLeftBlockElement,
"The preceding invisible BR element computation was different");
@ -705,7 +710,8 @@ Result<EditActionResult, nsresult> WhiteSpaceVisibilityKeeper::
RefPtr<HTMLBRElement> invisibleBRElementAtEndOfLeftBlockElement =
WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound(
aHTMLEditor.ComputeEditingHost(),
EditorDOMPoint::AtEndOf(aLeftBlockElement));
EditorDOMPoint::AtEndOf(aLeftBlockElement),
BlockInlineCheck::UseComputedDisplayStyle);
NS_ASSERTION(
aPrecedingInvisibleBRElement == invisibleBRElementAtEndOfLeftBlockElement,
"The preceding invisible BR element computation was different");
@ -819,8 +825,8 @@ WhiteSpaceVisibilityKeeper::InsertBRElement(
// meanwhile, the pre case is handled in HandleInsertText() in
// HTMLEditSubActionHandler.cpp
TextFragmentData textFragmentDataAtInsertionPoint(aPointToInsert,
&aEditingHost);
TextFragmentData textFragmentDataAtInsertionPoint(
aPointToInsert, &aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (MOZ_UNLIKELY(
NS_WARN_IF(!textFragmentDataAtInsertionPoint.IsInitialized()))) {
return Err(NS_ERROR_FAILURE);
@ -1034,8 +1040,9 @@ Result<InsertTextResult, nsresult> WhiteSpaceVisibilityKeeper::ReplaceText(
return InsertTextResult();
}
TextFragmentData textFragmentDataAtStart(aRangeToBeReplaced.StartRef(),
&aEditingHost);
TextFragmentData textFragmentDataAtStart(
aRangeToBeReplaced.StartRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (MOZ_UNLIKELY(NS_WARN_IF(!textFragmentDataAtStart.IsInitialized()))) {
return Err(NS_ERROR_FAILURE);
}
@ -1045,7 +1052,8 @@ Result<InsertTextResult, nsresult> WhiteSpaceVisibilityKeeper::ReplaceText(
TextFragmentData textFragmentDataAtEnd =
aRangeToBeReplaced.Collapsed()
? textFragmentDataAtStart
: TextFragmentData(aRangeToBeReplaced.EndRef(), &aEditingHost);
: TextFragmentData(aRangeToBeReplaced.EndRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (MOZ_UNLIKELY(NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized()))) {
return Err(NS_ERROR_FAILURE);
}
@ -1410,7 +1418,8 @@ Result<CaretPoint, nsresult>
WhiteSpaceVisibilityKeeper::DeletePreviousWhiteSpace(
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aPoint,
const Element& aEditingHost) {
TextFragmentData textFragmentDataAtDeletion(aPoint, &aEditingHost);
TextFragmentData textFragmentDataAtDeletion(
aPoint, &aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtDeletion.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -1522,7 +1531,8 @@ Result<CaretPoint, nsresult>
WhiteSpaceVisibilityKeeper::DeleteInclusiveNextWhiteSpace(
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aPoint,
const Element& aEditingHost) {
TextFragmentData textFragmentDataAtDeletion(aPoint, &aEditingHost);
TextFragmentData textFragmentDataAtDeletion(
aPoint, &aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtDeletion.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -1713,7 +1723,7 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
MOZ_ASSERT(aPoint.IsSet());
if (!TextFragmentDataAtStartRef().IsInitialized()) {
return WSScanResult(nullptr, WSType::UnexpectedError);
return WSScanResult(nullptr, WSType::UnexpectedError, mBlockInlineCheck);
}
// If the range has visible text and start of the visible text is before
@ -1726,7 +1736,8 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck);
}
const auto atPreviousChar =
GetPreviousEditableCharPoint<EditorRawDOMPointInText>(aPoint);
@ -1736,7 +1747,8 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
return WSScanResult(atPreviousChar.template NextPoint<EditorDOMPoint>(),
atPreviousChar.IsCharCollapsibleASCIISpaceOrNBSP()
? WSType::CollapsibleWhiteSpaces
: WSType::NonCollapsibleCharacters);
: WSType::NonCollapsibleCharacters,
mBlockInlineCheck);
}
}
@ -1746,10 +1758,12 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
// In this case, TextFragmentDataAtStartRef().StartRef().Offset() is not
// meaningful.
return WSScanResult(TextFragmentDataAtStartRef().GetStartReasonContent(),
TextFragmentDataAtStartRef().StartRawReason());
TextFragmentDataAtStartRef().StartRawReason(),
mBlockInlineCheck);
}
return WSScanResult(TextFragmentDataAtStartRef().StartRef(),
TextFragmentDataAtStartRef().StartRawReason());
TextFragmentDataAtStartRef().StartRawReason(),
mBlockInlineCheck);
}
template <typename PT, typename CT>
@ -1758,7 +1772,7 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
MOZ_ASSERT(aPoint.IsSet());
if (!TextFragmentDataAtStartRef().IsInitialized()) {
return WSScanResult(nullptr, WSType::UnexpectedError);
return WSScanResult(nullptr, WSType::UnexpectedError, mBlockInlineCheck);
}
// If the range has visible text and aPoint equals or is before the end of the
@ -1771,7 +1785,8 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
// things now. Whether keep scanning editable things or not should be
// considered by the caller.
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent,
mBlockInlineCheck);
}
const auto atNextChar =
GetInclusiveNextEditableCharPoint<EditorDOMPoint>(aPoint);
@ -1781,7 +1796,8 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
!atNextChar.IsEndOfContainer() &&
atNextChar.IsCharCollapsibleASCIISpaceOrNBSP()
? WSType::CollapsibleWhiteSpaces
: WSType::NonCollapsibleCharacters);
: WSType::NonCollapsibleCharacters,
mBlockInlineCheck);
}
}
@ -1791,16 +1807,19 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
// In this case, TextFragmentDataAtStartRef().EndRef().Offset() is not
// meaningful.
return WSScanResult(TextFragmentDataAtStartRef().GetEndReasonContent(),
TextFragmentDataAtStartRef().EndRawReason());
TextFragmentDataAtStartRef().EndRawReason(),
mBlockInlineCheck);
}
return WSScanResult(TextFragmentDataAtStartRef().EndRef(),
TextFragmentDataAtStartRef().EndRawReason());
TextFragmentDataAtStartRef().EndRawReason(),
mBlockInlineCheck);
}
template <typename EditorDOMPointType>
WSRunScanner::TextFragmentData::TextFragmentData(
const EditorDOMPointType& aPoint, const Element* aEditingHost)
: mEditingHost(aEditingHost) {
const EditorDOMPointType& aPoint, const Element* aEditingHost,
BlockInlineCheck aBlockInlineCheck)
: mEditingHost(aEditingHost), mBlockInlineCheck(aBlockInlineCheck) {
if (!aPoint.IsSetAndValid()) {
NS_WARNING("aPoint was invalid");
return;
@ -1828,7 +1847,8 @@ WSRunScanner::TextFragmentData::TextFragmentData(
const Element* editableBlockElementOrInlineEditingHost =
HTMLEditUtils::GetInclusiveAncestorElement(
*mScanStartPoint.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost);
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
aBlockInlineCheck);
if (!editableBlockElementOrInlineEditingHost) {
NS_WARNING(
"HTMLEditUtils::GetInclusiveAncestorElement(HTMLEditUtils::"
@ -1839,14 +1859,14 @@ WSRunScanner::TextFragmentData::TextFragmentData(
mStart = BoundaryData::ScanCollapsibleWhiteSpaceStartFrom(
mScanStartPoint, *editableBlockElementOrInlineEditingHost, mEditingHost,
&mNBSPData);
&mNBSPData, aBlockInlineCheck);
MOZ_ASSERT_IF(mStart.IsNonCollapsibleCharacters(),
!mStart.PointRef().IsPreviousCharPreformattedNewLine());
MOZ_ASSERT_IF(mStart.IsPreformattedLineBreak(),
mStart.PointRef().IsPreviousCharPreformattedNewLine());
mEnd = BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
mScanStartPoint, *editableBlockElementOrInlineEditingHost, mEditingHost,
&mNBSPData);
&mNBSPData, aBlockInlineCheck);
MOZ_ASSERT_IF(mEnd.IsNonCollapsibleCharacters(),
!mEnd.PointRef().IsCharPreformattedNewLine());
MOZ_ASSERT_IF(mEnd.IsPreformattedLineBreak(),
@ -1857,7 +1877,8 @@ WSRunScanner::TextFragmentData::TextFragmentData(
template <typename EditorDOMPointType>
Maybe<WSRunScanner::TextFragmentData::BoundaryData> WSRunScanner::
TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceStartInTextNode(
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData) {
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aPoint.IsSetAndValid());
MOZ_DIAGNOSTIC_ASSERT(aPoint.IsInTextNode());
@ -1919,14 +1940,15 @@ template <typename EditorDOMPointType>
WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
BoundaryData::ScanCollapsibleWhiteSpaceStartFrom(
const EditorDOMPointType& aPoint,
const Element& aEditableBlockParentOrTopmostEditableInlineContent,
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData) {
const Element& aEditableBlockParentOrTopmostEditableInlineElement,
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aPoint.IsSetAndValid());
if (aPoint.IsInTextNode() && !aPoint.IsStartOfContainer()) {
Maybe<BoundaryData> startInTextNode =
BoundaryData::ScanCollapsibleWhiteSpaceStartInTextNode(aPoint,
aNBSPData);
BoundaryData::ScanCollapsibleWhiteSpaceStartInTextNode(
aPoint, aNBSPData, aBlockInlineCheck);
if (startInTextNode.isSome()) {
return startInTextNode.ref();
}
@ -1934,27 +1956,29 @@ WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
// preceding nodes.
return BoundaryData::ScanCollapsibleWhiteSpaceStartFrom(
EditorDOMPoint(aPoint.template ContainerAs<Text>(), 0),
aEditableBlockParentOrTopmostEditableInlineContent, aEditingHost,
aNBSPData);
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData, aBlockInlineCheck);
}
// Then, we need to check previous leaf node.
nsIContent* previousLeafContentOrBlock =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineContent,
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
aPoint, aEditableBlockParentOrTopmostEditableInlineElement,
{LeafNodeType::LeafNodeOrNonEditableNode}, aBlockInlineCheck,
aEditingHost);
if (!previousLeafContentOrBlock) {
// no prior node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineContent
// aEditableBlockParentOrTopmostEditableInlineElement
// mReasonContent can be either a block element or any non-editable
// content in this case.
return BoundaryData(aPoint,
const_cast<Element&>(
aEditableBlockParentOrTopmostEditableInlineContent),
aEditableBlockParentOrTopmostEditableInlineElement),
WSType::CurrentBlockBoundary);
}
if (HTMLEditUtils::IsBlockElement(*previousLeafContentOrBlock)) {
if (HTMLEditUtils::IsBlockElement(*previousLeafContentOrBlock,
aBlockInlineCheck)) {
return BoundaryData(aPoint, *previousLeafContentOrBlock,
WSType::OtherBlockBoundary);
}
@ -1975,14 +1999,14 @@ WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
// looking for the previous one.
return BoundaryData::ScanCollapsibleWhiteSpaceStartFrom(
EditorDOMPointInText(previousLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent, aEditingHost,
aNBSPData);
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData, aBlockInlineCheck);
}
Maybe<BoundaryData> startInTextNode =
BoundaryData::ScanCollapsibleWhiteSpaceStartInTextNode(
EditorDOMPointInText::AtEndOf(*previousLeafContentOrBlock->AsText()),
aNBSPData);
aNBSPData, aBlockInlineCheck);
if (startInTextNode.isSome()) {
return startInTextNode.ref();
}
@ -1991,15 +2015,16 @@ WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
// preceding nodes.
return BoundaryData::ScanCollapsibleWhiteSpaceStartFrom(
EditorDOMPointInText(previousLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineContent, aEditingHost,
aNBSPData);
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData, aBlockInlineCheck);
}
// static
template <typename EditorDOMPointType>
Maybe<WSRunScanner::TextFragmentData::BoundaryData> WSRunScanner::
TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndInTextNode(
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData) {
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aPoint.IsSetAndValid());
MOZ_DIAGNOSTIC_ASSERT(aPoint.IsInTextNode());
@ -2060,12 +2085,14 @@ WSRunScanner::TextFragmentData::BoundaryData
WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
const EditorDOMPointType& aPoint,
const Element& aEditableBlockParentOrTopmostEditableInlineElement,
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData) {
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aPoint.IsSetAndValid());
if (aPoint.IsInTextNode() && !aPoint.IsEndOfContainer()) {
Maybe<BoundaryData> endInTextNode =
BoundaryData::ScanCollapsibleWhiteSpaceEndInTextNode(aPoint, aNBSPData);
BoundaryData::ScanCollapsibleWhiteSpaceEndInTextNode(aPoint, aNBSPData,
aBlockInlineCheck);
if (endInTextNode.isSome()) {
return endInTextNode.ref();
}
@ -2074,14 +2101,15 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
return BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
EditorDOMPointInText::AtEndOf(*aPoint.template ContainerAs<Text>()),
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData);
aNBSPData, aBlockInlineCheck);
}
// Then, we need to check next leaf node.
nsIContent* nextLeafContentOrBlock =
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
aPoint, aEditableBlockParentOrTopmostEditableInlineElement,
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, aBlockInlineCheck,
aEditingHost);
if (!nextLeafContentOrBlock) {
// no next node means we exhausted
// aEditableBlockParentOrTopmostEditableInlineElement
@ -2093,7 +2121,8 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
WSType::CurrentBlockBoundary);
}
if (HTMLEditUtils::IsBlockElement(*nextLeafContentOrBlock)) {
if (HTMLEditUtils::IsBlockElement(*nextLeafContentOrBlock,
aBlockInlineCheck)) {
// we encountered a new block. therefore no more ws.
return BoundaryData(aPoint, *nextLeafContentOrBlock,
WSType::OtherBlockBoundary);
@ -2117,12 +2146,13 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
return BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
EditorDOMPointInText(nextLeafContentOrBlock->AsText(), 0),
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData);
aNBSPData, aBlockInlineCheck);
}
Maybe<BoundaryData> endInTextNode =
BoundaryData::ScanCollapsibleWhiteSpaceEndInTextNode(
EditorDOMPointInText(nextLeafContentOrBlock->AsText(), 0), aNBSPData);
EditorDOMPointInText(nextLeafContentOrBlock->AsText(), 0), aNBSPData,
aBlockInlineCheck);
if (endInTextNode.isSome()) {
return endInTextNode.ref();
}
@ -2132,7 +2162,7 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
return BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
EditorDOMPointInText::AtEndOf(*nextLeafContentOrBlock->AsText()),
aEditableBlockParentOrTopmostEditableInlineElement, aEditingHost,
aNBSPData);
aNBSPData, aBlockInlineCheck);
}
const EditorDOMRange&
@ -2375,12 +2405,15 @@ Result<CaretPoint, nsresult> WhiteSpaceVisibilityKeeper::
NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT |
NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
TextFragmentData textFragmentDataAtStart(rangeToDelete.StartRef(),
&aEditingHost);
TextFragmentData textFragmentDataAtStart(
rangeToDelete.StartRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtStart.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
TextFragmentData textFragmentDataAtEnd(rangeToDelete.EndRef(), &aEditingHost);
TextFragmentData textFragmentDataAtEnd(
rangeToDelete.EndRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -2492,9 +2525,11 @@ Result<CaretPoint, nsresult> WhiteSpaceVisibilityKeeper::
// should retrieve the latest data for avoiding to delete/replace
// unexpected range.
textFragmentDataAtStart =
TextFragmentData(rangeToDelete.StartRef(), &aEditingHost);
TextFragmentData(rangeToDelete.StartRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
textFragmentDataAtEnd =
TextFragmentData(rangeToDelete.EndRef(), &aEditingHost);
TextFragmentData(rangeToDelete.EndRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
}
}
ReplaceRangeData replaceRangeDataAtStart =
@ -2697,7 +2732,8 @@ nsresult
WhiteSpaceVisibilityKeeper::MakeSureToKeepVisibleWhiteSpacesVisibleAfterSplit(
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aPointToSplit) {
TextFragmentData textFragmentDataAtSplitPoint(
aPointToSplit, aHTMLEditor.ComputeEditingHost());
aPointToSplit, aHTMLEditor.ComputeEditingHost(),
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtSplitPoint.IsInitialized())) {
return NS_ERROR_FAILURE;
}
@ -2846,7 +2882,8 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
*mScanStartPoint.ContainerAs<nsIContent>(), EditorType::HTML)
? HTMLEditUtils::GetInclusiveAncestorElement(
*mScanStartPoint.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost)
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
mBlockInlineCheck)
: nullptr;
if (NS_WARN_IF(!editableBlockElementOrInlineEditingHost)) {
// Meaning that the container of `mScanStartPoint` is not editable.
@ -2858,11 +2895,13 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*point.ContainerAs<nsIContent>(),
*editableBlockElementOrInlineEditingHost,
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, mBlockInlineCheck,
mEditingHost);
nextContent;
nextContent = HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
*nextContent, *editableBlockElementOrInlineEditingHost,
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
{LeafNodeType::LeafNodeOrNonEditableNode}, mBlockInlineCheck,
mEditingHost)) {
if (!nextContent->IsText() || !nextContent->IsEditable()) {
if (nextContent == GetEndReasonContent()) {
break; // Reached end of current runs.
@ -2927,7 +2966,8 @@ EditorDOMPointType WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
*mScanStartPoint.ContainerAs<nsIContent>(), EditorType::HTML)
? HTMLEditUtils::GetInclusiveAncestorElement(
*mScanStartPoint.ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost)
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
mBlockInlineCheck)
: nullptr;
if (NS_WARN_IF(!editableBlockElementOrInlineEditingHost)) {
// Meaning that the container of `mScanStartPoint` is not editable.
@ -2939,12 +2979,14 @@ EditorDOMPointType WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*point.ContainerAs<nsIContent>(),
*editableBlockElementOrInlineEditingHost,
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
{LeafNodeType::LeafNodeOrNonEditableNode}, mBlockInlineCheck,
mEditingHost);
previousContent;
previousContent =
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
*previousContent, *editableBlockElementOrInlineEditingHost,
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
{LeafNodeType::LeafNodeOrNonEditableNode}, mBlockInlineCheck,
mEditingHost)) {
if (!previousContent->IsText() || !previousContent->IsEditable()) {
if (previousContent == GetStartReasonContent()) {
break; // Reached start of current runs.
@ -2970,7 +3012,8 @@ EditorDOMPointType WSRunScanner::GetAfterLastVisiblePoint(
!atLastCharOfTextNode.IsCharCollapsibleASCIISpace()) {
return EditorDOMPointType::AtEndOf(aTextNode);
}
TextFragmentData textFragmentData(atLastCharOfTextNode, aAncestorLimiter);
TextFragmentData textFragmentData(atLastCharOfTextNode, aAncestorLimiter,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentData.IsInitialized())) {
return EditorDOMPointType(); // TODO: Make here return error with Err.
}
@ -2992,7 +3035,8 @@ EditorDOMPointType WSRunScanner::GetFirstVisiblePoint(
atStartOfTextNode.IsCharCollapsibleASCIISpace()) {
return atStartOfTextNode.To<EditorDOMPointType>();
}
TextFragmentData textFragmentData(atStartOfTextNode, aAncestorLimiter);
TextFragmentData textFragmentData(atStartOfTextNode, aAncestorLimiter,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentData.IsInitialized())) {
return EditorDOMPointType(); // TODO: Make here return error with Err.
}
@ -3290,7 +3334,8 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
MOZ_ASSERT(EditorUtils::IsEditableContent(
*aPoint.template ContainerAs<nsIContent>(), EditorType::HTML));
Element* editingHost = aHTMLEditor.ComputeEditingHost();
TextFragmentData textFragmentData(aPoint, editingHost);
TextFragmentData textFragmentData(aPoint, editingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentData.IsInitialized())) {
return NS_ERROR_FAILURE;
}
@ -3359,7 +3404,8 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
if (visibleWhiteSpaces.EndsByBlockBoundary() &&
aPoint.IsInContentNode()) {
bool insertBRElement = HTMLEditUtils::IsBlockElement(
*aPoint.template ContainerAs<nsIContent>());
*aPoint.template ContainerAs<nsIContent>(),
BlockInlineCheck::UseComputedDisplayStyle);
if (!insertBRElement) {
NS_ASSERTION(
EditorUtils::IsEditableContent(
@ -3373,7 +3419,8 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt(
*aPoint.template ContainerAs<nsIContent>(), EditorType::HTML)
? HTMLEditUtils::GetInclusiveAncestorElement(
*aPoint.template ContainerAs<nsIContent>(),
HTMLEditUtils::ClosestEditableBlockElement)
HTMLEditUtils::ClosestEditableBlockElement,
BlockInlineCheck::UseComputedDisplayStyle)
: nullptr;
insertBRElement = !!editableBlockElement;
}
@ -3732,7 +3779,8 @@ WhiteSpaceVisibilityKeeper::DeleteInvisibleASCIIWhiteSpaces(
HTMLEditor& aHTMLEditor, const EditorDOMPoint& aPoint) {
MOZ_ASSERT(aPoint.IsSet());
Element* editingHost = aHTMLEditor.ComputeEditingHost();
TextFragmentData textFragmentData(aPoint, editingHost);
TextFragmentData textFragmentData(aPoint, editingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentData.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -3900,7 +3948,8 @@ WSRunScanner::GetRangeInTextNodesToBackspaceFrom(const EditorDOMPoint& aPoint,
// `WhiteSpaceVisibilityKeeper::DeletePreviousWhiteSpace()`
MOZ_ASSERT(aPoint.IsSetAndValid());
TextFragmentData textFragmentDataAtCaret(aPoint, &aEditingHost);
TextFragmentData textFragmentDataAtCaret(
aPoint, &aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtCaret.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -3966,11 +4015,13 @@ WSRunScanner::GetRangeInTextNodesToBackspaceFrom(const EditorDOMPoint& aPoint,
// And also delete invisible white-spaces if they become visible.
TextFragmentData textFragmentDataAtStart =
rangeToDelete.StartRef() != aPoint
? TextFragmentData(rangeToDelete.StartRef(), &aEditingHost)
? TextFragmentData(rangeToDelete.StartRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle)
: textFragmentDataAtCaret;
TextFragmentData textFragmentDataAtEnd =
rangeToDelete.EndRef() != aPoint
? TextFragmentData(rangeToDelete.EndRef(), &aEditingHost)
? TextFragmentData(rangeToDelete.EndRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle)
: textFragmentDataAtCaret;
if (NS_WARN_IF(!textFragmentDataAtStart.IsInitialized()) ||
NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized())) {
@ -3992,7 +4043,8 @@ WSRunScanner::GetRangeInTextNodesToForwardDeleteFrom(
// `WhiteSpaceVisibilityKeeper::DeleteInclusiveNextWhiteSpace()`
MOZ_ASSERT(aPoint.IsSetAndValid());
TextFragmentData textFragmentDataAtCaret(aPoint, &aEditingHost);
TextFragmentData textFragmentDataAtCaret(
aPoint, &aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtCaret.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -4058,11 +4110,13 @@ WSRunScanner::GetRangeInTextNodesToForwardDeleteFrom(
// And also delete invisible white-spaces if they become visible.
TextFragmentData textFragmentDataAtStart =
rangeToDelete.StartRef() != aPoint
? TextFragmentData(rangeToDelete.StartRef(), &aEditingHost)
? TextFragmentData(rangeToDelete.StartRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle)
: textFragmentDataAtCaret;
TextFragmentData textFragmentDataAtEnd =
rangeToDelete.EndRef() != aPoint
? TextFragmentData(rangeToDelete.EndRef(), &aEditingHost)
? TextFragmentData(rangeToDelete.EndRef(), &aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle)
: textFragmentDataAtCaret;
if (NS_WARN_IF(!textFragmentDataAtStart.IsInitialized()) ||
NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized())) {
@ -4083,7 +4137,8 @@ EditorDOMRange WSRunScanner::GetRangesForDeletingAtomicContent(
// Preceding white-spaces should be preserved, but the following
// white-spaces should be invisible around `<br>` element.
TextFragmentData textFragmentDataAfterBRElement(
EditorDOMPoint::After(aAtomicContent), aEditingHost);
EditorDOMPoint::After(aAtomicContent), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAfterBRElement.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4101,7 +4156,8 @@ EditorDOMRange WSRunScanner::GetRangesForDeletingAtomicContent(
EditorDOMPoint::After(aAtomicContent));
}
if (!HTMLEditUtils::IsBlockElement(aAtomicContent)) {
if (!HTMLEditUtils::IsBlockElement(
aAtomicContent, BlockInlineCheck::UseComputedDisplayStyle)) {
// Both preceding and following white-spaces around it should be preserved
// around inline elements like `<img>`.
return EditorDOMRange(
@ -4112,7 +4168,8 @@ EditorDOMRange WSRunScanner::GetRangesForDeletingAtomicContent(
// Both preceding and following white-spaces can be invisible around a
// block element.
TextFragmentData textFragmentDataBeforeAtomicContent(
EditorDOMPoint(const_cast<nsIContent*>(&aAtomicContent)), aEditingHost);
EditorDOMPoint(const_cast<nsIContent*>(&aAtomicContent)), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataBeforeAtomicContent.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4121,7 +4178,8 @@ EditorDOMRange WSRunScanner::GetRangesForDeletingAtomicContent(
textFragmentDataBeforeAtomicContent
.InvisibleTrailingWhiteSpaceRangeRef());
TextFragmentData textFragmentDataAfterAtomicContent(
EditorDOMPoint::After(aAtomicContent), aEditingHost);
EditorDOMPoint::After(aAtomicContent), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAfterAtomicContent.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4185,7 +4243,7 @@ EditorDOMRange WSRunScanner::GetRangeForDeletingBlockElementBoundaries(
aPointContainingTheOtherBlock.GetContainer() == &aLeftBlockElement
? aPointContainingTheOtherBlock
: EditorDOMPoint::AtEndOf(const_cast<Element&>(aLeftBlockElement)),
editingHost);
editingHost, BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (NS_WARN_IF(!textFragmentDataAtEndOfLeftBlockElement.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4212,7 +4270,7 @@ EditorDOMRange WSRunScanner::GetRangeForDeletingBlockElementBoundaries(
!aPointContainingTheOtherBlock.IsEndOfContainer()
? aPointContainingTheOtherBlock.NextPoint()
: EditorDOMPoint(const_cast<Element*>(&aRightBlockElement), 0u),
editingHost);
editingHost, BlockInlineCheck::UseComputedDisplayOutsideStyle);
if (NS_WARN_IF(!textFragmentDataAtStartOfRightBlockElement.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4236,7 +4294,9 @@ WSRunScanner::GetRangeContainingInvisibleWhiteSpacesAtRangeBoundaries(
MOZ_ASSERT(aRange.StartRef().IsSetAndValid());
EditorDOMRange result;
TextFragmentData textFragmentDataAtStart(aRange.StartRef(), aEditingHost);
TextFragmentData textFragmentDataAtStart(
aRange.StartRef(), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtStart.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4269,7 +4329,8 @@ WSRunScanner::GetRangeContainingInvisibleWhiteSpacesAtRangeBoundaries(
result.SetStart(aRange.StartRef());
}
TextFragmentData textFragmentDataAtEnd(aRange.EndRef(), aEditingHost);
TextFragmentData textFragmentDataAtEnd(
aRange.EndRef(), aEditingHost, BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized())) {
return EditorDOMRange(); // TODO: Make here return error with Err.
}
@ -4333,10 +4394,12 @@ WSRunScanner::ShrinkRangeIfStartsFromOrEndsAfterAtomicContent(
// joining the blocks.
if (HTMLEditUtils::GetInclusiveAncestorElement(
*aRange.GetStartContainer()->AsContent(),
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement) !=
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement,
BlockInlineCheck::UseComputedDisplayStyle) !=
HTMLEditUtils::GetInclusiveAncestorElement(
*aRange.GetEndContainer()->AsContent(),
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement)) {
HTMLEditUtils::ClosestEditableBlockElementExceptHRElement,
BlockInlineCheck::UseComputedDisplayStyle)) {
return false;
}
@ -4347,7 +4410,8 @@ WSRunScanner::ShrinkRangeIfStartsFromOrEndsAfterAtomicContent(
// (e.g., `<img>`, non-editable text node, etc) or a block level void
// element like `<hr>`, the range should start with it.
TextFragmentData textFragmentDataAtStart(
EditorRawDOMPoint(aRange.StartRef()), aEditingHost);
EditorRawDOMPoint(aRange.StartRef()), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtStart.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}
@ -4368,8 +4432,9 @@ WSRunScanner::ShrinkRangeIfStartsFromOrEndsAfterAtomicContent(
// If previous content is a visible `<br>` element, special inline content
// (e.g., `<img>`, non-editable text node, etc) or a block level void
// element like `<hr>`, the range should end after it.
TextFragmentData textFragmentDataAtEnd(EditorRawDOMPoint(aRange.EndRef()),
aEditingHost);
TextFragmentData textFragmentDataAtEnd(
EditorRawDOMPoint(aRange.EndRef()), aEditingHost,
BlockInlineCheck::UseComputedDisplayStyle);
if (NS_WARN_IF(!textFragmentDataAtEnd.IsInitialized())) {
return Err(NS_ERROR_FAILURE);
}

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

@ -11,8 +11,8 @@
#include "EditorForwards.h"
#include "EditorDOMPoint.h" // for EditorDOMPoint
#include "EditorUtils.h" // for CaretPoint
#include "HTMLEditHelpers.h"
#include "HTMLEditor.h"
#include "HTMLEditUtils.h"
#include "mozilla/Assertions.h"
@ -93,19 +93,22 @@ class MOZ_STACK_CLASS WSScanResult final {
public:
WSScanResult() = delete;
MOZ_NEVER_INLINE_DEBUG WSScanResult(nsIContent* aContent, WSType aReason)
MOZ_NEVER_INLINE_DEBUG WSScanResult(nsIContent* aContent, WSType aReason,
BlockInlineCheck aBlockInlineCheck)
: mContent(aContent), mReason(aReason) {
AssertIfInvalidData();
AssertIfInvalidData(aBlockInlineCheck);
}
MOZ_NEVER_INLINE_DEBUG WSScanResult(const EditorDOMPoint& aPoint,
WSType aReason)
WSType aReason,
BlockInlineCheck aBlockInlineCheck)
: mContent(aPoint.GetContainerAs<nsIContent>()),
mOffset(Some(aPoint.Offset())),
mReason(aReason) {
AssertIfInvalidData();
AssertIfInvalidData(aBlockInlineCheck);
}
MOZ_NEVER_INLINE_DEBUG void AssertIfInvalidData() const {
MOZ_NEVER_INLINE_DEBUG void AssertIfInvalidData(
BlockInlineCheck aBlockInlineCheck) const {
#ifdef DEBUG
MOZ_ASSERT(mReason == WSType::UnexpectedError ||
mReason == WSType::NonCollapsibleCharacters ||
@ -126,11 +129,13 @@ class MOZ_STACK_CLASS WSScanResult final {
EditorUtils::IsNewLinePreformatted(*mContent));
MOZ_ASSERT_IF(
mReason == WSType::SpecialContent,
mContent && ((mContent->IsText() && !mContent->IsEditable()) ||
(!mContent->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsBlockElement(*mContent))));
mContent &&
((mContent->IsText() && !mContent->IsEditable()) ||
(!mContent->IsHTMLElement(nsGkAtoms::br) &&
!HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck))));
MOZ_ASSERT_IF(mReason == WSType::OtherBlockBoundary,
mContent && HTMLEditUtils::IsBlockElement(*mContent));
mContent && HTMLEditUtils::IsBlockElement(*mContent,
aBlockInlineCheck));
// If mReason is WSType::CurrentBlockBoundary, mContent can be any content.
// In most cases, it's current block element which is editable. However, if
// there is no editable block parent, this is topmost editable inline
@ -139,8 +144,9 @@ class MOZ_STACK_CLASS WSScanResult final {
MOZ_ASSERT_IF(
mReason == WSType::CurrentBlockBoundary,
!mContent || !mContent->GetParentElement() ||
HTMLEditUtils::IsBlockElement(*mContent) ||
HTMLEditUtils::IsBlockElement(*mContent->GetParentElement()) ||
HTMLEditUtils::IsBlockElement(*mContent, aBlockInlineCheck) ||
HTMLEditUtils::IsBlockElement(*mContent->GetParentElement(),
aBlockInlineCheck) ||
!mContent->GetParentElement()->IsEditable());
#endif // #ifdef DEBUG
}
@ -324,10 +330,13 @@ class MOZ_STACK_CLASS WSRunScanner final {
template <typename EditorDOMPointType>
WSRunScanner(const Element* aEditingHost,
const EditorDOMPointType& aScanStartPoint)
const EditorDOMPointType& aScanStartPoint,
BlockInlineCheck aBlockInlineCheck)
: mScanStartPoint(aScanStartPoint.template To<EditorDOMPoint>()),
mEditingHost(const_cast<Element*>(aEditingHost)),
mTextFragmentDataAtStart(mScanStartPoint, mEditingHost) {}
mTextFragmentDataAtStart(mScanStartPoint, mEditingHost,
aBlockInlineCheck),
mBlockInlineCheck(aBlockInlineCheck) {}
// ScanNextVisibleNodeOrBlockBoundaryForwardFrom() returns the first visible
// node after aPoint. If there is no visible nodes after aPoint, returns
@ -338,8 +347,9 @@ class MOZ_STACK_CLASS WSRunScanner final {
const EditorDOMPointBase<PT, CT>& aPoint) const;
template <typename PT, typename CT>
static WSScanResult ScanNextVisibleNodeOrBlockBoundary(
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
return WSRunScanner(aEditingHost, aPoint)
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) {
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck)
.ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint);
}
@ -352,8 +362,9 @@ class MOZ_STACK_CLASS WSRunScanner final {
const EditorDOMPointBase<PT, CT>& aPoint) const;
template <typename PT, typename CT>
static WSScanResult ScanPreviousVisibleNodeOrBlockBoundary(
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
return WSRunScanner(aEditingHost, aPoint)
const Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) {
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck)
.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint);
}
@ -365,14 +376,15 @@ class MOZ_STACK_CLASS WSRunScanner final {
template <typename EditorDOMPointType = EditorDOMPointInText, typename PT,
typename CT>
static EditorDOMPointType GetInclusiveNextEditableCharPoint(
Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) {
if (aPoint.IsInTextNode() && !aPoint.IsEndOfContainer() &&
HTMLEditUtils::IsSimplyEditableNode(
*aPoint.template ContainerAs<Text>())) {
return EditorDOMPointType(aPoint.template ContainerAs<Text>(),
aPoint.Offset());
}
return WSRunScanner(aEditingHost, aPoint)
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck)
.GetInclusiveNextEditableCharPoint<EditorDOMPointType>(aPoint);
}
@ -383,14 +395,15 @@ class MOZ_STACK_CLASS WSRunScanner final {
template <typename EditorDOMPointType = EditorDOMPointInText, typename PT,
typename CT>
static EditorDOMPointType GetPreviousEditableCharPoint(
Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint) {
Element* aEditingHost, const EditorDOMPointBase<PT, CT>& aPoint,
BlockInlineCheck aBlockInlineCheck) {
if (aPoint.IsInTextNode() && !aPoint.IsStartOfContainer() &&
HTMLEditUtils::IsSimplyEditableNode(
*aPoint.template ContainerAs<Text>())) {
return EditorDOMPointType(aPoint.template ContainerAs<Text>(),
aPoint.Offset() - 1);
}
return WSRunScanner(aEditingHost, aPoint)
return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck)
.GetPreviousEditableCharPoint<EditorDOMPointType>(aPoint);
}
@ -483,7 +496,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
template <typename EditorDOMPointType>
MOZ_NEVER_INLINE_DEBUG static HTMLBRElement*
GetPrecedingBRElementUnlessVisibleContentFound(
Element* aEditingHost, const EditorDOMPointType& aPoint) {
Element* aEditingHost, const EditorDOMPointType& aPoint,
BlockInlineCheck aBlockInlineCheck) {
MOZ_ASSERT(aPoint.IsSetAndValid());
// XXX This method behaves differently even in similar point.
// If aPoint is in a text node following `<br>` element, reaches the
@ -497,7 +511,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
}
// TODO: Scan for end boundary is redundant in this case, we should optimize
// it.
TextFragmentData textFragmentData(aPoint, aEditingHost);
TextFragmentData textFragmentData(aPoint, aEditingHost, aBlockInlineCheck);
return textFragmentData.StartsFromBRElement()
? textFragmentData.StartReasonBRElementPtr()
: nullptr;
@ -819,7 +833,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
static BoundaryData ScanCollapsibleWhiteSpaceStartFrom(
const EditorDOMPointType& aPoint,
const Element& aEditableBlockParentOrTopmostEditableInlineElement,
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData);
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck);
/**
* ScanCollapsibleWhiteSpaceEndFrom() returns end boundary data of
@ -840,9 +855,10 @@ class MOZ_STACK_CLASS WSRunScanner final {
static BoundaryData ScanCollapsibleWhiteSpaceEndFrom(
const EditorDOMPointType& aPoint,
const Element& aEditableBlockParentOrTopmostEditableInlineElement,
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData);
const Element* aEditingHost, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck);
BoundaryData() : mReason(WSType::NotInitialized) {}
BoundaryData() = default;
template <typename EditorDOMPointType>
BoundaryData(const EditorDOMPointType& aPoint, nsIContent& aReasonContent,
WSType aReason)
@ -898,10 +914,12 @@ class MOZ_STACK_CLASS WSRunScanner final {
*/
template <typename EditorDOMPointType>
static Maybe<BoundaryData> ScanCollapsibleWhiteSpaceStartInTextNode(
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData);
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck);
template <typename EditorDOMPointType>
static Maybe<BoundaryData> ScanCollapsibleWhiteSpaceEndInTextNode(
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData);
const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData,
BlockInlineCheck aBlockInlineCheck);
nsCOMPtr<nsIContent> mReasonContent;
EditorDOMPoint mPoint;
@ -909,7 +927,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
// WSType::NonCollapsibleCharacters, WSType::SpecialContent,
// WSType::BRElement, WSType::CurrentBlockBoundary or
// WSType::OtherBlockBoundary.
WSType mReason;
WSType mReason = WSType::NotInitialized;
};
class MOZ_STACK_CLASS NoBreakingSpaceData final {
@ -943,8 +961,14 @@ class MOZ_STACK_CLASS WSRunScanner final {
public:
TextFragmentData() = delete;
template <typename EditorDOMPointType>
TextFragmentData(const WSRunScanner& aWSRunScanner,
const EditorDOMPointType& aPoint)
: TextFragmentData(aPoint, aWSRunScanner.mEditingHost,
aWSRunScanner.mBlockInlineCheck) {}
template <typename EditorDOMPointType>
TextFragmentData(const EditorDOMPointType& aPoint,
const Element* aEditingHost);
const Element* aEditingHost,
BlockInlineCheck aBlockInlineCheck);
bool IsInitialized() const {
return mStart.Initialized() && mEnd.Initialized();
@ -1298,6 +1322,7 @@ class MOZ_STACK_CLASS WSRunScanner final {
mutable Maybe<EditorDOMRange> mLeadingWhiteSpaceRange;
mutable Maybe<EditorDOMRange> mTrailingWhiteSpaceRange;
mutable Maybe<VisibleWhiteSpacesData> mVisibleWhiteSpacesData;
BlockInlineCheck mBlockInlineCheck;
};
const TextFragmentData& TextFragmentDataAtStartRef() const {
@ -1329,6 +1354,8 @@ class MOZ_STACK_CLASS WSRunScanner final {
TextFragmentData mTextFragmentDataAtStart;
const BlockInlineCheck mBlockInlineCheck;
friend class WhiteSpaceVisibilityKeeper;
};

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

@ -93,12 +93,14 @@ interface nsIHTMLEditor : nsISupports
/* ------------ HTML content methods -------------- */
/**
* Tests if a node is a BLOCK element according the the HTML 4.0 DTD.
* This does NOT consider CSS effect on display type
* Tests if a node is a BLOCK element. It's depend on
* `editor.block_inline_check.use_computed_style` pref whether this refers
* the computed style or the default style.
*
* @param aNode the node to test
*/
boolean nodeIsBlock(in Node node);
[can_run_script]
boolean nodeIsBlock(in Node aNode);
/**
* Insert some HTML source at the current location

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

@ -8,6 +8,7 @@
#include "EditorBase.h" // for EditorBase
#include "EditorUtils.h" // for AutoTransactionBatchExternal
#include "FilteredContentIterator.h" // for FilteredContentIterator
#include "HTMLEditHelpers.h" // for BlockInlineCheck
#include "HTMLEditUtils.h" // for HTMLEditUtils
#include "JoinSplitNodeDirection.h" // for JoinNodesDirection
@ -1653,11 +1654,13 @@ bool TextServicesDocument::HasSameBlockNodeParent(Text& aTextNode1,
const Element* editableBlockElementOrInlineEditingHost1 =
HTMLEditUtils::GetAncestorElement(
aTextNode1,
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost);
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
BlockInlineCheck::UseHTMLDefaultStyle);
const Element* editableBlockElementOrInlineEditingHost2 =
HTMLEditUtils::GetAncestorElement(
aTextNode2,
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost);
HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost,
BlockInlineCheck::UseHTMLDefaultStyle);
return editableBlockElementOrInlineEditingHost1 &&
editableBlockElementOrInlineEditingHost1 ==
editableBlockElementOrInlineEditingHost2;
@ -2307,8 +2310,11 @@ nsresult TextServicesDocument::FirstTextNodeInCurrentBlock(
aFilteredIter->GetCurrentNode()->IsContent()
? aFilteredIter->GetCurrentNode()->AsContent()
: nullptr;
// We don't observe layout updates, therefore, we should consider whether
// block or inline only with the default definition of the element.
if (lastTextNode && content &&
(HTMLEditUtils::IsBlockElement(*content) ||
(HTMLEditUtils::IsBlockElement(*content,
BlockInlineCheck::UseHTMLDefaultStyle) ||
content->IsHTMLElement(nsGkAtoms::br))) {
break;
}
@ -2387,9 +2393,13 @@ nsresult TextServicesDocument::FirstTextNodeInNextBlock(
break;
}
previousTextNode = content->AsText();
} else if (!crossedBlockBoundary &&
(HTMLEditUtils::IsBlockElement(*content) ||
content->IsHTMLElement(nsGkAtoms::br))) {
}
// We don't observe layout updates, therefore, we should consider whether
// block or inline only with the default definition of the element.
else if (!crossedBlockBoundary &&
(HTMLEditUtils::IsBlockElement(
*content, BlockInlineCheck::UseHTMLDefaultStyle) ||
content->IsHTMLElement(nsGkAtoms::br))) {
crossedBlockBoundary = true;
}
}
@ -2517,7 +2527,10 @@ TextServicesDocument::OffsetEntryArray::Init(
aFilteredIter.GetCurrentNode()->IsContent()
? aFilteredIter.GetCurrentNode()->AsContent()
: nullptr) {
if (HTMLEditUtils::IsBlockElement(*content) ||
// We don't observe layout updates, therefore, we should consider whether
// block or inline only with the default definition of the element.
if (HTMLEditUtils::IsBlockElement(
*content, BlockInlineCheck::UseHTMLDefaultStyle) ||
content->IsHTMLElement(nsGkAtoms::br)) {
break;
}

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

@ -40,7 +40,12 @@ function nonCollapsedDeletionTest(host, clickCount) {
is(selection.isCollapsed, false, "Noncollapsed selection should occur");
synthesizeKey("KEY_Backspace");
is(host.textContent, "", "Backspace should delete the content of the editing host");
is(
host.textContent,
"",
`Backspace should delete the content of the editing host (<div contenteditable style="${
host.getAttribute("style")
}">)`);
}
function collapsedSelectionTest(host, clickCount) {

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

@ -4758,6 +4758,13 @@
value: "#FFFFFF"
mirror: never
# Whether HTMLEditor consides block or inline element with computed style or
# only with the default style of HTML definition.
- name: editor.block_inline_check.use_computed_style
type: bool
value: @IS_EARLY_BETA_OR_EARLIER@
mirror: always
# Use compatible range computation when applying inline style. This is used
# for making it possible to backout with Normandy Pref Rollout.
- name: editor.inline_style.range.compatible_with_the_other_browsers

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

@ -260,19 +260,24 @@
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[<div contenteditable style="white-space:nowrap; display:inline">abc[\]</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">[\]abc</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">a[\]bc</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">abc[\]</div> (defaultparagraphseparator: div) (preserving temporary inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline"><b>abc[\]</b></div> (defaultparagraphseparator: div) (preserving inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable><div style="display:inline; white-space:nowrap">abc[\]</div></div> (defaultparagraphseparator: div)]
expected: FAIL
@ -293,19 +298,24 @@
expected: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">abc[\]</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">[\]abc</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">a[\]bc</div> (defaultparagraphseparator: div)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">abc[\]</div> (defaultparagraphseparator: div) (preserving temporary inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block"><b>abc[\]</b></div> (defaultparagraphseparator: div) (preserving inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable><div style="display:inline-block; white-space:nowrap">abc[\]</div></div> (defaultparagraphseparator: div)]
expected: FAIL
@ -326,19 +336,24 @@
expected: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">abc[\]</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">[\]abc</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">a[\]bc</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline">abc[\]</div> (defaultparagraphseparator: p) (preserving temporary inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline"><b>abc[\]</b></div> (defaultparagraphseparator: p) (preserving inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable><div style="display:inline; white-space:nowrap">abc[\]</div></div> (defaultparagraphseparator: p)]
expected: FAIL
@ -359,19 +374,24 @@
expected: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">abc[\]</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">[\]abc</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">a[\]bc</div> (defaultparagraphseparator: p)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block">abc[\]</div> (defaultparagraphseparator: p) (preserving temporary inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable style="white-space:nowrap; display:inline-block"><b>abc[\]</b></div> (defaultparagraphseparator: p) (preserving inline style test)]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[<div contenteditable><div style="display:inline-block; white-space:nowrap">abc[\]</div></div> (defaultparagraphseparator: p)]
expected: FAIL

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

@ -158,6 +158,10 @@
[[["stylewithcss","true"\],["backcolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("backcolor") before]
expected: FAIL
[[["stylewithcss","false"\],["backcolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("backcolor") before]
expected:
if early_beta_or_earlier: FAIL
[[["stylewithcss","false"\],["backcolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("backcolor") after]
expected: FAIL

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

@ -518,19 +518,24 @@
expected: FAIL
[[["delete",""\]\] "<p style=display:inline>fo[o<p style=display:inline>b\]ar" compare innerHTML]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[[["stylewithcss","true"\],["delete",""\]\] "<span style=display:block>fo[o</span><span style=display:block>b\]ar</span>" compare innerHTML]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[[["stylewithcss","false"\],["delete",""\]\] "<span style=display:block>fo[o</span><span style=display:block>b\]ar</span>" compare innerHTML]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[[["stylewithcss","true"\],["delete",""\]\] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b\]ar</quasit>" compare innerHTML]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[[["stylewithcss","false"\],["delete",""\]\] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b\]ar</quasit>" compare innerHTML]
expected: FAIL
expected:
if not early_beta_or_earlier: FAIL
[[["delete",""\]\] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" compare innerHTML]
expected: FAIL

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

@ -160,6 +160,10 @@
[[["stylewithcss","true"\],["hilitecolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("hilitecolor") before]
expected: FAIL
[[["stylewithcss","false"\],["hilitecolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("hilitecolor") before]
expected:
if early_beta_or_earlier: FAIL
[[["stylewithcss","false"\],["hilitecolor","#00FFFF"\]\] "<span style=\\"display: block; background-color: aqua\\"><span style=\\"display: block; background-color: tan\\">b[ar\]</span></span>" queryCommandValue("hilitecolor") after]
expected: FAIL

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

@ -26,10 +26,7 @@ const tests = [
selector: "caption",
initial: "<div><table><caption>abc</caption><tbody><tr><td>abc</td></tr></tbody></table></div>",
// <caption> can have paragraphs so that it should be handled as in a block.
expected: [
"<div><table><caption><br><div>abc</div></caption><tbody><tr><td>abc</td></tr></tbody></table></div>",
"<div><table><caption><div><br></div><div>abc</div></caption><tbody><tr><td>abc</td></tr></tbody></table></div>",
],
expected: "<div><table><caption><br>abc</caption><tbody><tr><td>abc</td></tr></tbody></table></div>",
},
{
selector: "col",