`AutoEditActionDataSetter` is created in the stack when editor's public method
is called and that guarantees lifetime of global objects in editor such as
editor itself, selection controller, etc.
The dispatcher of `beforeinput` event returns `NS_ERROR_EDITOR_ACTION_CANCELED`
if an event is actually dispatched but canceled. The reason why it's an error
is, editor code must stop handling anything when any methods return error.
So, returning an error code is reasonable in editor module. But when it's
filtered by `EditorBase::ToGenericNSResult()` at return statement of public
methods, it's converted to `NS_SUCCESS_DOM_NO_OPERATION`. This avoids throwing
new exception, but editor class users in C++ can distinguish whether each edit
action is canceled or handled. The reason why we should not throw new
exception from XPCOM API is, without taking care of each caller may break some
our UI (especially for avoiding to break comm-central). Therefore, this patch
does not make XPCOM methods return error code when `beforeinput` event is
canceled.
In most cases, immediately after creating `AutoEditActionDataSetter` is good
timing to dispatch `beforeinput` event since editor has not touched the DOM
yet. If `beforeinput` requires `data` or `dataTransfer`, methods need to
dispatch `beforeinput` event after that. Alhtough this is not a good thing
from point of view of consistency of the code. However, I have no better
idea.
Note 1: Our implementation does NOT conform to the spec about event order
between `keypress` and `beforeinput` (dispatching `beforeinput` event after
`keypress` event). However, we follow all other browsers' behavior so that it
must be safe and the spec should be updated for backward compatibility.
Spec issue: https://github.com/w3c/uievents/issues/220
Note 2: Our implementation does NOT conform to the spec about event order
between `compositionupdate` and `beforeinput`. Our behavior is same as
Safari, but different from Chrome. This might cause web-compat issues.
However, our behavior does make sense from point of view of consistency of
event spec. Additionally, at both `compositionupdate` and `beforeinput`,
composition string in editor has not been modified yet. Therefore, this
may not cause web-compat issues (and I hope so).
Spec issue: https://github.com/w3c/input-events/issues/49
Note that this patch makes editor detect bugs that `beforeinput` event hasn't
been handled yet when it dispatches `input` event or modifying `data` and
`dataTransfer` value are modified after dispatching `beforeinput` event with
`MOZ_ASSERT`s.
Differential Revision: https://phabricator.services.mozilla.com/D58127
Some HTML editor command classes call `*AsAction()` methods multiple times.
That causes that user needs multiple undo/redo for a command and one command
causes multiple "input" events. For both compatibility with the other
browsers and making "beforeinput" cancelable, they should call `*AsAction()`
once. Instead, `HTMLEditor` should handle related element deletion.
This patch makes `HTMLEditor::RemoveInlinePropertyInternal()` remove multiple
elements if its caller allows, and `HTMLEditor::SetInlinePropertyAsAction()`
call `RemoveInlinePropertyInternal()` in some cases.
According to comm-central and BlueGriffon, we can make
`HTMLEditor::RemoveInlineProperty()` also removes the related methods
automatically because comm-central does same thing from script and BlueGriffon
does not use this. However, we cannot do that for
`HTMLEditor::SetInlineProperty()` because BlueGriffon may call it with any
HTML5 elements and does not expect removing elements in same block at that
time. If we needed to reduce the overhead of comm-central, we could change
only `RemoveInlineProperty()`, but it would make these APIs behavior
inconsistent.
Differential Revision: https://phabricator.services.mozilla.com/D58124
Finally, `Document.execCommand()` still does not work fine if selection
starts from very start of block and/or end at very end of block because
`PromoteInlineRange()` extends selection range to contain the
containers, then, `SubtreeContentIterator` won't list up text nodes.
In this case, `RemoveInlinePropertyInternal()` expects that
`RemoveStyleInside()` removes text node style with creating
`<span>` elements. However, `RemoveStyleInsilde()` only handles
`Element`s and it handles elements from most-descendants.
Therefore, it cannot distinguish whether text node style comes
from removing inline elements or parent block.
This patch makes `RemoveInlinePropertyInternal()` collect
descendant text nodes in the range after handling all nodes in
the range except descendant text nodes, then, check the
final style of descendant text nodes, finally, remove the style
if coming from parent block.
Differential Revision: https://phabricator.services.mozilla.com/D47865
If selection range is not in **one** text node, `RemoveInlinePropertyInternal()`
collects target nodes with `SubtreeContentIterator`. It only collects topmost
nodes which are **entirely** contained in the range (it's enough because their
descendants will be handled by `RemoveStyleInside()` recursively).
The reasons why it uses `SubtreeContentIterator` rather than
`PreContentIterator` must be:
1. Performance reason.
2. Assuming there are no multiple text nodes.
3. Not expects that user removes text node styles come from parent block.
The reason 2 is wrong because when removing a style, all browsers don't
join text nodes which was in removing element with adjacent text nodes.
(I.e., we cannot change this behavior for compatibility.)
The reason 3 is of course wrong we're struggling with this scenario.
Therefore, `RemoveInlinePropertyInternal()` needs to collect partially
selected text nodes by itself (if there are). Then, we can merge the
single text node selected case with the `for` loop.
Differential Revision: https://phabricator.services.mozilla.com/D47864
For compatibility with Chrome, when removing inline style at block parent,
we should reset the style with creating `<span>` element whose `style`
attribute removes the style. We do this only in CSS mode, but we should do
it in HTML mode too.
This patch also makes `FontFaceStateCommand::SetState()` ignore `tt` value
if its root caller is `Document::ExecCommand()`. It was implemented for
composer to handle XUL command in bug 115922. Therefore, we should not do
this special handling on the web. If it were possible to separate this
change to another bug, it'd be nicer. But without this change, we'll have
a lot of regressions of `Document.execCommand("fontname")`. Therefore,
this is also fixed in this patch.
Note that this removes first `.ini` file selection because
the tests cannot be run without test number range parameter.
So, the sections are not used anymore.
Differential Revision: https://phabricator.services.mozilla.com/D47862
For compatibility with Chrome, when removing inline style at block parent,
we should reset the style with creating `<span>` element whose `style`
attribute removes the style. We do this only in CSS mode, but we should do
it in HTML mode too.
This patch also makes `FontFaceStateCommand::SetState()` ignore `tt` value
if its root caller is `Document::ExecCommand()`. It was implemented for
composer to handle XUL command in bug 115922. Therefore, we should not do
this special handling on the web. If it were possible to separate this
change to another bug, it'd be nicer. But without this change, we'll have
a lot of regressions of `Document.execCommand("fontname")`. Therefore,
this is also fixed in this patch.
Note that this removes first `.ini` file selection because
the tests cannot be run without test number range parameter.
So, the sections are not used anymore.
Differential Revision: https://phabricator.services.mozilla.com/D47862
Surprisingly, its `aChildOnly` is never set to `true` and if it were set to
`true`, it does unnecessary recursive calls. Therefore, we can make it
simpler.
Differential Revision: https://phabricator.services.mozilla.com/D47860
Both method take a DOM point with `nsCOMPtr<nsINode>*` and `int32_t*`.
This makes each caller complicated. Instead, we should use stack only class
to return both `EditorDOMPoint` and `nsresult`. I name it `EditResult`.
Additionally, this fixes a bug of `HTMLeditor::SplitStyleAboveRange()`. That
is not tracking new selection start point while it splits elements at end
of given range. This is detected by the debug assertion in
`ToRawRangeBoundary()` (i.e., this fix is required to pass some tests).
Differential Revision: https://phabricator.services.mozilla.com/D47858
Now, we can get rid of `TextEditRules` and `HTMLEditRules` completely.
And also this patch renames their cpp files to `TextEditSubActionHandler`
and `HTMLEditSubActionHandler`.
`TextEditor::Init()` and `HTMLEditor::Init()` are still complicated due to
`AutoEditInitRulesTrigger`. The following patch will remove it.
Differential Revision: https://phabricator.services.mozilla.com/D45792
And also this patch make each `AutoEditSubActionNotifier` creator check
the result of `OnStartToHandleTopLevelEditSubAction()` at least for
`NS_ERROR_EDITOR_DESTROYED`.
We need to take care of its destructor's result later, though.
Differential Revision: https://phabricator.services.mozilla.com/D45786
Oddly, they are used only by `HTMLEditor`, but implemented by `TextEditRules`.
They cancels when the editor is in plaintext mode. So, actual things are
implemented by each caller. This patch cleans them up too.
Differential Revision: https://phabricator.services.mozilla.com/D45299
The members of `HTMLEditRules` which are used only while `WillDoAction()` and
`DidDoAction()` are called should be moved to specific stack only struct
`EditorBase::EditSubActionData`.
Differential Revision: https://phabricator.services.mozilla.com/D42106
`Document::ExecCommand()` knows subject principal. This patch makes it tell
`EditorCommand::DoCommand()` and `EditorCommand::DoCommandParam()`. Then,
makes they tell each editor public methods which may cause dispatching
`beforeinput` event once we implement it. Finally, each editor public
method sets it to the constructor of `EditorBase::AutoEditActionDataSetter`.
This means that when editor tries to dispatch `beforeinput` event, editor
can check whether it's called by JS or not from everywhere.
Differential Revision: https://phabricator.services.mozilla.com/D29635
It'd be better to change copy constructor of `EditorDOMPointBase` to explicit,
but it'd require too many changes in editor code. So, this patch just changes
each method callers only.
Differential Revision: https://phabricator.services.mozilla.com/D30054
This patch marks `EditorBase::InsertNodeTransaction()` **and** its callers as `MOZ_CAN_RUN_SCRIPT`.
Unfortunately, this patch tells us that some `GetSomething()` methods may destroy the editor since `HTMLEditRules::GetNodesForOperation()`, `HTMLEditRules::GetNodesFromPoint()` and `HTMLEditRules::GetNodesFromSelection()` may change the DOM tree. Additionally, initialization methods may destroy the editor since it may insert a bogus `<br>` node.
Note that this patch also removes some unused methods. I.e., they are not result of some cleaning up the code. This patch just avoids marking unused methods as `MOZ_CAN_RUN_SCRIPT`.
Differential Revision: https://phabricator.services.mozilla.com/D25027
This patch marks `EditorBase::InsertNodeTransaction()` **and** its callers as `MOZ_CAN_RUN_SCRIPT`.
Unfortunately, this patch tells us that some `GetSomething()` methods may destroy the editor since `HTMLEditRules::GetNodesForOperation()`, `HTMLEditRules::GetNodesFromPoint()` and `HTMLEditRules::GetNodesFromSelection()` may change the DOM tree. Additionally, initialization methods may destroy the editor since it may insert a bogus `<br>` node.
Note that this patch also removes some unused methods. I.e., they are not result of some cleaning up the code. This patch just avoids marking unused methods as `MOZ_CAN_RUN_SCRIPT`.
Differential Revision: https://phabricator.services.mozilla.com/D25027
As far as I've tested, Chrome does not throw exception even when editor is
destroyed or editor content is modified unexpectedly. So, we should return
`NS_OK` from most public methods of editor when internal methods return
`NS_ERROR_EDITOR_DESTROYED` or `NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE`.
Differential Revision: https://phabricator.services.mozilla.com/D20811
Although neither Chrome nor Safari does not set InputEvent.data when the event
is caused by `document.execCommand()` with `backColor`, `foreColor` nor
`hiliteColor`, Safari supports styling color with touchbar and in that case,
Safari sets it (*1).
Additionally, currently Safari uses `rgb()` to represents a color value and
using same rule to serializing color value for CSS OM matches Safari's behavior
and can represent any valid color values.
This patch makes given color value parsed and then serialized with same code
in style system. If the value is `currentcolor`, `inherit`, `initial` or `reset`, sets
the value as-is for now. Additionally, when given value is invalid, sets the value
as-is for forward compatibility.
Note that automated tests will be added into input-events-exec-command.html
by the last patch.
1. https://github.com/w3c/input-events/issues/94#issuecomment-461061517
Differential Revision: https://phabricator.services.mozilla.com/D19295
Although neither Chrome nor Safari does not set InputEvent.data value when
InputEvent.inputType is "fontName", but it's easy to implement. Therefore, this
patch implements it as declaration of Input Events.
This patch uses given value as-is. Perhaps, this shouldn't cause any problems
because such value can be set to Element.style.fontFamily without any changes.
Note that automated test will be added into WPT later.
Differential Revision: https://phabricator.services.mozilla.com/D19294
This patch makes ContentIteratorBase, PostContentIterator, PreContentIterator
and ContentSubtreeIterator classes non-refcountable because most users can
create their instances in stack and such users may be in a hot path. So,
we can save a lot of cost of instantiation.
Unfortunately, only ScriptableContentIterator creates one of the concrete
classes and needs to destroy it properly. Therefore, its
EnsureContentIterator(), destructor, traverse and unlink code becomes messy.
However, ScriptableContentIterator was designed for automated tests and we
need to maintain it not so many times. Therefore, improvement of other
users must be worthwhiler than this demerit.
Differential Revision: https://phabricator.services.mozilla.com/D15928
Now, all users of ContentSubtreeIterator can access it directly. This patch
makes them use the concrete class directly.
Differential Revision: https://phabricator.services.mozilla.com/D15920
This patch makes ContentIteratorBase, PostContentIterator, PreContentIterator
and ContentSubtreeIterator classes non-refcountable because most users can
create their instances in stack and such users may be in a hot path. So,
we can save a lot of cost of instantiation.
Unfortunately, only ScriptableContentIterator creates one of the concrete
classes and needs to destroy it properly. Therefore, its
EnsureContentIterator(), destructor, traverse and unlink code becomes messy.
However, ScriptableContentIterator was designed for automated tests and we
need to maintain it not so many times. Therefore, improvement of other
users must be worthwhiler than this demerit.
Differential Revision: https://phabricator.services.mozilla.com/D15928
Now, all users of ContentSubtreeIterator can access it directly. This patch
makes them use the concrete class directly.
Differential Revision: https://phabricator.services.mozilla.com/D15920
After fixing bug 1427060, HTMLEditor treats attribute of style as nullptr.
However, if empty string is used to call NS_Atomize(), it returns
nsGkAtoms::_empty. Therefore, HTMLEditor fails to check whether attribute is
specified or not with nullptr check since some root callers sets
nsGkAtoms::_empty instead of nullptr.
This patch makes HTMLEditor always use nullptr for empty string of attribute
of style with wrapping NS_Atomize() with AtomzieAttribute(). Additionally,
for safer change, this patch makes PropItem and TypeInState treat
nsGkAtom::_empty as nullptr.
Differential Revision: https://phabricator.services.mozilla.com/D13203
Similar to EditorBase::mSavedSel, we can move EditorBase::mRangeUpdater too
because of it's referred only when there is AutoEditActionDataSetter instance
so that it also does not need to be in the cycle collection.
And now, it can be marked as MOZ_STACK_CLASS and remove cycle collection
support.
Differential Revision: https://phabricator.services.mozilla.com/D12402
Now, any protected/private methods of editor classes can refer
SelectionRefPtr() safely. So, we can cut the cost of calling GetSelection()
only once per edit action handling.
Differential Revision: https://phabricator.services.mozilla.com/D10011
When each method of TextEditRules and HTMLEditRules should be called only by
EditorBase/TextEditor/HTMLEditor while the editor instance has
AutoEditActionDataSetter instance. Therefore, we can get rid of all
pointers/references of Selection from each method's argument.
Additionally, this reimplements TextEditRules::SelectionRef() with
EditorBase::SelectionRefPtr() and make it return |const RefPtr<Selection>&|
rather than |Selection&| since RefPtr reference is required when we call
methods which are marked as MOZ_CAN_RUN_SCRIPT.
Differential Revision: https://phabricator.services.mozilla.com/D10010
EditorBase::SelectionRefPtr() is now safe to use in editor and really fast to
retrieve Selection than EditorBase::GetSelection(). Therefore, we can get rid of
all Selection pointer/reference argument of each method which always take
normal Selection.
Note that this changes nsIHTMLEditor.checkSelectionStateForAnonymousButtons()
because its argument is only Selection. So, BlueGriffon should work even
though it calls the method with nsIEditor.selection.
Differential Revision: https://phabricator.services.mozilla.com/D10009
AutoTransactionBatch, AutoPlaceholderBatch, AutoSelectionRestorer,
AutoTopLevelEditSubActionNotifier, AutoTransactionsConserveSelection and
AutoUpdateViewBatch access protected members of EditorBase. The access
scope management assume that they are used only by EditorBase or its
subclasses or TextEditRules or its inherited class (i.e., HTMLEditRules).
For guaranteeing this at build-time, we should change them to nested classes
of EditorBase. Then, EditorBase and its subclasses and friends can use them.
Differential Revision: https://phabricator.services.mozilla.com/D9479
StyleUpdatingCommand::ToggleState() removes exclusive style when it sets
superscript style or subscript style. However, it accesses protected
members of EditorBase via AutoTransactionBatch even though it's outside
of editor classes.
This patch moves the removing exclusive style code from the method to
HTMLEditor::SetInlineProperty() and rename it "AsAction".
Differential Revision: https://phabricator.services.mozilla.com/D9477
Even though HTMLEditor::GetIsCSSEnabled() is an implementation of an XPCOM
method, it uses nsresult as its return type. We should change it to
NS_IMETHODIMP.
Additionally, SetDocumentStateCommand::GetCommandStateParams() calls this,
but HTMLEditor can expose non-virtual method, HTMLEditor::IsCSSEnabled().
Therefore, this patch makes it public and makes SetDocumentStateCommand use
HTMLEditor::IsCSSEnabled().
Differential Revision: https://phabricator.services.mozilla.com/D4304
Neither comm-central nor BlueGriffon uses nsIHTMLEditor.getFontColorSetate().
So, we can get rid of this from nsIHTMLEditor. However, we need to keep it
as a non-virtual public method since it's used by FontColorStateCommand.
Differential Revision: https://phabricator.services.mozilla.com/D4303
For making it possible to distinguish if HTMLEditor::RemoveInlineProperty() is
called by outer class or editor itself, this patch creates
Create HTMLEditor::RemoveInlinePropertyInternal() and makes the internal
callers use this new method.
Differential Revision: https://phabricator.services.mozilla.com/D3000
For making it possible to distinguish if SetInlineProperty() is called by outer
class or the editor itself, this patch creates SetInlinePropertyInternal().
Additionally, this makes the first argument of SetInlineProperty() from
nsAtom* to nsAtom& since it's not nullable.
Differential Revision: https://phabricator.services.mozilla.com/D2999