diff --git a/editor/libeditor/AutoRangeArray.cpp b/editor/libeditor/AutoRangeArray.cpp index c3fe82766634..43a9a611bc25 100644 --- a/editor/libeditor/AutoRangeArray.cpp +++ b/editor/libeditor/AutoRangeArray.cpp @@ -521,7 +521,8 @@ void AutoRangeArray:: Element* const maybeNonEditableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *aStartPoint.ContainerAs(), - 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( 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 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& item : Reversed(rangeItemArray)) { // MOZ_KnownLive because 'rangeItemArray' is guaranteed to keep it alive. Result 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; } diff --git a/editor/libeditor/AutoRangeArray.h b/editor/libeditor/AutoRangeArray.h index ff0f223663a5..18833fc1d5e9 100644 --- a/editor/libeditor/AutoRangeArray.h +++ b/editor/libeditor/AutoRangeArray.h @@ -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 SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - HTMLEditor& aHTMLEditor, const dom::Element& aEditingHost, + HTMLEditor& aHTMLEditor, BlockInlineCheck aBlockInlineCheck, + const dom::Element& aEditingHost, const nsIContent* aAncestorLimiter = nullptr); /** diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp index 63c49bfcf765..41fc59c2b7d8 100644 --- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -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) { diff --git a/editor/libeditor/EditorForwards.h b/editor/libeditor/EditorForwards.h index 7adc988d0298..0062943a36b8 100644 --- a/editor/libeditor/EditorForwards.h +++ b/editor/libeditor/EditorForwards.h @@ -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 diff --git a/editor/libeditor/HTMLEditHelpers.h b/editor/libeditor/HTMLEditHelpers.h index 9cbe11bbe73c..e96e78b511de 100644 --- a/editor/libeditor/HTMLEditHelpers.h +++ b/editor/libeditor/HTMLEditHelpers.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
+ // * Looking for whether a padding
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) { diff --git a/editor/libeditor/HTMLEditSubActionHandler.cpp b/editor/libeditor/HTMLEditSubActionHandler.cpp index c364bad9cadb..6d36b930c695 100644 --- a/editor/libeditor/HTMLEditSubActionHandler.cpp +++ b/editor/libeditor/HTMLEditSubActionHandler.cpp @@ -686,7 +686,8 @@ nsresult HTMLEditor::OnEndHandlingTopLevelEditSubActionInternal() { if (!ancestor->IsHTMLElement() || !HTMLEditUtils::IsRemovableFromParentNode(*ancestor) || !HTMLEditUtils::IsEmptyInlineContainer( - *ancestor, {EmptyCheckOption::TreatSingleBRElementAsVisible})) { + *ancestor, {EmptyCheckOption::TreatSingleBRElementAsVisible}, + BlockInlineCheck::UseComputedDisplayStyle)) { break; } mostDistantEmptyInlineAncestor = ancestor; @@ -862,8 +863,9 @@ nsresult HTMLEditor::EnsureCaretNotAfterInvisibleBRElement() { return NS_OK; } - nsIContent* previousBRElement = - HTMLEditUtils::GetPreviousContent(atSelectionStart, {}, editingHost); + nsIContent* previousBRElement = HTMLEditUtils::GetPreviousContent( + atSelectionStart, {}, BlockInlineCheck::UseComputedDisplayStyle, + editingHost); if (!previousBRElement || !previousBRElement->IsHTMLElement(nsGkAtoms::br) || !previousBRElement->GetParent() || !EditorUtils::IsEditableContent(*previousBRElement->GetParent(), @@ -875,10 +877,12 @@ nsresult HTMLEditor::EnsureCaretNotAfterInvisibleBRElement() { const RefPtr blockElementAtSelectionStart = HTMLEditUtils::GetInclusiveAncestorElement( *atSelectionStart.ContainerAs(), - HTMLEditUtils::ClosestBlockElement); + HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayStyle); const RefPtr parentBlockElementOfBRElement = - HTMLEditUtils::GetAncestorElement(*previousBRElement, - HTMLEditUtils::ClosestBlockElement); + HTMLEditUtils::GetAncestorElement( + *previousBRElement, HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayStyle); if (!blockElementAtSelectionStart || blockElementAtSelectionStart != parentBlockElementOfBRElement) { @@ -928,7 +932,8 @@ nsresult HTMLEditor::MaybeCreatePaddingBRElementForEmptyEditor() { child = child->GetNextSibling()) { if (EditorUtils::IsPaddingBRElementForEmptyEditor(*child) || !isRootEditable || EditorUtils::IsEditableContent(*child, editorType) || - HTMLEditUtils::IsBlockElement(*child)) { + HTMLEditUtils::IsBlockElement( + *child, BlockInlineCheck::UseComputedDisplayStyle)) { return NS_OK; } } @@ -1578,7 +1583,8 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() { WSScanResult backwardScanFromBeforeBRElementResult = WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary( editingHost, - EditorDOMPoint(unwrappedInsertBRElementResult.GetNewNode())); + EditorDOMPoint(unwrappedInsertBRElementResult.GetNewNode()), + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(backwardScanFromBeforeBRElementResult.Failed())) { NS_WARNING( "WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary() failed"); @@ -1586,8 +1592,9 @@ nsresult HTMLEditor::InsertLineBreakAsSubAction() { } WSScanResult forwardScanFromAfterBRElementResult = - WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(editingHost, - pointToPutCaret); + WSRunScanner::ScanNextVisibleNodeOrBlockBoundary( + editingHost, pointToPutCaret, + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(forwardScanFromAfterBRElementResult.Failed())) { NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundary() failed"); return Err(NS_ERROR_FAILURE); @@ -1862,7 +1869,8 @@ HTMLEditor::InsertParagraphSeparatorAsSubAction(const Element& aEditingHost) { // element. if (!HTMLEditUtils::IsSplittableNode(*aEditableBlockElement)) { return aDefaultParagraphSeparator == ParagraphSeparator::br || - !HTMLEditUtils::CanElementContainParagraph(aEditingHost) || + !HTMLEditUtils::CanElementContainParagraph( + *aEditableBlockElement) || HTMLEditUtils::ShouldInsertLinefeedCharacter( aCandidatePointToSplit, aEditingHost); } @@ -1880,7 +1888,8 @@ HTMLEditor::InsertParagraphSeparatorAsSubAction(const Element& aEditingHost) { editableBlockAncestor; editableBlockAncestor = HTMLEditUtils::GetAncestorElement( *editableBlockAncestor, - HTMLEditUtils::ClosestEditableBlockElementOrButtonElement)) { + HTMLEditUtils::ClosestEditableBlockElementOrButtonElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle)) { if (HTMLEditUtils::CanElementContainParagraph( *editableBlockAncestor)) { return false; @@ -1895,7 +1904,8 @@ HTMLEditor::InsertParagraphSeparatorAsSubAction(const Element& aEditingHost) { RefPtr editableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *pointToInsert.ContainerAs(), - HTMLEditUtils::ClosestEditableBlockElementOrButtonElement); + HTMLEditUtils::ClosestEditableBlockElementOrButtonElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); // If we cannot insert a

/

element at the selection, we should insert // a
element or a linefeed instead. @@ -2003,7 +2013,8 @@ HTMLEditor::InsertParagraphSeparatorAsSubAction(const Element& aEditingHost) { editableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *pointToInsert.ContainerAs(), - HTMLEditUtils::ClosestEditableBlockElementOrButtonElement); + HTMLEditUtils::ClosestEditableBlockElementOrButtonElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); if (NS_WARN_IF(!editableBlockElement)) { return Err(NS_ERROR_UNEXPECTED); } @@ -2044,7 +2055,8 @@ HTMLEditor::InsertParagraphSeparatorAsSubAction(const Element& aEditingHost) { RefPtr insertedPaddingBRElement; if (HTMLEditUtils::IsEmptyBlockElement( *editableBlockElement, - {EmptyCheckOption::TreatSingleBRElementAsVisible})) { + {EmptyCheckOption::TreatSingleBRElementAsVisible}, + BlockInlineCheck::UseComputedDisplayOutsideStyle)) { Result insertBRElementResult = InsertBRElement(WithTransaction::Yes, EditorDOMPoint::AtEndOf(*editableBlockElement)); @@ -2207,7 +2219,8 @@ Result HTMLEditor::HandleInsertBRElement( MOZ_ASSERT(IsEditActionDataAvailable()); const bool editingHostIsEmpty = HTMLEditUtils::IsEmptyNode(aEditingHost); - WSRunScanner wsRunScanner(&aEditingHost, aPointToBreak); + WSRunScanner wsRunScanner(&aEditingHost, aPointToBreak, + BlockInlineCheck::UseComputedDisplayStyle); WSScanResult backwardScanResult = wsRunScanner.ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPointToBreak); if (MOZ_UNLIKELY(backwardScanResult.Failed())) { @@ -2332,8 +2345,9 @@ Result HTMLEditor::HandleInsertBRElement( } WSScanResult forwardScanFromAfterBRElementResult = - WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(&aEditingHost, - afterBRElement); + WSRunScanner::ScanNextVisibleNodeOrBlockBoundary( + &aEditingHost, afterBRElement, + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(forwardScanFromAfterBRElementResult.Failed())) { NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundary() failed"); return Err(NS_ERROR_FAILURE); @@ -2386,8 +2400,9 @@ Result HTMLEditor::HandleInsertBRElement( // node. Then we stick to the left to avoid an uber caret. nsIContent* nextSiblingOfBRElement = brElement->GetNextSibling(); afterBRElement.SetInterlinePosition( - nextSiblingOfBRElement && - HTMLEditUtils::IsBlockElement(*nextSiblingOfBRElement) + nextSiblingOfBRElement && HTMLEditUtils::IsBlockElement( + *nextSiblingOfBRElement, + BlockInlineCheck::UseComputedDisplayStyle) ? InterlinePosition::EndOfLine : InterlinePosition::StartOfNextLine); return CreateElementResult(std::move(brElement), afterBRElement); @@ -2472,7 +2487,8 @@ Result HTMLEditor::HandleInsertLinefeed( // for doing it, we need more work, e.g., updating serializer, deleting // unnecessary padding
element at modifying the last line. if (pointToPutCaret.IsInContentNode() && pointToPutCaret.IsEndOfContainer()) { - WSRunScanner wsScannerAtCaret(&aEditingHost, pointToPutCaret); + WSRunScanner wsScannerAtCaret(&aEditingHost, pointToPutCaret, + BlockInlineCheck::UseComputedDisplayStyle); if (wsScannerAtCaret.StartsFromPreformattedLineBreak() && wsScannerAtCaret.EndsByBlockBoundary() && HTMLEditUtils::CanNodeContain(*wsScannerAtCaret.GetEndReasonContent(), @@ -2555,8 +2571,8 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement( // user if they click there and start typing, because being in the // mailquote may affect wrapping behavior, or font color, etc. WSScanResult forwardScanFromPointToSplitResult = - WSRunScanner::ScanNextVisibleNodeOrBlockBoundary(&aEditingHost, - pointToSplit); + WSRunScanner::ScanNextVisibleNodeOrBlockBoundary( + &aEditingHost, pointToSplit, BlockInlineCheck::UseHTMLDefaultStyle); if (forwardScanFromPointToSplitResult.Failed()) { return Err(NS_ERROR_FAILURE); } @@ -2659,7 +2675,8 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement( // also just after it. If we don't have another br or block boundary // adjacent, then we will need a 2nd br added to achieve blank line that user // expects. - if (HTMLEditUtils::IsInlineElement(aMailCiteElement)) { + if (HTMLEditUtils::IsInlineContent( + aMailCiteElement, BlockInlineCheck::UseComputedDisplayStyle)) { nsresult rvOfInsertingBRElement = [&]() MOZ_CAN_RUN_SCRIPT { EditorDOMPoint pointToCreateNewBRElement( unwrappedInsertBRElementResult.GetNewNode()); @@ -2669,7 +2686,8 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement( // resultOfInsertingBRElement.inspect()? WSScanResult backwardScanFromPointToCreateNewBRElementResult = WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundary( - &aEditingHost, pointToCreateNewBRElement); + &aEditingHost, pointToCreateNewBRElement, + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY( backwardScanFromPointToCreateNewBRElementResult.Failed())) { NS_WARNING( @@ -2686,7 +2704,8 @@ HTMLEditor::HandleInsertParagraphInMailCiteElement( WSScanResult forwardScanFromPointAfterNewBRElementResult = WSRunScanner::ScanNextVisibleNodeOrBlockBoundary( &aEditingHost, - EditorRawDOMPoint::After(pointToCreateNewBRElement)); + EditorRawDOMPoint::After(pointToCreateNewBRElement), + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(forwardScanFromPointAfterNewBRElementResult.Failed())) { NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundary() failed"); return NS_ERROR_FAILURE; @@ -2757,7 +2776,8 @@ HTMLEditor::GetPreviousCharPointDataForNormalizingWhiteSpaces( } const auto previousCharPoint = WSRunScanner::GetPreviousEditableCharPoint( - ComputeEditingHost(), aPoint); + ComputeEditingHost(), aPoint, + BlockInlineCheck::UseComputedDisplayStyle); if (!previousCharPoint.IsSet()) { return CharPointData::InDifferentTextNode(CharPointType::TextEnd); } @@ -2775,7 +2795,8 @@ HTMLEditor::GetInclusiveNextCharPointDataForNormalizingWhiteSpaces( } const auto nextCharPoint = WSRunScanner::GetInclusiveNextEditableCharPoint( - ComputeEditingHost(), aPoint); + ComputeEditingHost(), aPoint, + BlockInlineCheck::UseComputedDisplayStyle); if (!nextCharPoint.IsSet()) { return CharPointData::InDifferentTextNode(CharPointType::TextEnd); } @@ -2874,10 +2895,12 @@ void HTMLEditor::ExtendRangeToDeleteWithNormalizingWhiteSpaces( // adjacent text node's first or last character information in some cases. Element* editingHost = ComputeEditingHost(); const EditorDOMPointInText precedingCharPoint = - WSRunScanner::GetPreviousEditableCharPoint(editingHost, aStartToDelete); + WSRunScanner::GetPreviousEditableCharPoint( + editingHost, aStartToDelete, + BlockInlineCheck::UseComputedDisplayStyle); const EditorDOMPointInText followingCharPoint = - WSRunScanner::GetInclusiveNextEditableCharPoint(editingHost, - aEndToDelete); + WSRunScanner::GetInclusiveNextEditableCharPoint( + editingHost, aEndToDelete, BlockInlineCheck::UseComputedDisplayStyle); // Blink-compat: Normalize white-spaces in first node only when not removing // its last character or no text nodes follow the first node. // If removing last character of first node and there are @@ -3179,15 +3202,18 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces( if (const Element* editableBlockElementOrInlineEditingHost = HTMLEditUtils::GetInclusiveAncestorElement( *newCaretPosition.ContainerAs(), - HTMLEditUtils:: - ClosestEditableBlockElementOrInlineEditingHost)) { + HTMLEditUtils::ClosestEditableBlockElementOrInlineEditingHost, + BlockInlineCheck::UseComputedDisplayStyle)) { Element* editingHost = ComputeEditingHost(); // Try to put caret next to immediately after previous editable leaf. nsIContent* previousContent = HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement( newCaretPosition, *editableBlockElementOrInlineEditingHost, - {LeafNodeType::LeafNodeOrNonEditableNode}, editingHost); - if (previousContent && !HTMLEditUtils::IsBlockElement(*previousContent)) { + {LeafNodeType::LeafNodeOrNonEditableNode}, + BlockInlineCheck::UseComputedDisplayStyle, editingHost); + if (previousContent && + !HTMLEditUtils::IsBlockElement( + *previousContent, BlockInlineCheck::UseComputedDisplayStyle)) { newCaretPosition = previousContent->IsText() || HTMLEditUtils::IsContainerNode(*previousContent) @@ -3201,6 +3227,7 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces( newCaretPosition, *editableBlockElementOrInlineEditingHost, {LeafNodeType::LeafNodeOrNonEditableNode}, + BlockInlineCheck::UseComputedDisplayStyle, editingHost)) { newCaretPosition = nextContent->IsText() || HTMLEditUtils::IsContainerNode(*nextContent) @@ -3254,7 +3281,8 @@ HTMLEditor::InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary( // If container of the point is not in a block, we don't need to put a // `
` element here. if (!HTMLEditUtils::IsBlockElement( - *aPointToInsert.ContainerAs())) { + *aPointToInsert.ContainerAs(), + BlockInlineCheck::UseComputedDisplayStyle)) { return CaretPoint(EditorDOMPoint()); } @@ -3263,7 +3291,8 @@ HTMLEditor::InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary( return Err(NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE); } - WSRunScanner wsRunScanner(ComputeEditingHost(), aPointToInsert); + WSRunScanner wsRunScanner(ComputeEditingHost(), aPointToInsert, + BlockInlineCheck::UseComputedDisplayStyle); // If the point is not start of a hard line, we don't need to put a `
` // element here. if (!wsRunScanner.StartsFromHardLineBreak()) { @@ -3561,7 +3590,7 @@ nsresult HTMLEditor::AutoListElementCreator:: EditSubAction::eCreateOrChangeList, aEditingHost); Result splitResult = extendedRanges.SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - aHTMLEditor, aEditingHost); + aHTMLEditor, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -3599,7 +3628,8 @@ bool HTMLEditor::AutoListElementCreator:: // XXX Should we handle line breaks in preformatted text node? if (!content->IsHTMLElement(nsGkAtoms::br) && !HTMLEditUtils::IsEmptyInlineContainer( - content, {EmptyCheckOption::TreatSingleBRElementAsVisible})) { + content, {EmptyCheckOption::TreatSingleBRElementAsVisible}, + BlockInlineCheck::UseComputedDisplayStyle)) { return false; } } @@ -3689,8 +3719,9 @@ HTMLEditor::AutoListElementCreator::WrapContentNodesIntoNewListElements( if (Element* deepestDivBlockquoteOrListElement = HTMLEditUtils::GetInclusiveDeepestFirstChildWhichHasOneChild( aArrayOfContents[0], {WalkTreeOption::IgnoreNonEditableNode}, - nsGkAtoms::div, nsGkAtoms::blockquote, nsGkAtoms::ul, - nsGkAtoms::ol, nsGkAtoms::dl)) { + BlockInlineCheck::UseHTMLDefaultStyle, nsGkAtoms::div, + nsGkAtoms::blockquote, nsGkAtoms::ul, nsGkAtoms::ol, + nsGkAtoms::dl)) { if (deepestDivBlockquoteOrListElement->IsAnyOfHTMLElements( nsGkAtoms::div, nsGkAtoms::blockquote)) { aArrayOfContents.Clear(); @@ -3738,8 +3769,8 @@ nsresult HTMLEditor::AutoListElementCreator::HandleChildContent( if (EditorUtils::IsEditableContent(aHandlingContent, EditorType::HTML) && (aHandlingContent.IsHTMLElement(nsGkAtoms::br) || HTMLEditUtils::IsEmptyInlineContainer( - aHandlingContent, - {EmptyCheckOption::TreatSingleBRElementAsVisible}))) { + aHandlingContent, {EmptyCheckOption::TreatSingleBRElementAsVisible}, + BlockInlineCheck::UseHTMLDefaultStyle))) { nsresult rv = aHTMLEditor.DeleteNodeWithTransaction(aHandlingContent); if (NS_FAILED(rv)) { NS_WARNING("EditorBase::DeleteNodeWithTransaction() failed"); @@ -3803,9 +3834,8 @@ nsresult HTMLEditor::AutoListElementCreator::HandleChildContent( // If we meet an inline content, we want to move it to previously used list // item element or new list item element. - // XXX Despite the name, HTMLEditUtils::IsInlineElement() returns true for - // non-element content nodes too. - if (HTMLEditUtils::IsInlineElement(aHandlingContent)) { + if (HTMLEditUtils::IsInlineContent(aHandlingContent, + BlockInlineCheck::UseHTMLDefaultStyle)) { nsresult rv = HandleChildInlineContent(aHTMLEditor, aHandlingContent, aState); NS_WARNING_ASSERTION( @@ -4284,7 +4314,8 @@ HTMLEditor::AutoListElementCreator::AppendListItemElement( nsresult HTMLEditor::AutoListElementCreator::HandleChildInlineContent( HTMLEditor& aHTMLEditor, nsIContent& aHandlingInlineContent, AutoHandlingState& aState) const { - MOZ_ASSERT(HTMLEditUtils::IsInlineElement(aHandlingInlineContent)); + MOZ_ASSERT(HTMLEditUtils::IsInlineContent( + aHandlingInlineContent, BlockInlineCheck::UseHTMLDefaultStyle)); // If we're currently handling contents of a list item and current node // is not a block element, move current node into the list item. @@ -4355,7 +4386,8 @@ nsresult HTMLEditor::AutoListElementCreator::WrapContentIntoNewListItemElement( // If current node is not a block element, new list item should have // following inline nodes too. - if (HTMLEditUtils::IsInlineElement(aHandlingContent)) { + if (HTMLEditUtils::IsInlineContent(aHandlingContent, + BlockInlineCheck::UseHTMLDefaultStyle)) { aState.mPreviousListItemElement = unwrappedWrapContentInListItemElementResult.UnwrapNewNode(); } else { @@ -4465,7 +4497,7 @@ nsresult HTMLEditor::RemoveListAtSelectionAsSubAction( Result splitResult = extendedSelectionRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -4576,7 +4608,7 @@ HTMLEditor::FormatBlockContainerWithTransaction( Result splitResult = aSelectionRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -4606,7 +4638,8 @@ HTMLEditor::FormatBlockContainerWithTransaction( // If there is no visible and editable nodes in the edit targets, make an // empty block. // XXX Isn't this odd if there are only non-editable visible nodes? - if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) { + if (HTMLEditUtils::IsEmptyOneHardLine( + arrayOfContents, BlockInlineCheck::UseHTMLDefaultStyle)) { if (NS_WARN_IF(aSelectionRanges.Ranges().IsEmpty())) { return Err(NS_ERROR_FAILURE); } @@ -4624,7 +4657,8 @@ HTMLEditor::FormatBlockContainerWithTransaction( const RefPtr editableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *pointToInsertBlock.ContainerAs(), - HTMLEditUtils::ClosestEditableBlockElement); + HTMLEditUtils::ClosestEditableBlockElement, + BlockInlineCheck::UseHTMLDefaultStyle); if (!editableBlockElement) { NS_WARNING( "HTMLEditor::FormatBlockContainerWithTransaction() couldn't find " @@ -4640,7 +4674,7 @@ HTMLEditor::FormatBlockContainerWithTransaction( // which is visually bad. if (nsCOMPtr brContent = HTMLEditUtils::GetNextContent( pointToInsertBlock, {WalkTreeOption::IgnoreNonEditableNode}, - &aEditingHost)) { + BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) { if (brContent && brContent->IsHTMLElement(nsGkAtoms::br)) { AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock); nsresult rv = DeleteNodeWithTransaction(*brContent); @@ -4686,7 +4720,7 @@ HTMLEditor::FormatBlockContainerWithTransaction( pointToInsertBlock, {WalkTreeOption::IgnoreNonEditableNode, WalkTreeOption::StopAtBlockBoundary}, - &aEditingHost)) { + BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) { if (maybeBRContent->IsHTMLElement(nsGkAtoms::br)) { AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertBlock); nsresult rv = DeleteNodeWithTransaction(*maybeBRContent); @@ -4759,7 +4793,8 @@ HTMLEditor::FormatBlockContainerWithTransaction( } if (&blockType == nsGkAtoms::normal || &blockType == nsGkAtoms::_empty) { Result removeBlockContainerElementsResult = - RemoveBlockContainerElementsWithTransaction(arrayOfContents); + RemoveBlockContainerElementsWithTransaction( + arrayOfContents, BlockInlineCheck::UseHTMLDefaultStyle); if (MOZ_UNLIKELY(removeBlockContainerElementsResult.isErr())) { NS_WARNING( "HTMLEditor::RemoveBlockContainerElementsWithTransaction() failed"); @@ -5085,7 +5120,8 @@ nsresult HTMLEditor::HandleCSSIndentAroundRanges(AutoRangeArray& aRanges, Element* const editableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *atCaret.ContainerAs(), - HTMLEditUtils::ClosestEditableBlockElement); + HTMLEditUtils::ClosestEditableBlockElement, + BlockInlineCheck::UseHTMLDefaultStyle); if (editableBlockElement && HTMLEditUtils::IsListItem(editableBlockElement)) { arrayOfContents.AppendElement(*editableBlockElement); @@ -5101,7 +5137,7 @@ nsresult HTMLEditor::HandleCSSIndentAroundRanges(AutoRangeArray& aRanges, Result splitResult = extendedRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -5139,7 +5175,8 @@ nsresult HTMLEditor::HandleCSSIndentAroundRanges(AutoRangeArray& aRanges, // If there is no visible and editable nodes in the edit targets, make an // empty block. // XXX Isn't this odd if there are only non-editable visible nodes? - if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) { + if (HTMLEditUtils::IsEmptyOneHardLine( + arrayOfContents, BlockInlineCheck::UseHTMLDefaultStyle)) { const EditorDOMPoint pointToInsertDivElement = pointToPutCaret.IsSet() ? std::move(pointToPutCaret) @@ -5264,7 +5301,8 @@ nsresult HTMLEditor::HandleCSSIndentAroundRanges(AutoRangeArray& aRanges, // Not a list item. - if (HTMLEditUtils::IsBlockElement(content)) { + if (HTMLEditUtils::IsBlockElement(content, + BlockInlineCheck::UseHTMLDefaultStyle)) { Result pointToPutCaretOrError = ChangeMarginStart(MOZ_KnownLive(*content->AsElement()), ChangeMargin::Increase, aEditingHost); @@ -5405,7 +5443,7 @@ nsresult HTMLEditor::HandleHTMLIndentAroundRanges(AutoRangeArray& aRanges, Result splitResult = extendedRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -5444,7 +5482,8 @@ nsresult HTMLEditor::HandleHTMLIndentAroundRanges(AutoRangeArray& aRanges, // If there is no visible and editable nodes in the edit targets, make an // empty block. // XXX Isn't this odd if there are only non-editable visible nodes? - if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) { + if (HTMLEditUtils::IsEmptyOneHardLine( + arrayOfContents, BlockInlineCheck::UseHTMLDefaultStyle)) { const EditorDOMPoint pointToInsertBlockquoteElement = pointToPutCaret.IsSet() ? std::move(pointToPutCaret) @@ -6002,7 +6041,8 @@ HTMLEditor::HandleOutdentAtSelectionInternal(const Element& aEditingHost) { // If we're using CSS and the node is a block element, check its start // margin whether it's indented with CSS. - if (useCSS && HTMLEditUtils::IsBlockElement(content)) { + if (useCSS && HTMLEditUtils::IsBlockElement( + content, BlockInlineCheck::UseHTMLDefaultStyle)) { nsStaticAtom& marginProperty = MarginPropertyAtomForIndent(MOZ_KnownLive(content)); if (NS_WARN_IF(Destroyed())) { @@ -6342,20 +6382,20 @@ HTMLEditor::HandleOutdentAtSelectionInternal(const Element& aEditingHost) { Result HTMLEditor::RemoveBlockContainerElementWithTransactionBetween( Element& aBlockContainerElement, nsIContent& aStartOfRange, - nsIContent& aEndOfRange) { + nsIContent& aEndOfRange, BlockInlineCheck aBlockInlineCheck) { MOZ_ASSERT(IsEditActionDataAvailable()); EditorDOMPoint pointToPutCaret; Result splitResult = - SplitRangeOffFromBlock(aBlockContainerElement, aStartOfRange, - aEndOfRange); + SplitRangeOffFromElement(aBlockContainerElement, aStartOfRange, + aEndOfRange); if (MOZ_UNLIKELY(splitResult.isErr())) { if (splitResult.inspectErr() == NS_ERROR_EDITOR_DESTROYED) { - NS_WARNING("HTMLEditor::SplitRangeOffFromBlock() failed"); + NS_WARNING("HTMLEditor::SplitRangeOffFromElement() failed"); return splitResult; } NS_WARNING( - "HTMLEditor::SplitRangeOffFromBlock() failed, but might be ignored"); + "HTMLEditor::SplitRangeOffFromElement() failed, but might be ignored"); return SplitRangeOffFromNodeResult(nullptr, nullptr, nullptr); } SplitRangeOffFromNodeResult unwrappedSplitResult = splitResult.unwrap(); @@ -6393,20 +6433,21 @@ HTMLEditor::RemoveBlockContainerElementWithTransactionBetween( } Result -HTMLEditor::SplitRangeOffFromBlock(Element& aBlockElement, - nsIContent& aStartOfMiddleElement, - nsIContent& aEndOfMiddleElement) { +HTMLEditor::SplitRangeOffFromElement(Element& aElementToSplit, + nsIContent& aStartOfMiddleElement, + nsIContent& aEndOfMiddleElement) { MOZ_ASSERT(IsEditActionDataAvailable()); // aStartOfMiddleElement and aEndOfMiddleElement must be exclusive - // descendants of aBlockElement. - MOZ_ASSERT(EditorUtils::IsDescendantOf(aStartOfMiddleElement, aBlockElement)); - MOZ_ASSERT(EditorUtils::IsDescendantOf(aEndOfMiddleElement, aBlockElement)); + // descendants of aElementToSplit. + MOZ_ASSERT( + EditorUtils::IsDescendantOf(aStartOfMiddleElement, aElementToSplit)); + MOZ_ASSERT(EditorUtils::IsDescendantOf(aEndOfMiddleElement, aElementToSplit)); EditorDOMPoint pointToPutCaret; // Split at the start. Result splitAtStartResult = - SplitNodeDeepWithTransaction(aBlockElement, + SplitNodeDeepWithTransaction(aElementToSplit, EditorDOMPoint(&aStartOfMiddleElement), SplitAtEdges::eDoNotCreateEmptyContainer); if (MOZ_UNLIKELY(splitAtStartResult.isErr())) { @@ -6427,9 +6468,9 @@ HTMLEditor::SplitRangeOffFromBlock(Element& aBlockElement, Element* rightElement = splitAtStartResult.isOk() && splitAtStartResult.inspect().DidSplit() ? splitAtStartResult.inspect().GetNextContentAs() - : &aBlockElement; + : &aElementToSplit; // MOZ_KnownLive(rightElement) because it's grabbed by splitAtStartResult or - // aBlockElement whose lifetime is guaranteed by the caller. + // aElementToSplit whose lifetime is guaranteed by the caller. Result splitAtEndResult = SplitNodeDeepWithTransaction(MOZ_KnownLive(*rightElement), atAfterEnd, SplitAtEdges::eDoNotCreateEmptyContainer); @@ -6469,7 +6510,7 @@ HTMLEditor::SplitRangeOffFromBlock(Element& aBlockElement, splitAtEndResult.inspect().GetNextContent(), std::move(pointToPutCaret)); } - return SplitRangeOffFromNodeResult(nullptr, &aBlockElement, nullptr, + return SplitRangeOffFromNodeResult(nullptr, &aElementToSplit, nullptr, std::move(pointToPutCaret)); } @@ -6480,9 +6521,9 @@ Result HTMLEditor::OutdentPartOfBlock( MOZ_ASSERT(IsEditActionDataAvailable()); Result splitResult = - SplitRangeOffFromBlock(aBlockElement, aStartOfOutdent, aEndOfOutdent); + SplitRangeOffFromElement(aBlockElement, aStartOfOutdent, aEndOfOutdent); if (MOZ_UNLIKELY(splitResult.isErr())) { - NS_WARNING("HTMLEditor::SplitRangeOffFromBlock() failed"); + NS_WARNING("HTMLEditor::SplitRangeOffFromElement() failed"); return splitResult; } @@ -6490,7 +6531,7 @@ Result HTMLEditor::OutdentPartOfBlock( Element* middleElement = unwrappedSplitResult.GetMiddleContentAs(); if (MOZ_UNLIKELY(!middleElement)) { NS_WARNING( - "HTMLEditor::SplitRangeOffFromBlock() didn't return middle content"); + "HTMLEditor::SplitRangeOffFromElement() didn't return middle content"); unwrappedSplitResult.IgnoreCaretPointSuggestion(); return Err(NS_ERROR_FAILURE); } @@ -6942,7 +6983,7 @@ nsresult HTMLEditor::AlignContentsAtRanges(AutoRangeArray& aRanges, Result splitResult = extendedRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -6984,7 +7025,9 @@ nsresult HTMLEditor::AlignContentsAtRanges(AutoRangeArray& aRanges, if (arrayOfContents.Length() == 1) { OwningNonNull& content = arrayOfContents[0]; - if (HTMLEditUtils::SupportsAlignAttr(content)) { + if (HTMLEditUtils::SupportsAlignAttr(content) && + HTMLEditUtils::IsBlockElement(content, + BlockInlineCheck::UseHTMLDefaultStyle)) { // The node is a table element, an hr, a paragraph, a div or a section // header; in HTML 4, it can directly carry the ALIGN attribute and we // don't need to make a div! If we are in CSS mode, all the work is done @@ -7526,7 +7569,14 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // Is there any intervening visible white-space? If so we can't push // selection past that, it would visibly change meaning of users selection. - WSRunScanner wsScannerAtEnd(&aEditingHost, endPoint); + WSRunScanner wsScannerAtEnd( + &aEditingHost, endPoint, + // We should refer only the default style of HTML because we need to wrap + // any elements with a specific HTML element. So we should not refer + // actual style. For example, we want to reformat parent HTML block + // element even if selected in a blocked phrase element or + // non-HTMLelement. + BlockInlineCheck::UseHTMLDefaultStyle); WSScanResult scanResultAtEnd = wsScannerAtEnd.ScanPreviousVisibleNodeOrBlockBoundaryFrom(endPoint); if (scanResultAtEnd.Failed()) { @@ -7541,7 +7591,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // endpoint is just after the close of a block. if (nsIContent* child = HTMLEditUtils::GetLastLeafContent( *wsScannerAtEnd.StartReasonOtherBlockElementPtr(), - {LeafNodeType::LeafNodeOrChildBlock})) { + {LeafNodeType::LeafNodeOrChildBlock}, + BlockInlineCheck::UseHTMLDefaultStyle)) { newRange.SetEnd(EditorRawDOMPoint::After(*child)); } // else block is empty - we can leave selection alone here, i think. @@ -7549,7 +7600,7 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // endpoint is just after start of this block if (nsIContent* child = HTMLEditUtils::GetPreviousContent( endPoint, {WalkTreeOption::IgnoreNonEditableNode}, - &aEditingHost)) { + BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) { newRange.SetEnd(EditorRawDOMPoint::After(*child)); } // else block is empty - we can leave selection alone here, i think. @@ -7562,7 +7613,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // Is there any intervening visible white-space? If so we can't push // selection past that, it would visibly change meaning of users selection. - WSRunScanner wsScannerAtStart(&aEditingHost, startPoint); + WSRunScanner wsScannerAtStart(&aEditingHost, startPoint, + BlockInlineCheck::UseHTMLDefaultStyle); WSScanResult scanResultAtStart = wsScannerAtStart.ScanNextVisibleNodeOrBlockBoundaryFrom(startPoint); if (scanResultAtStart.Failed()) { @@ -7576,7 +7628,8 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // startpoint is just before the start of a block. if (nsIContent* child = HTMLEditUtils::GetFirstLeafContent( *wsScannerAtStart.EndReasonOtherBlockElementPtr(), - {LeafNodeType::LeafNodeOrChildBlock})) { + {LeafNodeType::LeafNodeOrChildBlock}, + BlockInlineCheck::UseHTMLDefaultStyle)) { newRange.SetStart(EditorRawDOMPoint(child)); } // else block is empty - we can leave selection alone here, i think. @@ -7584,7 +7637,7 @@ HTMLEditor::GetRangeExtendedToHardLineEdgesForBlockEditAction( // startpoint is just before end of this block if (nsIContent* child = HTMLEditUtils::GetNextContent( startPoint, {WalkTreeOption::IgnoreNonEditableNode}, - &aEditingHost)) { + BlockInlineCheck::UseHTMLDefaultStyle, &aEditingHost)) { newRange.SetStart(EditorRawDOMPoint(child)); } // else block is empty - we can leave selection alone here, i think. @@ -7728,9 +7781,10 @@ Result HTMLEditor::MaybeSplitElementsAtEveryBRElement( case EditSubAction::eIndent: case EditSubAction::eOutdent: { EditorDOMPoint pointToPutCaret; - for (int32_t i = aArrayOfContents.Length() - 1; i >= 0; i--) { - OwningNonNull& content = aArrayOfContents[i]; - if (HTMLEditUtils::IsInlineElement(content) && + for (size_t index : Reversed(IntegerRange(aArrayOfContents.Length()))) { + OwningNonNull& content = aArrayOfContents[index]; + if (HTMLEditUtils::IsInlineContent( + content, BlockInlineCheck::UseHTMLDefaultStyle) && HTMLEditUtils::IsContainerNode(content) && !content->IsText()) { AutoTArray, 24> arrayOfInlineContents; // MOZ_KnownLive because 'aArrayOfContents' is guaranteed to keep it @@ -7746,8 +7800,8 @@ Result HTMLEditor::MaybeSplitElementsAtEveryBRElement( pointToPutCaret = splitResult.unwrap(); } // Put these nodes in aArrayOfContents, replacing the current node - aArrayOfContents.RemoveElementAt(i); - aArrayOfContents.InsertElementsAt(i, arrayOfInlineContents); + aArrayOfContents.RemoveElementAt(index); + aArrayOfContents.InsertElementsAt(index, arrayOfInlineContents); } } return pointToPutCaret; @@ -7758,8 +7812,9 @@ Result HTMLEditor::MaybeSplitElementsAtEveryBRElement( } Result -HTMLEditor::SplitParentInlineElementsAtRangeBoundaries( - RangeItem& aRangeItem, const Element& aEditingHost, +HTMLEditor::SplitInlineAncestorsAtRangeBoundaries( + RangeItem& aRangeItem, BlockInlineCheck aBlockInlineCheck, + const Element& aEditingHost, const nsIContent* aAncestorLimiter /* = nullptr */) { MOZ_ASSERT(IsEditActionDataAvailable()); @@ -7768,8 +7823,8 @@ HTMLEditor::SplitParentInlineElementsAtRangeBoundaries( aRangeItem.mEndContainer->IsContent()) { nsCOMPtr mostAncestorInlineContentAtEnd = HTMLEditUtils::GetMostDistantAncestorInlineElement( - *aRangeItem.mEndContainer->AsContent(), &aEditingHost, - aAncestorLimiter); + *aRangeItem.mEndContainer->AsContent(), aBlockInlineCheck, + &aEditingHost, aAncestorLimiter); if (mostAncestorInlineContentAtEnd) { Result splitEndInlineResult = @@ -7814,8 +7869,8 @@ HTMLEditor::SplitParentInlineElementsAtRangeBoundaries( nsCOMPtr mostAncestorInlineContentAtStart = HTMLEditUtils::GetMostDistantAncestorInlineElement( - *aRangeItem.mStartContainer->AsContent(), &aEditingHost, - aAncestorLimiter); + *aRangeItem.mStartContainer->AsContent(), aBlockInlineCheck, + &aEditingHost, aAncestorLimiter); if (mostAncestorInlineContentAtStart) { Result splitStartInlineResult = @@ -8009,7 +8064,9 @@ HTMLEditor::HandleInsertParagraphInHeadingElement( MOZ_ASSERT(rightHeadingElement, "SplitNodeResult::GetNextContent() should return something if " "DidSplit() returns true"); - if (!HTMLEditUtils::IsEmptyBlockElement(*rightHeadingElement, {})) { + if (!HTMLEditUtils::IsEmptyBlockElement( + *rightHeadingElement, {}, + BlockInlineCheck::UseComputedDisplayOutsideStyle)) { return InsertParagraphResult(rightHeadingElement, EditorDOMPoint(rightHeadingElement, 0u)); } @@ -8339,13 +8396,14 @@ Result HTMLEditor::HandleInsertParagraphInParagraph( // moving to the caret, but I think that this could be handled in fewer // cases than this. brElement = HTMLBRElement::FromNodeOrNull(HTMLEditUtils::GetPreviousContent( - pointToSplit, {WalkTreeOption::IgnoreNonEditableNode}, &aEditingHost)); + pointToSplit, {WalkTreeOption::IgnoreNonEditableNode}, + BlockInlineCheck::Unused, &aEditingHost)); if (!brElement || HTMLEditUtils::IsInvisibleBRElement(*brElement) || EditorUtils::IsPaddingBRElementForEmptyLastLine(*brElement)) { // is there a BR after it? brElement = HTMLBRElement::FromNodeOrNull(HTMLEditUtils::GetNextContent( pointToSplit, {WalkTreeOption::IgnoreNonEditableNode}, - &aEditingHost)); + BlockInlineCheck::Unused, &aEditingHost)); if (!brElement || HTMLEditUtils::IsInvisibleBRElement(*brElement) || EditorUtils::IsPaddingBRElementForEmptyLastLine(*brElement)) { // If insertParagraph does not create a new paragraph, default to @@ -8467,7 +8525,8 @@ Result HTMLEditor::SplitParagraphWithTransaction( // also behaves so. auto InsertBRElementIfEmptyBlockElement = [&](Element& aElement) MOZ_CAN_RUN_SCRIPT { - if (!HTMLEditUtils::IsBlockElement(aElement)) { + if (!HTMLEditUtils::IsBlockElement( + aElement, BlockInlineCheck::UseComputedDisplayStyle)) { return NS_OK; } @@ -8514,7 +8573,9 @@ Result HTMLEditor::SplitParagraphWithTransaction( for (Element* maybeDeepestInlineContainer = Element::FromNodeOrNull(aBlockElement.GetFirstChild()); maybeDeepestInlineContainer && - HTMLEditUtils::IsInlineElement(*maybeDeepestInlineContainer) && + HTMLEditUtils::IsInlineContent( + *maybeDeepestInlineContainer, + BlockInlineCheck::UseComputedDisplayStyle) && HTMLEditUtils::IsContainerNode(*maybeDeepestInlineContainer); maybeDeepestInlineContainer = maybeDeepestInlineContainer->GetFirstElementChild()) { @@ -8573,7 +8634,8 @@ Result HTMLEditor::SplitParagraphWithTransaction( // Let's put caret at start of the first leaf container. nsIContent* child = HTMLEditUtils::GetFirstLeafContent( - *rightDivOrParagraphElement, {LeafNodeType::LeafNodeOrChildBlock}); + *rightDivOrParagraphElement, {LeafNodeType::LeafNodeOrChildBlock}, + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(!child)) { return SplitNodeResult(std::move(unwrappedSplitDivOrPResult), EditorDOMPoint(rightDivOrParagraphElement, 0u)); @@ -8594,7 +8656,9 @@ HTMLEditor::HandleInsertParagraphInListItemElement( // If aListItemElement is empty, then we want to outdent its content. if (&aEditingHost != aListItemElement.GetParentElement() && - HTMLEditUtils::IsEmptyBlockElement(aListItemElement, {})) { + HTMLEditUtils::IsEmptyBlockElement( + aListItemElement, {}, + BlockInlineCheck::UseComputedDisplayOutsideStyle)) { RefPtr leftListElement = aListItemElement.GetParentElement(); // If the given list item element is not the last list item element of // its parent nor not followed by sub list elements, split the parent @@ -8802,7 +8866,8 @@ HTMLEditor::HandleInsertParagraphInListItemElement( // the element is proper position. WSScanResult forwardScanFromStartOfListItemResult = WSRunScanner::ScanNextVisibleNodeOrBlockBoundary( - &aEditingHost, EditorRawDOMPoint(&rightListItemElement, 0u)); + &aEditingHost, EditorRawDOMPoint(&rightListItemElement, 0u), + BlockInlineCheck::UseComputedDisplayStyle); if (MOZ_UNLIKELY(forwardScanFromStartOfListItemResult.Failed())) { NS_WARNING("WSRunScanner::ScanNextVisibleNodeOrBlockBoundary() failed"); return Err(NS_ERROR_FAILURE); @@ -8934,7 +8999,8 @@ HTMLEditor::WrapContentsInBlockquoteElementsWithTransaction( Result HTMLEditor::RemoveBlockContainerElementsWithTransaction( - const nsTArray>& aArrayOfContents) { + const nsTArray>& aArrayOfContents, + BlockInlineCheck aBlockInlineCheck) { MOZ_ASSERT(IsEditActionDataAvailable()); // Intent of this routine is to be used for converting to/from headers, @@ -8943,14 +9009,14 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction( RefPtr blockElement; nsCOMPtr firstContent, lastContent; EditorDOMPoint pointToPutCaret; - for (auto& content : aArrayOfContents) { + for (const auto& content : aArrayOfContents) { // If curNode is an
,

, , or

, remove it.
     if (HTMLEditUtils::IsFormatNode(content)) {
       // Process any partial progress saved
       if (blockElement) {
         Result unwrapBlockElementResult =
             RemoveBlockContainerElementWithTransactionBetween(
-                *blockElement, *firstContent, *lastContent);
+                *blockElement, *firstContent, *lastContent, aBlockInlineCheck);
         if (MOZ_UNLIKELY(unwrapBlockElementResult.isErr())) {
           NS_WARNING(
               "HTMLEditor::RemoveBlockContainerElementWithTransactionBetween() "
@@ -8987,7 +9053,7 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
       if (blockElement) {
         Result unwrapBlockElementResult =
             RemoveBlockContainerElementWithTransactionBetween(
-                *blockElement, *firstContent, *lastContent);
+                *blockElement, *firstContent, *lastContent, aBlockInlineCheck);
         if (MOZ_UNLIKELY(unwrapBlockElementResult.isErr())) {
           NS_WARNING(
               "HTMLEditor::RemoveBlockContainerElementWithTransactionBetween() "
@@ -9005,7 +9071,8 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
       AutoTArray, 24> childContents;
       HTMLEditUtils::CollectAllChildren(*content, childContents);
       Result removeBlockContainerElementsResult =
-          RemoveBlockContainerElementsWithTransaction(childContents);
+          RemoveBlockContainerElementsWithTransaction(childContents,
+                                                      aBlockInlineCheck);
       if (MOZ_UNLIKELY(removeBlockContainerElementsResult.isErr())) {
         NS_WARNING(
             "HTMLEditor::RemoveBlockContainerElementsWithTransaction() failed");
@@ -9017,7 +9084,7 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
       continue;
     }
 
-    if (HTMLEditUtils::IsInlineElement(content)) {
+    if (HTMLEditUtils::IsInlineContent(content, aBlockInlineCheck)) {
       if (blockElement) {
         // If so, is this node a descendant?
         if (EditorUtils::IsDescendantOf(*content, *blockElement)) {
@@ -9030,7 +9097,7 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
         // contains [firstContent - lastContent].
         Result unwrapBlockElementResult =
             RemoveBlockContainerElementWithTransactionBetween(
-                *blockElement, *firstContent, *lastContent);
+                *blockElement, *firstContent, *lastContent, aBlockInlineCheck);
         if (MOZ_UNLIKELY(unwrapBlockElementResult.isErr())) {
           NS_WARNING(
               "HTMLEditor::RemoveBlockContainerElementWithTransactionBetween() "
@@ -9043,7 +9110,8 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
         // Fall out and handle content
       }
       blockElement = HTMLEditUtils::GetAncestorElement(
-          content, HTMLEditUtils::ClosestEditableBlockElement);
+          content, HTMLEditUtils::ClosestEditableBlockElement,
+          aBlockInlineCheck);
       if (!blockElement || !HTMLEditUtils::IsFormatNode(blockElement) ||
           !HTMLEditUtils::IsRemovableNode(*blockElement)) {
         // Not a block kind that we care about.
@@ -9059,7 +9127,7 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
       // any partial progress saved.
       Result unwrapBlockElementResult =
           RemoveBlockContainerElementWithTransactionBetween(
-              *blockElement, *firstContent, *lastContent);
+              *blockElement, *firstContent, *lastContent, aBlockInlineCheck);
       if (MOZ_UNLIKELY(unwrapBlockElementResult.isErr())) {
         NS_WARNING(
             "HTMLEditor::RemoveBlockContainerElementWithTransactionBetween() "
@@ -9076,7 +9144,7 @@ HTMLEditor::RemoveBlockContainerElementsWithTransaction(
   if (blockElement) {
     Result unwrapBlockElementResult =
         RemoveBlockContainerElementWithTransactionBetween(
-            *blockElement, *firstContent, *lastContent);
+            *blockElement, *firstContent, *lastContent, aBlockInlineCheck);
     if (MOZ_UNLIKELY(unwrapBlockElementResult.isErr())) {
       NS_WARNING(
           "HTMLEditor::RemoveBlockContainerElementWithTransactionBetween() "
@@ -9115,7 +9183,8 @@ HTMLEditor::CreateOrChangeBlockContainerElement(
     // Is it already the right kind of block, or an uneditable block?
     if (content->IsHTMLElement(&aBlockTag) ||
         (!EditorUtils::IsEditableContent(content, EditorType::HTML) &&
-         HTMLEditUtils::IsBlockElement(content))) {
+         HTMLEditUtils::IsBlockElement(
+             content, BlockInlineCheck::UseHTMLDefaultStyle))) {
       // Forget any previous block used for previous inline nodes
       curBlock = nullptr;
       // Do nothing to this block
@@ -9262,11 +9331,12 @@ HTMLEditor::CreateOrChangeBlockContainerElement(
       continue;
     }
 
-    if (HTMLEditUtils::IsInlineElement(content)) {
+    if (HTMLEditUtils::IsInlineContent(content,
+                                       BlockInlineCheck::UseHTMLDefaultStyle)) {
       // If content is inline, pull it into curBlock.  Note: it's assumed that
       // consecutive inline nodes in aNodeArray are actually members of the
       // same block parent.  This happens to be true now as a side effect of
-      // how aNodeArray is contructed, but some additional logic should be
+      // how aNodeArray is constructed, but some additional logic should be
       // added here if that should change
       //
       // If content is a non editable, drop it if we are going to 
.
@@ -9429,7 +9499,7 @@ HTMLEditor::InsertElementWithSplittingAncestorsWithTransaction(
             splitPoint,
             {WalkTreeOption::IgnoreNonEditableNode,
              WalkTreeOption::StopAtBlockBoundary},
-            &aEditingHost)) {
+            BlockInlineCheck::UseComputedDisplayOutsideStyle, &aEditingHost)) {
       if (maybeBRContent->IsHTMLElement(nsGkAtoms::br) &&
           splitPoint.GetChild()) {
         // Making use of html structure... if next node after where we are
@@ -9438,7 +9508,9 @@ HTMLEditor::InsertElementWithSplittingAncestorsWithTransaction(
         if (nsIContent* nextEditableSibling = HTMLEditUtils::GetNextSibling(
                 *splitPoint.GetChild(),
                 {WalkTreeOption::IgnoreNonEditableNode})) {
-          if (!HTMLEditUtils::IsBlockElement(*nextEditableSibling)) {
+          if (!HTMLEditUtils::IsBlockElement(
+                  *nextEditableSibling,
+                  BlockInlineCheck::UseComputedDisplayOutsideStyle)) {
             AutoEditorDOMPointChildInvalidator lockOffset(splitPoint);
             nsresult rv = DeleteNodeWithTransaction(*maybeBRContent);
             if (NS_FAILED(rv)) {
@@ -9624,7 +9696,9 @@ nsresult HTMLEditor::GetInlineStyles(
     };
     for (Element* const inclusiveAncestor :
          aElement.InclusiveAncestorsOfType()) {
-      if (HTMLEditUtils::IsBlockElement(*inclusiveAncestor) ||
+      if (HTMLEditUtils::IsBlockElement(
+              *inclusiveAncestor,
+              BlockInlineCheck::UseComputedDisplayOutsideStyle) ||
           (givenElementIsEditable &&
            !HTMLEditUtils::IsSimplyEditableNode(*inclusiveAncestor))) {
         break;
@@ -9907,7 +9981,7 @@ void HTMLEditor::SetSelectionInterlinePosition() {
                 atCaret,
                 {WalkTreeOption::IgnoreNonEditableNode,
                  WalkTreeOption::StopAtBlockBoundary},
-                editingHost)) {
+                BlockInlineCheck::UseComputedDisplayStyle, editingHost)) {
       if (previousEditableContentInBlock->IsHTMLElement(nsGkAtoms::br)) {
         DebugOnly rvIgnored = SelectionRef().SetInterlinePosition(
             InterlinePosition::StartOfNextLine);
@@ -9931,7 +10005,9 @@ void HTMLEditor::SetSelectionInterlinePosition() {
   if (nsIContent* previousEditableContentInBlockAtCaret =
           HTMLEditUtils::GetPreviousSibling(
               *atCaret.GetChild(), {WalkTreeOption::IgnoreNonEditableNode})) {
-    if (HTMLEditUtils::IsBlockElement(*previousEditableContentInBlockAtCaret)) {
+    if (HTMLEditUtils::IsBlockElement(
+            *previousEditableContentInBlockAtCaret,
+            BlockInlineCheck::UseComputedDisplayStyle)) {
       DebugOnly rvIgnored = SelectionRef().SetInterlinePosition(
           InterlinePosition::StartOfNextLine);
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
@@ -9948,7 +10024,9 @@ void HTMLEditor::SetSelectionInterlinePosition() {
   if (nsIContent* nextEditableContentInBlockAtCaret =
           HTMLEditUtils::GetNextSibling(
               *atCaret.GetChild(), {WalkTreeOption::IgnoreNonEditableNode})) {
-    if (HTMLEditUtils::IsBlockElement(*nextEditableContentInBlockAtCaret)) {
+    if (HTMLEditUtils::IsBlockElement(
+            *nextEditableContentInBlockAtCaret,
+            BlockInlineCheck::UseComputedDisplayStyle)) {
       DebugOnly rvIgnored =
           SelectionRef().SetInterlinePosition(InterlinePosition::EndOfLine);
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
@@ -9984,7 +10062,8 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement(
   if (Element* const editableBlockElement =
           HTMLEditUtils::GetInclusiveAncestorElement(
               *point.ContainerAs(),
-              HTMLEditUtils::ClosestEditableBlockElement)) {
+              HTMLEditUtils::ClosestEditableBlockElement,
+              BlockInlineCheck::UseComputedDisplayStyle)) {
     if (editableBlockElement &&
         HTMLEditUtils::IsEmptyNode(
             *editableBlockElement,
@@ -10045,17 +10124,20 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement(
 
   if (nsCOMPtr previousEditableContent =
           HTMLEditUtils::GetPreviousContent(
-              point, {WalkTreeOption::IgnoreNonEditableNode}, editingHost)) {
+              point, {WalkTreeOption::IgnoreNonEditableNode},
+              BlockInlineCheck::UseComputedDisplayStyle, editingHost)) {
     // If caret and previous editable content are in same block element
     // (even if it's a non-editable element), we should put a padding 
// element at end of the block. const Element* const blockElementContainingCaret = HTMLEditUtils::GetInclusiveAncestorElement( *point.ContainerAs(), - HTMLEditUtils::ClosestBlockElement); + HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayStyle); const Element* const blockElementContainingPreviousEditableContent = - HTMLEditUtils::GetAncestorElement(*previousEditableContent, - HTMLEditUtils::ClosestBlockElement); + HTMLEditUtils::GetAncestorElement( + *previousEditableContent, HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayStyle); // If previous editable content of caret is in same block and a `
` // element, we need to adjust interline position. if (blockElementContainingCaret && @@ -10095,6 +10177,7 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement( *previousEditableContent, {WalkTreeOption::IgnoreNonEditableNode, WalkTreeOption::StopAtBlockBoundary}, + BlockInlineCheck::UseComputedDisplayStyle, editingHost)) { if (EditorUtils::IsPaddingBRElementForEmptyLastLine( *nextEditableContentInBlock)) { @@ -10118,7 +10201,7 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement( point, {WalkTreeOption::IgnoreNonEditableNode, WalkTreeOption::StopAtBlockBoundary}, - editingHost)) { + BlockInlineCheck::UseComputedDisplayStyle, editingHost)) { if (previousEditableContentInBlock->IsHTMLElement(nsGkAtoms::br) || previousEditableContentInBlock->IsText() || HTMLEditUtils::IsImage(previousEditableContentInBlock) || @@ -10129,11 +10212,11 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement( // If next editable content in same block is `
`, text node, `` or // `
`, current caret position is fine. - if (nsIContent* nextEditableContentInBlock = - HTMLEditUtils::GetNextContent(point, - {WalkTreeOption::IgnoreNonEditableNode, - WalkTreeOption::StopAtBlockBoundary}, - editingHost)) { + if (nsIContent* nextEditableContentInBlock = HTMLEditUtils::GetNextContent( + point, + {WalkTreeOption::IgnoreNonEditableNode, + WalkTreeOption::StopAtBlockBoundary}, + BlockInlineCheck::UseComputedDisplayStyle, editingHost)) { if (nextEditableContentInBlock->IsText() || nextEditableContentInBlock->IsAnyOfHTMLElements( nsGkAtoms::br, nsGkAtoms::img, nsGkAtoms::hr)) { @@ -10226,7 +10309,8 @@ nsresult HTMLEditor::RemoveEmptyNodesIn(const EditorDOMRange& aRange) { } EmptyCheckOptions options = {EmptyCheckOption::TreatListItemAsVisible, EmptyCheckOption::TreatTableCellAsVisible}; - if (!HTMLEditUtils::IsBlockElement(*content)) { + if (!HTMLEditUtils::IsBlockElement( + *content, BlockInlineCheck::UseComputedDisplayStyle)) { options += EmptyCheckOption::TreatSingleBRElementAsVisible; } if (!HTMLEditUtils::IsEmptyNode(*content, options)) { @@ -10417,9 +10501,9 @@ nsresult HTMLEditor::LiftUpListItemElement( // if it's first or last list item, don't need to split the list // otherwise we do. - bool isFirstListItem = HTMLEditUtils::IsFirstChild( + const bool isFirstListItem = HTMLEditUtils::IsFirstChild( aListItemElement, {WalkTreeOption::IgnoreNonEditableNode}); - bool isLastListItem = HTMLEditUtils::IsLastChild( + const bool isLastListItem = HTMLEditUtils::IsLastChild( aListItemElement, {WalkTreeOption::IgnoreNonEditableNode}); Element* leftListElement = aListItemElement.GetParentElement(); @@ -10685,7 +10769,8 @@ nsresult HTMLEditor::InsertPaddingBRElementForEmptyLastLineIfNeeded( Element& aElement) { MOZ_ASSERT(IsEditActionDataAvailable()); - if (!HTMLEditUtils::IsBlockElement(aElement)) { + if (!HTMLEditUtils::IsBlockElement( + aElement, BlockInlineCheck::UseComputedDisplayStyle)) { return NS_OK; } @@ -10813,7 +10898,8 @@ Result HTMLEditor::RemoveAlignFromDescendants( continue; } - if (!HTMLEditUtils::IsBlockElement(*content) && + if (!HTMLEditUtils::IsBlockElement(*content, + BlockInlineCheck::UseHTMLDefaultStyle) && !content->IsHTMLElement(nsGkAtoms::hr)) { continue; } @@ -10896,7 +10982,8 @@ HTMLEditor::EnsureHardLineBeginsWithFirstChildOf( return CreateElementResult::NotHandled(); } - if (HTMLEditUtils::IsBlockElement(*firstEditableChild) || + if (HTMLEditUtils::IsBlockElement( + *firstEditableChild, BlockInlineCheck::UseComputedDisplayStyle) || firstEditableChild->IsHTMLElement(nsGkAtoms::br)) { return CreateElementResult::NotHandled(); } @@ -10907,7 +10994,9 @@ HTMLEditor::EnsureHardLineBeginsWithFirstChildOf( return CreateElementResult::NotHandled(); } - if (HTMLEditUtils::IsBlockElement(*previousEditableContent) || + if (HTMLEditUtils::IsBlockElement( + *previousEditableContent, + BlockInlineCheck::UseComputedDisplayStyle) || previousEditableContent->IsHTMLElement(nsGkAtoms::br)) { return CreateElementResult::NotHandled(); } @@ -10931,7 +11020,8 @@ HTMLEditor::EnsureHardLineEndsWithLastChildOf( return CreateElementResult::NotHandled(); } - if (HTMLEditUtils::IsBlockElement(*firstEditableContent) || + if (HTMLEditUtils::IsBlockElement( + *firstEditableContent, BlockInlineCheck::UseComputedDisplayStyle) || firstEditableContent->IsHTMLElement(nsGkAtoms::br)) { return CreateElementResult::NotHandled(); } @@ -10942,7 +11032,8 @@ HTMLEditor::EnsureHardLineEndsWithLastChildOf( return CreateElementResult::NotHandled(); } - if (HTMLEditUtils::IsBlockElement(*nextEditableContent) || + if (HTMLEditUtils::IsBlockElement( + *nextEditableContent, BlockInlineCheck::UseComputedDisplayStyle) || nextEditableContent->IsHTMLElement(nsGkAtoms::br)) { return CreateElementResult::NotHandled(); } @@ -10959,7 +11050,8 @@ Result HTMLEditor::SetBlockElementAlign( Element& aBlockOrHRElement, const nsAString& aAlignType, EditTarget aEditTarget) { MOZ_ASSERT(IsEditActionDataAvailable()); - MOZ_ASSERT(HTMLEditUtils::IsBlockElement(aBlockOrHRElement) || + MOZ_ASSERT(HTMLEditUtils::IsBlockElement( + aBlockOrHRElement, BlockInlineCheck::UseHTMLDefaultStyle) || aBlockOrHRElement.IsHTMLElement(nsGkAtoms::hr)); MOZ_ASSERT(IsCSSEnabled() || HTMLEditUtils::SupportsAlignAttr(aBlockOrHRElement)); @@ -11283,7 +11375,7 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition( Result splitResult = extendedSelectionRanges .SplitTextAtEndBoundariesAndInlineAncestorsAtBothBoundaries( - *this, aEditingHost); + *this, BlockInlineCheck::UseHTMLDefaultStyle, aEditingHost); if (MOZ_UNLIKELY(splitResult.isErr())) { NS_WARNING( "AutoRangeArray::" @@ -11330,7 +11422,8 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition( // If there is no visible and editable nodes in the edit targets, make an // empty block. // XXX Isn't this odd if there are only non-editable visible nodes? - if (HTMLEditUtils::IsEmptyOneHardLine(arrayOfContents)) { + if (HTMLEditUtils::IsEmptyOneHardLine( + arrayOfContents, BlockInlineCheck::UseHTMLDefaultStyle)) { const auto atCaret = EditorBase::GetFirstSelectionStartPoint(); if (NS_WARN_IF(!atCaret.IsSet())) { diff --git a/editor/libeditor/HTMLEditUtils.cpp b/editor/libeditor/HTMLEditUtils.cpp index 27bc9a73303c..e0230c2e3296 100644 --- a/editor/libeditor/HTMLEditUtils.cpp +++ b/editor/libeditor/HTMLEditUtils.cpp @@ -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 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 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
element of aBlockElement, we don't // need to look for a line break in another block because the caller // needs to handle only preceding
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
...
...

// ^^^^ @@ -907,7 +1008,8 @@ bool HTMLEditUtils::ShouldInsertLinefeedCharacter( Element* closestEditableBlockElement = HTMLEditUtils::GetInclusiveAncestorElement( *aPointToInsert.ContainerAs(), - 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 nsIContent* HTMLEditUtils::GetPreviousContent( const EditorDOMPointBase& 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())) { + *aPoint.template ContainerAs(), 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 nsIContent* HTMLEditUtils::GetNextContent( const EditorDOMPointBase& 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())) { + HTMLEditUtils::IsBlockElement(*point.template ContainerAs(), + 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(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(); 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(&aEditingHost), - pointToInsert); + WSRunScanner wsScannerForPointToInsert( + const_cast(&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
, @@ -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>& 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); diff --git a/editor/libeditor/HTMLEditUtils.h b/editor/libeditor/HTMLEditUtils.h index 9b89e536a6b2..5c07ed5794bb 100644 --- a/editor/libeditor/HTMLEditUtils.h +++ b/editor/libeditor/HTMLEditUtils.h @@ -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
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>& aArrayOfContents) { + nsTArray>& 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; 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 static nsIContent* GetPreviousContent( const EditorDOMPointBase& aPoint, const WalkTreeOptions& aOptions, + BlockInlineCheck aBlockInlineCheck, const Element* aAncestorLimiter = nullptr); /** @@ -786,37 +817,26 @@ class HTMLEditUtils final { template static nsIContent* GetNextContent(const EditorDOMPointBase& 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; + + /** + * 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& 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(), aCurrentBlock, - aLeafNodeTypes, aAncestorLimiter); + aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter); } if (!HTMLEditUtils::IsContainerNode( *aStartPoint.template ContainerAs())) { return HTMLEditUtils::GetNextLeafContentOrNextBlockElement( *aStartPoint.template ContainerAs(), aCurrentBlock, - aLeafNodeTypes, aAncestorLimiter); + aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter); } nsCOMPtr nextContent = aStartPoint.GetChild(); @@ -1164,11 +1249,12 @@ class HTMLEditUtils final { // We are at end of non-block container return HTMLEditUtils::GetNextLeafContentOrNextBlockElement( *aStartPoint.template ContainerAs(), 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& 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(), aCurrentBlock, - aLeafNodeTypes, aAncestorLimiter); + aLeafNodeTypes, aBlockInlineCheck, aAncestorLimiter); } if (!HTMLEditUtils::IsContainerNode( *aStartPoint.template ContainerAs())) { return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement( *aStartPoint.template ContainerAs(), 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(), aCurrentBlock, - aLeafNodeTypes, aAncestorLimiter); + aLeafNodeTypes, IgnoreInsideBlockBoundary(aBlockInlineCheck), + aAncestorLimiter); } nsCOMPtr 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(&aContent); for (Element* element : aContent.AncestorsOfType()) { 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 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>& 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); /** diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 3fdd199f3236..5ab11770444d 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -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( //

// then, we should put caret at the
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 = 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 blockElement = closestBlockElement; blockElement;) { RefPtr nextBlockElement = HTMLEditUtils::GetAncestorElement( - *blockElement, HTMLEditUtils::ClosestBlockElement); + *blockElement, HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); DebugOnly 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 content = aContent; for (nsIContent* parentContent : aContent.AncestorsOfType()) { - 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 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 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 insertBRElementResult = InsertBRElement(WithTransaction::Yes, @@ -6212,7 +6252,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction( const RefPtr editableBlockStyledElement = nsStyledElement::FromNodeOrNull(HTMLEditUtils::GetAncestorElement( *range.StartRef().ContainerAs(), - 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(), - HTMLEditUtils::ClosestEditableBlockElement); + HTMLEditUtils::ClosestEditableBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); if (editableBlockElement && handledBlockParent != editableBlockElement) { handledBlockParent = editableBlockElement; nsStyledElement* const blockStyledElement = @@ -6356,7 +6399,8 @@ nsresult HTMLEditor::SetBlockBackgroundColorWithCSSAsSubAction( for (OwningNonNull& 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(), - HTMLEditUtils::ClosestEditableBlockElement); + HTMLEditUtils::ClosestEditableBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); if (editableBlockElement && handledBlockParent != editableBlockElement) { const RefPtr 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); diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 82ea3ab19134..bf48bbe6313c 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -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 - 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 - 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 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 RemoveBlockContainerElementsWithTransaction( - const nsTArray>& aArrayOfContents); + const nsTArray>& 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 diff --git a/editor/libeditor/HTMLEditorDataTransfer.cpp b/editor/libeditor/HTMLEditorDataTransfer.cpp index 8c897c674c56..a7f73ff12b51 100644 --- a/editor/libeditor/HTMLEditorDataTransfer.cpp +++ b/editor/libeditor/HTMLEditorDataTransfer.cpp @@ -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 // `
` 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(), - HTMLEditUtils::ClosestBlockElement) + HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle) : nullptr; EditorDOMPoint lastInsertedPoint; diff --git a/editor/libeditor/HTMLEditorDeleteHandler.cpp b/editor/libeditor/HTMLEditorDeleteHandler.cpp index c04ac566fde7..5d3cb601489e 100644 --- a/editor/libeditor/HTMLEditorDeleteHandler.cpp +++ b/editor/libeditor/HTMLEditorDeleteHandler.cpp @@ -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 HTMLEditor::AutoDeleteRangesHandler::Run( *caretPoint.ref().ContainerAs(), 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 HTMLEditor::AutoDeleteRangesHandler::Run( NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT)) { // Let's check whether there is new invisible `
` 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(); } else { mLeafContentInOtherBlock = HTMLEditUtils::GetFirstLeafContent( aOtherBlockElement, {LeafNodeType::OnlyEditableLeafNode}, - &aOtherBlockElement); + BlockInlineCheck::Unused, &aOtherBlockElement); mLeftContent = aCaretPoint.GetContainerAs(); 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 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 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 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 HTMLEditor::DeleteTextAndTextNodesWithTransaction( TreatEmptyTextNodes::RemoveAllEmptyInlineAncestors) { Element* emptyParentElementToRemove = HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement( - nodeToRemove, editingHost); + nodeToRemove, BlockInlineCheck::UseComputedDisplayOutsideStyle, + editingHost); if (emptyParentElementToRemove) { nodeToRemove = *emptyParentElementToRemove; } @@ -4702,10 +4726,12 @@ Result 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 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 HTMLEditor::AutoDeleteRangesHandler:: mPrecedingInvisibleBRElement = WSRunScanner::GetPrecedingBRElementUnlessVisibleContentFound( aHTMLEditor.ComputeEditingHost(), - mPointContainingTheOtherBlockElement); + mPointContainingTheOtherBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle); // `WhiteSpaceVisibilityKeeper:: // MergeFirstLineOfRightBlockElementIntoAncestorLeftBlockElement()` // returns ignored when: @@ -4847,7 +4875,8 @@ Result 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(), {WalkTreeOption::IgnoreDataNodeExceptText, WalkTreeOption::StopAtBlockBoundary}, + BlockInlineCheck::UseComputedDisplayOutsideStyle, editingHost) : nullptr; if (!nextContent || nextContent != range.StartRef().GetChild()) { @@ -5057,7 +5087,8 @@ Result 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(), - HTMLEditUtils::ClosestBlockElement) + HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle) : nullptr; mDestInclusiveAncestorBlock = mPointToInsert.IsInContentNode() ? HTMLEditUtils::GetInclusiveAncestorElement( *mPointToInsert.ContainerAs(), - HTMLEditUtils::ClosestBlockElement) + HTMLEditUtils::ClosestBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle) : nullptr; mMovingToParentBlock = mDestInclusiveAncestorBlock && mSrcInclusiveAncestorBlock && @@ -5211,7 +5245,8 @@ HTMLEditor::AutoMoveOneLineHandler::SplitToMakeTheLineIsolated( Result 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 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 moveChildrenResult = aHTMLEditor.MoveChildrenWithTransaction( MOZ_KnownLive(*content->AsElement()), pointToInsert, @@ -5390,13 +5429,15 @@ Result 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 emptyContent = HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement( - content, &aEditingHost, - pointToInsert.ContainerAs()); + content, BlockInlineCheck::UseComputedDisplayOutsideStyle, + &aEditingHost, pointToInsert.ContainerAs()); 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 inlineElement = HTMLEditUtils::GetMostDistantAncestorEditableEmptyInlineElement( - *textNodeEndingWithUnnecessaryLineBreak, &aEditingHost); + *textNodeEndingWithUnnecessaryLineBreak, + BlockInlineCheck::UseComputedDisplayOutsideStyle, + &aEditingHost); nsresult rv = aHTMLEditor.DeleteNodeWithTransaction( inlineElement ? static_cast(*inlineElement) : static_cast( @@ -5593,7 +5637,9 @@ nsresult HTMLEditor::AutoMoveOneLineHandler:: // should remove the parent too. if (const RefPtr 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 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( *nextContentOfEmptyBlock, aDirectionAndAmount); if (!pt.IsSet()) { @@ -6291,7 +6340,7 @@ Result HTMLEditor::AutoDeleteRangesHandler:: if (nsIContent* previousContentOfEmptyBlock = HTMLEditUtils::GetPreviousContent( atEmptyBlock, {WalkTreeOption::IgnoreNonEditableNode}, - aHTMLEditor.ComputeEditingHost())) { + BlockInlineCheck::Unused, aHTMLEditor.ComputeEditingHost())) { EditorDOMPoint pt = HTMLEditUtils::GetGoodCaretPointFor( *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 editableBlockContainingBRElement = HTMLEditUtils::GetInclusiveAncestorElement( *atFirstInvisibleBRElement.ContainerAs(), - HTMLEditUtils::ClosestEditableBlockElement)) { + HTMLEditUtils::ClosestEditableBlockElement, + BlockInlineCheck::UseComputedDisplayOutsideStyle)) { if (rangeToDelete.Contains( EditorRawDOMPoint(editableBlockContainingBRElement))) { return rangeToDelete; diff --git a/editor/libeditor/HTMLEditorState.cpp b/editor/libeditor/HTMLEditorState.cpp index 734fdd4feae3..aa747133ac5f 100644 --- a/editor/libeditor/HTMLEditorState.cpp +++ b/editor/libeditor/HTMLEditorState.cpp @@ -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 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& 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>& 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 content = aArrayOfContents[i]; + for (size_t index : Reversed(IntegerRange(aArrayOfContents.Length()))) { + OwningNonNull 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}); } diff --git a/editor/libeditor/HTMLStyleEditor.cpp b/editor/libeditor/HTMLStyleEditor.cpp index 759c11987654..259da0f784d5 100644 --- a/editor/libeditor/HTMLStyleEditor.cpp +++ b/editor/libeditor/HTMLStyleEditor.cpp @@ -768,7 +768,9 @@ bool HTMLEditor::AutoInlineStyleSetter::ElementIsGoodContainerToSetStyle( // E.g., we don't want to create new when // `

{ abc }

`. 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()) { 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()) { 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(), EditorType::HTML) || (aStartPoint.ContainerAs()->IsElement() && (HTMLEditUtils::IsBlockElement( - *aStartPoint.ContainerAs()) || + *aStartPoint.ContainerAs(), + BlockInlineCheck::UseComputedDisplayOutsideStyle) || HTMLEditUtils::IsDisplayInsideFlowRoot( *aStartPoint.ContainerAs())))) { break; @@ -1813,7 +1828,9 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter:: if (!EditorUtils::IsEditableContent(*aEndPoint.ContainerAs(), EditorType::HTML) || (aEndPoint.ContainerAs()->IsElement() && - (HTMLEditUtils::IsBlockElement(*aEndPoint.ContainerAs()) || + (HTMLEditUtils::IsBlockElement( + *aEndPoint.ContainerAs(), + BlockInlineCheck::UseComputedDisplayOutsideStyle) || HTMLEditUtils::IsDisplayInsideFlowRoot( *aEndPoint.ContainerAs())))) { break; @@ -1862,7 +1879,8 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter:: *aStartPoint.ChildAs())) && // but don't cross block boundary at climbing up the tree !HTMLEditUtils::IsBlockElement( - *aStartPoint.ContainerAs()) && + *aStartPoint.ContainerAs(), + BlockInlineCheck::UseComputedDisplayOutsideStyle) && // and the container is a good editable element to set CSS style aStartPoint.GetContainerAs() && ElementIsGoodContainerToSetStyle( @@ -1879,7 +1897,9 @@ EditorRawDOMRange HTMLEditor::AutoInlineStyleSetter:: !ElementIsGoodContainerToSetStyle( *aEndPoint.GetPreviousSiblingOfChildAs())) && // but don't cross block boundary at climbing up the tree - !HTMLEditUtils::IsBlockElement(*aEndPoint.ContainerAs()) && + !HTMLEditUtils::IsBlockElement( + *aEndPoint.ContainerAs(), + BlockInlineCheck::UseComputedDisplayOutsideStyle) && // and the container is a good editable element to set CSS style aEndPoint.GetContainerAs() && 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, 24> arrayOfParents; for (Element* element : aPointToSplit.GetContainer()->InclusiveAncestorsOfType()) { - 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 HTMLEditor::ClearStyleAt( emptyInlineContainerElements, {EmptyCheckOption::TreatSingleBRElementAsVisible, EmptyCheckOption::TreatListItemAsVisible, - EmptyCheckOption::TreatTableCellAsVisible}); + EmptyCheckOption::TreatTableCellAsVisible}, + BlockInlineCheck::UseComputedDisplayOutsideStyle); for (const OwningNonNull& emptyInlineContainerElement : emptyInlineContainerElements) { // MOZ_KnownLive(emptyInlineContainerElement) due to bug 1622253. diff --git a/editor/libeditor/WSRunObject.cpp b/editor/libeditor/WSRunObject.cpp index 23e1b48d12a6..3136c468dec2 100644 --- a/editor/libeditor/WSRunObject.cpp +++ b/editor/libeditor/WSRunObject.cpp @@ -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 WhiteSpaceVisibilityKeeper:: RefPtr 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 WhiteSpaceVisibilityKeeper:: // Do br adjustment. RefPtr 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 WhiteSpaceVisibilityKeeper:: RefPtr 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 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 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 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 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(aPoint); @@ -1736,7 +1747,8 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom( return WSScanResult(atPreviousChar.template NextPoint(), 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 @@ -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(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 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(), - 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 Maybe 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 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 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(), 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( - 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 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 Maybe 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 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()), 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 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 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 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(), EditorType::HTML) ? HTMLEditUtils::GetInclusiveAncestorElement( *mScanStartPoint.ContainerAs(), - 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(), *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(), EditorType::HTML) ? HTMLEditUtils::GetInclusiveAncestorElement( *mScanStartPoint.ContainerAs(), - 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(), *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(); } - 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(), 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()); + *aPoint.template ContainerAs(), + BlockInlineCheck::UseComputedDisplayStyle); if (!insertBRElement) { NS_ASSERTION( EditorUtils::IsEditableContent( @@ -3373,7 +3419,8 @@ nsresult WhiteSpaceVisibilityKeeper::NormalizeVisibleWhiteSpacesAt( *aPoint.template ContainerAs(), EditorType::HTML) ? HTMLEditUtils::GetInclusiveAncestorElement( *aPoint.template ContainerAs(), - 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 `
` 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 ``. 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(&aAtomicContent)), aEditingHost); + EditorDOMPoint(const_cast(&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(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(&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., ``, non-editable text node, etc) or a block level void // element like `
`, 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 `
` element, special inline content // (e.g., ``, non-editable text node, etc) or a block level void // element like `
`, 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); } diff --git a/editor/libeditor/WSRunObject.h b/editor/libeditor/WSRunObject.h index 0894244cffa4..acefd2c7d04c 100644 --- a/editor/libeditor/WSRunObject.h +++ b/editor/libeditor/WSRunObject.h @@ -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()), 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 WSRunScanner(const Element* aEditingHost, - const EditorDOMPointType& aScanStartPoint) + const EditorDOMPointType& aScanStartPoint, + BlockInlineCheck aBlockInlineCheck) : mScanStartPoint(aScanStartPoint.template To()), mEditingHost(const_cast(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& aPoint) const; template static WSScanResult ScanNextVisibleNodeOrBlockBoundary( - const Element* aEditingHost, const EditorDOMPointBase& aPoint) { - return WSRunScanner(aEditingHost, aPoint) + const Element* aEditingHost, const EditorDOMPointBase& aPoint, + BlockInlineCheck aBlockInlineCheck) { + return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) .ScanNextVisibleNodeOrBlockBoundaryFrom(aPoint); } @@ -352,8 +362,9 @@ class MOZ_STACK_CLASS WSRunScanner final { const EditorDOMPointBase& aPoint) const; template static WSScanResult ScanPreviousVisibleNodeOrBlockBoundary( - const Element* aEditingHost, const EditorDOMPointBase& aPoint) { - return WSRunScanner(aEditingHost, aPoint) + const Element* aEditingHost, const EditorDOMPointBase& aPoint, + BlockInlineCheck aBlockInlineCheck) { + return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) .ScanPreviousVisibleNodeOrBlockBoundaryFrom(aPoint); } @@ -365,14 +376,15 @@ class MOZ_STACK_CLASS WSRunScanner final { template static EditorDOMPointType GetInclusiveNextEditableCharPoint( - Element* aEditingHost, const EditorDOMPointBase& aPoint) { + Element* aEditingHost, const EditorDOMPointBase& aPoint, + BlockInlineCheck aBlockInlineCheck) { if (aPoint.IsInTextNode() && !aPoint.IsEndOfContainer() && HTMLEditUtils::IsSimplyEditableNode( *aPoint.template ContainerAs())) { return EditorDOMPointType(aPoint.template ContainerAs(), aPoint.Offset()); } - return WSRunScanner(aEditingHost, aPoint) + return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) .GetInclusiveNextEditableCharPoint(aPoint); } @@ -383,14 +395,15 @@ class MOZ_STACK_CLASS WSRunScanner final { template static EditorDOMPointType GetPreviousEditableCharPoint( - Element* aEditingHost, const EditorDOMPointBase& aPoint) { + Element* aEditingHost, const EditorDOMPointBase& aPoint, + BlockInlineCheck aBlockInlineCheck) { if (aPoint.IsInTextNode() && !aPoint.IsStartOfContainer() && HTMLEditUtils::IsSimplyEditableNode( *aPoint.template ContainerAs())) { return EditorDOMPointType(aPoint.template ContainerAs(), aPoint.Offset() - 1); } - return WSRunScanner(aEditingHost, aPoint) + return WSRunScanner(aEditingHost, aPoint, aBlockInlineCheck) .GetPreviousEditableCharPoint(aPoint); } @@ -483,7 +496,8 @@ class MOZ_STACK_CLASS WSRunScanner final { template 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 `
` 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 BoundaryData(const EditorDOMPointType& aPoint, nsIContent& aReasonContent, WSType aReason) @@ -898,10 +914,12 @@ class MOZ_STACK_CLASS WSRunScanner final { */ template static Maybe ScanCollapsibleWhiteSpaceStartInTextNode( - const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData); + const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData, + BlockInlineCheck aBlockInlineCheck); template static Maybe ScanCollapsibleWhiteSpaceEndInTextNode( - const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData); + const EditorDOMPointType& aPoint, NoBreakingSpaceData* aNBSPData, + BlockInlineCheck aBlockInlineCheck); nsCOMPtr 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 + TextFragmentData(const WSRunScanner& aWSRunScanner, + const EditorDOMPointType& aPoint) + : TextFragmentData(aPoint, aWSRunScanner.mEditingHost, + aWSRunScanner.mBlockInlineCheck) {} + template 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 mLeadingWhiteSpaceRange; mutable Maybe mTrailingWhiteSpaceRange; mutable Maybe 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; }; diff --git a/editor/nsIHTMLEditor.idl b/editor/nsIHTMLEditor.idl index fd79f0b868f9..952d924c5641 100644 --- a/editor/nsIHTMLEditor.idl +++ b/editor/nsIHTMLEditor.idl @@ -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 diff --git a/editor/spellchecker/TextServicesDocument.cpp b/editor/spellchecker/TextServicesDocument.cpp index de69491f8427..c6b06e90e6d1 100644 --- a/editor/spellchecker/TextServicesDocument.cpp +++ b/editor/spellchecker/TextServicesDocument.cpp @@ -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; } diff --git a/layout/generic/test/test_bug1642588.html b/layout/generic/test/test_bug1642588.html index 48f2eecf4f17..56ebc6fc1ea8 100644 --- a/layout/generic/test/test_bug1642588.html +++ b/layout/generic/test/test_bug1642588.html @@ -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 (
)`); } function collapsedSelectionTest(host, clickCount) { diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 35e4c6084b19..6982a3f0c1d2 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -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 diff --git a/testing/web-platform/meta/editing/other/insertparagraph-with-white-space-style.tentative.html.ini b/testing/web-platform/meta/editing/other/insertparagraph-with-white-space-style.tentative.html.ini index b231ff51c651..7d60ec3ff831 100644 --- a/testing/web-platform/meta/editing/other/insertparagraph-with-white-space-style.tentative.html.ini +++ b/testing/web-platform/meta/editing/other/insertparagraph-with-white-space-style.tentative.html.ini @@ -260,19 +260,24 @@ expected: if (os == "android") and fission: [OK, TIMEOUT] [
abc[\]
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
[\]abc
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
a[\]bc
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div) (preserving temporary inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div) (preserving inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div)] expected: FAIL @@ -293,19 +298,24 @@ expected: FAIL [
abc[\]
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
[\]abc
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
a[\]bc
(defaultparagraphseparator: div)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div) (preserving temporary inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div) (preserving inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: div)] expected: FAIL @@ -326,19 +336,24 @@ expected: FAIL [
abc[\]
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
[\]abc
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
a[\]bc
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p) (preserving temporary inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p) (preserving inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p)] expected: FAIL @@ -359,19 +374,24 @@ expected: FAIL [
abc[\]
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
[\]abc
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
a[\]bc
(defaultparagraphseparator: p)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p) (preserving temporary inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p) (preserving inline style test)] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [
abc[\]
(defaultparagraphseparator: p)] expected: FAIL diff --git a/testing/web-platform/meta/editing/run/backcolor.html.ini b/testing/web-platform/meta/editing/run/backcolor.html.ini index d280ac85c3ec..c12705b43079 100644 --- a/testing/web-platform/meta/editing/run/backcolor.html.ini +++ b/testing/web-platform/meta/editing/run/backcolor.html.ini @@ -158,6 +158,10 @@ [[["stylewithcss","true"\],["backcolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("backcolor") before] expected: FAIL + [[["stylewithcss","false"\],["backcolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("backcolor") before] + expected: + if early_beta_or_earlier: FAIL + [[["stylewithcss","false"\],["backcolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("backcolor") after] expected: FAIL diff --git a/testing/web-platform/meta/editing/run/delete.html.ini b/testing/web-platform/meta/editing/run/delete.html.ini index de784146c384..ccce18a788c5 100644 --- a/testing/web-platform/meta/editing/run/delete.html.ini +++ b/testing/web-platform/meta/editing/run/delete.html.ini @@ -518,19 +518,24 @@ expected: FAIL [[["delete",""\]\] "

fo[o

b\]ar" compare innerHTML] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [[["stylewithcss","true"\],["delete",""\]\] "fo[ob\]ar" compare innerHTML] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [[["stylewithcss","false"\],["delete",""\]\] "fo[ob\]ar" compare innerHTML] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [[["stylewithcss","true"\],["delete",""\]\] "fo[ob\]ar" compare innerHTML] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [[["stylewithcss","false"\],["delete",""\]\] "fo[ob\]ar" compare innerHTML] - expected: FAIL + expected: + if not early_beta_or_earlier: FAIL [[["delete",""\]\] "

  1. foo
{}
  1. bar
" compare innerHTML] expected: FAIL diff --git a/testing/web-platform/meta/editing/run/hilitecolor.html.ini b/testing/web-platform/meta/editing/run/hilitecolor.html.ini index 79f7a4798b99..9349a7c11246 100644 --- a/testing/web-platform/meta/editing/run/hilitecolor.html.ini +++ b/testing/web-platform/meta/editing/run/hilitecolor.html.ini @@ -160,6 +160,10 @@ [[["stylewithcss","true"\],["hilitecolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("hilitecolor") before] expected: FAIL + [[["stylewithcss","false"\],["hilitecolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("hilitecolor") before] + expected: + if early_beta_or_earlier: FAIL + [[["stylewithcss","false"\],["hilitecolor","#00FFFF"\]\] "b[ar\]" queryCommandValue("hilitecolor") after] expected: FAIL diff --git a/testing/web-platform/tests/editing/other/insertparagraph-in-non-splittable-element.html b/testing/web-platform/tests/editing/other/insertparagraph-in-non-splittable-element.html index 21aa495bd675..c77862fecb29 100644 --- a/testing/web-platform/tests/editing/other/insertparagraph-in-non-splittable-element.html +++ b/testing/web-platform/tests/editing/other/insertparagraph-in-non-splittable-element.html @@ -26,10 +26,7 @@ const tests = [ selector: "caption", initial: "
abc
abc
", // can have paragraphs so that it should be handled as in a block. - expected: [ - "

abc
abc
", - "

abc
abc
", - ], + expected: "

abc
abc
", }, { selector: "col",