It and its helper class, `AutoInclusiveAncestorBlockElementsJoiner` work with
multiple ranges, but they handle special cases only with the first range.
That means that deleting content will be different if same structure is selected
with multiple ranges and that must be not expected by the users.
Differential Revision: https://phabricator.services.mozilla.com/D203853
It means that "treat non-editable things as visible" when it's not set.
However, it's odd. You must assume that if no option is set, `IsEmpty()` etc
should treat non-editable nodes as visible things. Therefore, this renames it
to `TreatNonEditableContentAsVisible` and changing all callers of
`HTMLEditUtils::IsEmptyNode`, `HTMLEditUtils::IsEmptyInlineContainer`,
`HTMLEditUtils::IsEmptyBlockElement` and
`HTMLEditUtils::CollectEmptyInlineContainerDescendants`. So, this does not
change any behavior.
Differential Revision: https://phabricator.services.mozilla.com/D196813
The text input of the multi-select combobox of Slack has the following
structure:
```
<div contenteditable style="display:flex">
<span class="c-multi_select_input__space"> </span>
<span class="c-multi_select_input__filter_query">text which you typed</span>
<span class="c-multi_select_input__space" contenteditable="false"> <span>
</div>
```
When you do "Select All", they adjust selection to start from start of the
text container `<span>` (i.e., `.c-multi_select_input__filter_query`).
Then, typing new character deletes selection first. At this time, in the
legacy mode, `AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete` does not
extend the deleting range because `<span>` is an inline element. However,
in the new mode, it extends the range because the `<span>` is a block since
it's a flex-item, and selection starts from current block boundary. Then,
deleting range starts before the text container. Finally, Gecko removes the
text container and the following non-editable `<span>`. Therefore, typing text
will be inserted as a child of the flex container which is the editing host.
Finally, Slack restores the previous structure and collapse selection to end
of the text.
Currently, Chrome does same thing for normal blocks without flex/gird container.
However, doing i in `AutoDeleteRangesHandler::ExtendOrShrinkRangeToDelete`
causes a lot of regressions. Therefore, this patch tries to avoid only the bug
in Slack. (I think that we need to redesign the deletion handler to fix it.)
Differential Revision: https://phabricator.services.mozilla.com/D195955
`AutoMoveOneLineHandler` uses `AutoRangeArray` API for block level edit
sub-actions. Therefore, the source line is computed with
`BlockInlineCheck::UseHTMLDefaultStyle`. However, the deletion handler works
with `BlockInlineCheck::UseComputedDisplayOutsideStyle`. Therefore,
`AutoMoveOneLineHandler` may try to move different range. In the reported
test case, it tries to move all content under the `<body>` into the
`<a display="table-header-group">` which is contained in the range. Therefore,
the `movedContentRange` check fails after the destination becomes into an
orphan node which was removed to move.
This patch renames the API and adds a `BlockInlineCheck` parameter to work
with both ways and makes `AutoMoveOneLineHandler` specify
`BlockInlineCheck::UseComputedDisplayOutsideStyle` as same as the other delete
handlers.
Finally, same thing may happen in
`HTMLEditor::OnEndHandlingTopLevelEditSubActionInternal`. This patch makes it
check whether the top-level edit sub-action is a block level one or not and
consider `BlockInlineCheck` with the result.
Depends on D194180
Differential Revision: https://phabricator.services.mozilla.com/D194181
Currently, we extend selection to outside block boundaries if selection starts
and/or ends very start/end of block boundaries. Then, replace most-distant
ancestor format node, but this is odd because the innermost format is applied
to the text and the other browsers targets the innermost ancestor formant node.
Therefore, we should align to them.
Additionally, our replacing code for `<dd>` and `<dt>` has not been implemented
yet. I guess that the old `HTMLEditUtils::IsFormatNode` returned `false` for
`<dd>`, `<dl>` and `<dt>` and it requires additional work for splitting parent
`<dl>` too. Now, we can do it with simple code.
Finally, we created new format block element if `<br>` element appears, but
the other browsers moves it into the new format node simply. Therefore, we
should follow them (about `<blockquote>`, we've already done this within
the different path).
Differential Revision: https://phabricator.services.mozilla.com/D190902
Blink [1] and WebKit [2] refers `display-outside` value when they consider whether an
element is a block or an inline.
However, our editor refers HTML default style instead. Therefore, our editor
cannot handle the following cases:
* If a container block is a non-HTML element whose `display` style is `block`.
* If a container `<div>` etc is styled as `inline` and typing `Enter` in it.
* If a container `<span>` is styled as `block` and it ends with spaces.
For making users get better result, we should follow the other browsers.
However, this is too risky change. Therefore, this patch enables new behavior
only in the Nightly channel and early beta builds to collect feedback from
testers.
The big rules of checking block vs. inline are:
* When we handle block level edit actions such as formatting block, indenting
or outdenting selection, making or removing list, we should keep referring
the HTML default style because the other browsers do so and the commands are
intended for modifying the HTML structure.
* Otherwise, we should refer the computed style of the block. However, if
working with non-connected elements, we may need a special handling that is
falling back to refer the HTML default style because `HTMLEditorDataTransfer`
work with non-connected document fragments.
* Finally, if we check visibility of collapsible white-spaces and `<br>`s, we
should refer computed style. However, in this case, we may need to treat
ancestor `inline-block`s as block too, but for siblings, we should refer only
`display-outside`.
1. https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/editing_utilities.cc;l=779;drc=31fb07c05718d671d96c227855bfe97af9e3fb20
2. https://searchfox.org/wubkat/rev/b054636fffeffa0314914a11ce39725a3057131e/Source/WebCore/editing/Editing.cpp#317
Differential Revision: https://phabricator.services.mozilla.com/D188598
Currently it runs if the instance is a `TextEditor` or it's in the plaintext
mode of `HTMLEditor`. However, it does not make sense to run it only in
specific mode of `HTMLEditor`, and most part does not make sense for
`HTMLEditor`.
This patch moves the method to `TextEditor`, and for
`EditorBase::InsertTextWithTransaction()` and
`AutoRangeArray::ExtendAnchorFocusRangeFor()`, adds new method to
`EditorDOMPointBase` to get a text node position if it points around
a text node.
Differential Revision: https://phabricator.services.mozilla.com/D181835
There are some paths which do not set `mAnchorFocusRange` correctly.
Therefore, even if its `RangeCount()` returns 1 or larger,
`GetAnchorFocusRange()` may return `nullptr`.
Differential Revision: https://phabricator.services.mozilla.com/D171045
The Custom Highlight API allows a use case where a `Range` of a `Highlight`
is also used as `Selection`. Due to the decision to use the `Selection` mechanism
to display `Highlight`s, a `Range` can be part of several `Selection`s.
Since the `Range` has a pointer to its associated `Selection`
to notify about changes, this must be adapted to allow several `Selections`.
As a tradeoff of performance and memory usage, the `Selection`s are stored
as `mozilla::LinkedList`. A helper class `mozilla::SelectionListWrapper`
was implemented to allow `Selection`s to be in multiple of these lists
and without having to be derived from `LinkedListElement<T>`.
To simplify usage of the list, the use case "does this range belong to Selection x?"
is wrapped into the convenience method`IsInSelection(Selection&)`;
The method previously named like this was renamed to `IsInAnySelection()`
to be named more precisely.
Registering and unregistering of the closest common inclusive ancestor
of the `Range` is done when the first `Selection` is registered and
the last `Selection` is unregistered.
Differential Revision: https://phabricator.services.mozilla.com/D169597
According to the WPTs and their result in the other browsers, we should:
* do not work with a range anchored from a node in an element which has `inert`.
* collapse the range first when it ends at a node in an element which has `inert`.
See new WPT for the detail.
Note that `inert` with `contenteditable` must not be so major cases. Therefore,
this patch does not fix the edge cases like the `nsFrameSelection` use cases
and replacing `Selection` cases of the other edit commands/operations.
Depends on D169037
Differential Revision: https://phabricator.services.mozilla.com/D169743
One of the crash reasons is, the destination is the parent `<video>` of the
`<ol>`. When `AutoRangeArray` considers the range of first line is, making
`<video><source/>{<ol><li>a</li></ol>}`. This is not intuitive, but extending
the range to outside of the block boundaries is required to collect editable
target nodes. However, this causes a problem. `AutoMoveOneLineHandler` splits
the parent `<video>` element at the range boundaries with
`AutoRangeArray::SplitTextNodesAtEndBoundariesAndParentInlineElementsAtBoundaries`
since it's treated as an inline element. However, the `<video>` element is the
container of destination, so this is one unexpected issue for
`AutoMoveOneLineHandler`. Then, it tries to move split empty nodes to same
or another `<video>` element (depending on the split node direction). However,
at this time, it fails to move the node and delete it instead because `<video>`
cannot have not all elements. If the source `<video>` and destination `<video>`
is same one, nodes disappear from `movedContentRange` in `Run()` and `Run()`
cannot track it. Therefore, the range becomes invalid.
Ideal approach to fix this issue is, we should redesign considering where is
a line and how to collect the target nodes. However, if I change the
`AutoRangeArray` methods to fix this case, a lot of regressions appeared because
they are shared in a lot of edit actions. Therefore, I give up to fix them.
Instead, this patch just prevents to split the destination container. This may
have not fixed the real point, However, for now, we should just patch this
case because this could be potentially a problem for web apps which use inline
elements with `display: block`.
Differential Revision: https://phabricator.services.mozilla.com/D168183
They are used in public inline methods of `HTMLEditor`. Therefore, they should
be defined in an exposed header file without other internal use things for the
editor module. Then, we can stop exposing `HTMLEditHelpers.h`.
Depends on D158632
Differential Revision: https://phabricator.services.mozilla.com/D158633
Similar to the previous patch, and for consistency between editor helper
classes, we should make result of getter methods of `EditorDOMPointBase` too.
Differential Revision: https://phabricator.services.mozilla.com/D153841