--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -50,39 +50,44 @@ class nsITransactionListener;
class nsIWidget;
class nsRange;
namespace mozilla {
class AddStyleSheetTransaction;
class AutoRules;
class AutoSelectionRestorer;
class AutoTransactionsConserveSelection;
+class AutoUpdateViewBatch;
class ChangeAttributeTransaction;
class CompositionTransaction;
class CreateElementTransaction;
+class CSSEditUtils;
class DeleteNodeTransaction;
class DeleteTextTransaction;
class EditAggregateTransaction;
class EditorEventListener;
class EditTransactionBase;
class ErrorResult;
class HTMLEditor;
+class HTMLEditUtils;
class IMEContentObserver;
class InsertNodeTransaction;
class InsertTextTransaction;
class JoinNodeTransaction;
class PlaceholderTransaction;
class RemoveStyleSheetTransaction;
class SplitNodeResult;
class SplitNodeTransaction;
class TextComposition;
class TextEditor;
class TextEditRules;
class TextInputListener;
class TextServicesDocument;
+class TypeInState;
+class WSRunObject;
enum class EditAction : int32_t;
namespace dom {
class DataTransfer;
class DragEvent;
class Element;
class EventTarget;
class Text;
@@ -192,39 +197,31 @@ class EditorBase : public nsIEditor
, public nsISelectionListener
, public nsSupportsWeakReference
{
public:
typedef dom::Element Element;
typedef dom::Selection Selection;
typedef dom::Text Text;
- enum IterDirection
- {
- kIterForward,
- kIterBackward
- };
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
+
+ // nsIEditor methods
+ NS_DECL_NSIEDITOR
+
+ // nsISelectionListener method
+ NS_DECL_NSISELECTIONLISTENER
/**
* The default constructor. This should suffice. the setting of the
* interfaces is done after the construction of the editor class.
*/
EditorBase();
-protected:
- /**
- * The default destructor. This should suffice. Should this be pure virtual
- * for someone to derive from the EditorBase later? I don't believe so.
- */
- virtual ~EditorBase();
-
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
-
/**
* Init is to tell the implementation of nsIEditor to begin its services
* @param aDoc The dom document interface being observed
* @param aRoot This is the root of the editable section of this
* document. If it is null then we get root
* from document body.
* @param aSelCon this should be used to get the selection location
* (will be null for HTML editors)
@@ -232,73 +229,443 @@ public:
* of the editor.
*/
virtual nsresult Init(nsIDocument& doc,
Element* aRoot,
nsISelectionController* aSelCon,
uint32_t aFlags,
const nsAString& aInitialValue);
+ /**
+ * PostCreate should be called after Init, and is the time that the editor
+ * tells its documentStateObservers that the document has been created.
+ */
+ nsresult PostCreate();
+
+ /**
+ * PreDestroy is called before the editor goes away, and gives the editor a
+ * chance to tell its documentStateObservers that the document is going away.
+ * @param aDestroyingFrames set to true when the frames being edited
+ * are being destroyed (so there is no need to modify any nsISelections,
+ * nor is it safe to do so)
+ */
+ virtual void PreDestroy(bool aDestroyingFrames);
+
bool IsInitialized() const { return !!mDocument; }
+ bool Destroyed() const { return mDidPreDestroy; }
+
nsIDocument* GetDocument() const { return mDocument; }
+
nsIPresShell* GetPresShell() const
{
return mDocument ? mDocument->GetShell() : nullptr;
}
nsPresContext* GetPresContext() const
{
nsIPresShell* presShell = GetPresShell();
return presShell ? presShell->GetPresContext() : nullptr;
}
+
already_AddRefed<nsIWidget> GetWidget();
+
nsISelectionController* GetSelectionController() const
{
if (mSelectionController) {
return mSelectionController;
}
if (!mDocument) {
return nullptr;
}
nsIPresShell* presShell = mDocument->GetShell();
if (!presShell) {
return nullptr;
}
nsISelectionController* sc = static_cast<PresShell*>(presShell);
return sc;
}
+
+ nsresult GetSelection(SelectionType aSelectionType,
+ Selection** aSelection);
+
+ Selection* GetSelection(SelectionType aSelectionType =
+ SelectionType::eNormal)
+ {
+ nsISelectionController* sc = GetSelectionController();
+ if (!sc) {
+ return nullptr;
+ }
+ Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
+ return selection;
+ }
+
+ /**
+ * Fast non-refcounting editor root element accessor
+ */
+ Element* GetRoot() const { return mRootElement; }
+
+ RangeUpdater& RangeUpdaterRef() { return mRangeUpdater; }
+
enum NotificationForEditorObservers
{
eNotifyEditorObserversOfEnd,
eNotifyEditorObserversOfBefore,
eNotifyEditorObserversOfCancel
};
void NotifyEditorObservers(NotificationForEditorObservers aNotification);
- // nsIEditor methods
- NS_DECL_NSIEDITOR
-
- // nsISelectionListener method
- NS_DECL_NSISELECTIONLISTENER
-
/**
* Set or unset TextInputListener. If setting non-nullptr when the editor
* already has a TextInputListener, this will crash in debug build.
*/
void SetTextInputListener(TextInputListener* aTextInputListener);
/**
* Set or unset IMEContentObserver. If setting non-nullptr when the editor
* already has an IMEContentObserver, this will crash in debug build.
*/
void SetIMEContentObserver(IMEContentObserver* aIMEContentObserver);
-public:
virtual bool IsModifiableNode(nsINode* aNode);
/**
+ * Returns current composition.
+ */
+ TextComposition* GetComposition() const;
+
+ /**
+ * Get preferred IME status of current widget.
+ */
+ virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
+
+ /**
+ * Returns true if there is composition string and not fixed.
+ */
+ bool IsIMEComposing() const;
+
+ /**
+ * Commit composition if there is.
+ * Note that when there is a composition, this requests to commit composition
+ * to native IME. Therefore, when there is composition, this can do anything.
+ * For example, the editor instance, the widget or the process itself may
+ * be destroyed.
+ */
+ nsresult CommitComposition();
+
+ void SwitchTextDirectionTo(uint32_t aDirection);
+
+ /**
+ * Finalizes selection and caret for the editor.
+ */
+ nsresult FinalizeSelection();
+
+ /**
+ * Returns true if selection is in an editable element and both the range
+ * start and the range end are editable. E.g., even if the selection range
+ * includes non-editable elements, returns true when one of common ancestors
+ * of the range start and the range end is editable. Otherwise, false.
+ */
+ bool IsSelectionEditable();
+
+ /**
+ * Returns number of undo or redo items.
+ */
+ size_t NumberOfUndoItems() const
+ {
+ return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
+ }
+ size_t NumberOfRedoItems() const
+ {
+ return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
+ }
+
+ /**
+ * Returns true if this editor can store transactions for undo/redo.
+ */
+ bool IsUndoRedoEnabled() const
+ {
+ return !!mTransactionManager;
+ }
+
+ /**
+ * Return true if it's possible to undo/redo right now.
+ */
+ bool CanUndo() const
+ {
+ return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
+ }
+ bool CanRedo() const
+ {
+ return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
+ }
+
+ /**
+ * Enables or disables undo/redo feature. Returns true if it succeeded,
+ * otherwise, e.g., we're undoing or redoing, returns false.
+ */
+ bool EnableUndoRedo(int32_t aMaxTransactionCount = -1)
+ {
+ if (!mTransactionManager) {
+ mTransactionManager = new TransactionManager();
+ }
+ return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
+ }
+ bool DisableUndoRedo()
+ {
+ if (!mTransactionManager) {
+ return true;
+ }
+ // XXX Even we clear the transaction manager, IsUndoRedoEnabled() keep
+ // returning true...
+ return mTransactionManager->DisableUndoRedo();
+ }
+ bool ClearUndoRedo()
+ {
+ if (!mTransactionManager) {
+ return true;
+ }
+ return mTransactionManager->ClearUndoRedo();
+ }
+
+ /**
+ * Adds or removes transaction listener to or from the transaction manager.
+ * Note that TransactionManager does not check if the listener is in the
+ * array. So, caller of AddTransactionListener() needs to manage if it's
+ * already been registered to the transaction manager.
+ */
+ bool AddTransactionListener(nsITransactionListener& aListener)
+ {
+ if (!mTransactionManager) {
+ return false;
+ }
+ return mTransactionManager->AddTransactionListener(aListener);
+ }
+ bool RemoveTransactionListener(nsITransactionListener& aListener)
+ {
+ if (!mTransactionManager) {
+ return false;
+ }
+ return mTransactionManager->RemoveTransactionListener(aListener);
+ }
+
+ virtual nsresult HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent);
+
+ virtual dom::EventTarget* GetDOMEventTarget() = 0;
+
+ /**
+ * Accessor methods to flags.
+ */
+ uint32_t Flags() const { return mFlags; }
+
+ nsresult AddFlags(uint32_t aFlags)
+ {
+ const uint32_t kOldFlags = Flags();
+ const uint32_t kNewFlags = (kOldFlags | aFlags);
+ if (kNewFlags == kOldFlags) {
+ return NS_OK;
+ }
+ return SetFlags(kNewFlags); // virtual call and may be expensive.
+ }
+ nsresult RemoveFlags(uint32_t aFlags)
+ {
+ const uint32_t kOldFlags = Flags();
+ const uint32_t kNewFlags = (kOldFlags & ~aFlags);
+ if (kNewFlags == kOldFlags) {
+ return NS_OK;
+ }
+ return SetFlags(kNewFlags); // virtual call and may be expensive.
+ }
+ nsresult AddAndRemoveFlags(uint32_t aAddingFlags, uint32_t aRemovingFlags)
+ {
+ MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
+ "Same flags are specified both adding and removing");
+ const uint32_t kOldFlags = Flags();
+ const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
+ if (kNewFlags == kOldFlags) {
+ return NS_OK;
+ }
+ return SetFlags(kNewFlags); // virtual call and may be expensive.
+ }
+
+ bool IsPlaintextEditor() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
+ }
+
+ bool IsSingleLineEditor() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) != 0;
+ }
+
+ bool IsPasswordEditor() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorPasswordMask) != 0;
+ }
+
+ // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
+ // the editor inherits the content node's direction.
+ bool IsRightToLeft() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorRightToLeft) != 0;
+ }
+ bool IsLeftToRight() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorLeftToRight) != 0;
+ }
+
+ bool IsReadonly() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorReadonlyMask) != 0;
+ }
+
+ bool IsDisabled() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorDisabledMask) != 0;
+ }
+
+ bool IsInputFiltered() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0;
+ }
+
+ bool IsMailEditor() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0;
+ }
+
+ bool IsWrapHackEnabled() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0;
+ }
+
+ bool IsFormWidget() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0;
+ }
+
+ bool NoCSS() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorNoCSSMask) != 0;
+ }
+
+ bool IsInteractionAllowed() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0;
+ }
+
+ bool DontEchoPassword() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
+ }
+
+ bool ShouldSkipSpellCheck() const
+ {
+ return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0;
+ }
+
+ bool IsTabbable() const
+ {
+ return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
+ IsInteractionAllowed();
+ }
+
+ bool HasIndependentSelection() const
+ {
+ return !!mSelectionController;
+ }
+
+ bool IsModifiable() const
+ {
+ return !IsReadonly();
+ }
+
+ /**
+ * IsInEditAction() return true while the instance is handling an edit action.
+ * Otherwise, false.
+ */
+ bool IsInEditAction() const { return mIsInEditAction; }
+
+ /**
+ * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
+ * "input" event.
+ */
+ void SuppressDispatchingInputEvent(bool aSuppress)
+ {
+ mDispatchInputEvent = !aSuppress;
+ }
+
+ /**
+ * IsSuppressingDispatchingInputEvent() returns true if the editor stops
+ * dispatching input event. Otherwise, false.
+ */
+ bool IsSuppressingDispatchingInputEvent() const
+ {
+ return !mDispatchInputEvent;
+ }
+
+ /**
+ * Returns true if markNodeDirty() has any effect. Returns false if
+ * markNodeDirty() is a no-op.
+ */
+ bool OutputsMozDirty() const
+ {
+ // Return true for Composer (!IsInteractionAllowed()) or mail
+ // (IsMailEditor()), but false for webpages.
+ return !IsInteractionAllowed() || IsMailEditor();
+ }
+
+ /**
+ * Get the input event target. This might return null.
+ */
+ virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0;
+
+ /**
+ * Get the focused content, if we're focused. Returns null otherwise.
+ */
+ virtual nsIContent* GetFocusedContent();
+
+ /**
+ * Get the focused content for the argument of some IMEStateManager's
+ * methods.
+ */
+ virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
+
+ /**
+ * Whether the aGUIEvent should be handled by this editor or not. When this
+ * returns false, The aGUIEvent shouldn't be handled on this editor,
+ * i.e., The aGUIEvent should be handled by another inner editor or ancestor
+ * elements.
+ */
+ virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent);
+
+ /**
+ * FindSelectionRoot() returns a selection root of this editor when aNode
+ * gets focus. aNode must be a content node or a document node. When the
+ * target isn't a part of this editor, returns nullptr. If this is for
+ * designMode, you should set the document node to aNode except that an
+ * element in the document has focus.
+ */
+ virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode);
+
+ /**
+ * This method has to be called by EditorEventListener::Focus.
+ * All actions that have to be done when the editor is focused needs to be
+ * added here.
+ */
+ void OnFocus(dom::EventTarget* aFocusEventTarget);
+
+ virtual nsresult InsertFromDrop(dom::DragEvent* aDropEvent) = 0;
+
+ /** Resyncs spellchecking state (enabled/disabled). This should be called
+ * when anything that affects spellchecking state changes, such as the
+ * spellcheck attribute value.
+ */
+ void SyncRealTimeSpell();
+
+protected: // May be called by friends.
+ /**
* InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
* better insertion point around it. If aPointToInsert isn't in a text node,
* this method looks for the nearest point in a text node with
* FindBetterInsertionPoint(). If there is no text node, this creates
* new text node and put aStringToInsert to it.
*
* @param aDocument The document of this editor.
* @param aStringToInsert The string to insert.
@@ -651,43 +1018,16 @@ public:
/**
* Creates text node which is marked as "maybe modified frequently".
*/
static already_AddRefed<nsTextNode> CreateTextNode(nsIDocument& aDocument,
const nsAString& aData);
/**
- * Get preferred IME status of current widget.
- */
- virtual nsresult GetPreferredIMEState(widget::IMEState* aState);
-
- /**
- * Commit composition if there is.
- * Note that when there is a composition, this requests to commit composition
- * to native IME. Therefore, when there is composition, this can do anything.
- * For example, the editor instance, the widget or the process itself may
- * be destroyed.
- */
- nsresult CommitComposition();
-
- void SwitchTextDirectionTo(uint32_t aDirection);
-
- RangeUpdater& RangeUpdaterRef() { return mRangeUpdater; }
-
- /**
- * Finalizes selection and caret for the editor.
- */
- nsresult FinalizeSelection();
-
-protected:
- nsresult DetermineCurrentDirection();
- void FireInputEvent();
-
- /**
* Create an element node whose name is aTag at before aPointToInsert. When
* this succeed to create an element node, this sets aPointToInsert to the
* new element because the relation of child and offset may be broken.
* If the caller needs to collapse the selection to next to the new element
* node, it should call |aPointToInsert.AdvanceOffset()| after calling this.
*
* @param aTag The element name to create.
* @param aPointToInsert The insertion point of new element. If this refers
@@ -794,218 +1134,16 @@ protected:
*/
already_AddRefed<Element>
InsertContainerWithTransactionInternal(nsIContent& aContent,
nsAtom& aTagName,
nsAtom& aAttribute,
const nsAString& aAttributeValue);
/**
- * Called after a transaction is done successfully.
- */
- void DoAfterDoTransaction(nsITransaction *aTxn);
-
- /**
- * Called after a transaction is undone successfully.
- */
-
- void DoAfterUndoTransaction();
-
- /**
- * Called after a transaction is redone successfully.
- */
- void DoAfterRedoTransaction();
-
- // Note that aSelection is optional and can be nullptr.
- nsresult DoTransaction(Selection* aSelection,
- nsITransaction* aTxn);
-
- enum TDocumentListenerNotification
- {
- eDocumentCreated,
- eDocumentToBeDestroyed,
- eDocumentStateChanged
- };
-
- /**
- * Tell the doc state listeners that the doc state has changed.
- */
- nsresult NotifyDocumentListeners(
- TDocumentListenerNotification aNotificationType);
-
- /**
- * Make the given selection span the entire document.
- */
- virtual nsresult SelectEntireDocument(Selection* aSelection);
-
- /**
- * Helper method for scrolling the selection into view after
- * an edit operation. aScrollToAnchor should be true if you
- * want to scroll to the point where the selection was started.
- * If false, it attempts to scroll the end of the selection into view.
- *
- * Editor methods *should* call this method instead of the versions
- * in the various selection interfaces, since this version makes sure
- * that the editor's sync/async settings for reflowing, painting, and
- * scrolling match.
- */
- nsresult ScrollSelectionIntoView(bool aScrollToAnchor);
-
- virtual bool IsBlockNode(nsINode* aNode);
-
- /**
- * Helper for GetPreviousNodeInternal() and GetNextNodeInternal().
- */
- nsIContent* FindNextLeafNode(nsINode* aCurrentNode,
- bool aGoForward,
- bool bNoBlockCrossing);
- nsIContent* FindNode(nsINode* aCurrentNode,
- bool aGoForward,
- bool aEditableNode,
- bool aFindAnyDataNode,
- bool bNoBlockCrossing);
-
- /**
- * Get the node immediately previous node of aNode.
- * @param atNode The node from which we start the search.
- * @param aFindEditableNode If true, only return an editable node.
- * @param aFindAnyDataNode If true, may return invisible data node
- * like Comment.
- * @param aNoBlockCrossing If true, don't move across "block" nodes,
- * whatever that means.
- * @return The node that occurs before aNode in
- * the tree, skipping non-editable nodes if
- * aFindEditableNode is true. If there is no
- * previous node, returns nullptr.
- */
- nsIContent* GetPreviousNodeInternal(nsINode& aNode,
- bool aFindEditableNode,
- bool aFindAnyDataNode,
- bool aNoBlockCrossing);
-
- /**
- * And another version that takes a point in DOM tree rather than a node.
- */
- nsIContent* GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
- bool aFindEditableNode,
- bool aFindAnyDataNode,
- bool aNoBlockCrossing);
-
- /**
- * Get the node immediately next node of aNode.
- * @param aNode The node from which we start the search.
- * @param aFindEditableNode If true, only return an editable node.
- * @param aFindAnyDataNode If true, may return invisible data node
- * like Comment.
- * @param aNoBlockCrossing If true, don't move across "block" nodes,
- * whatever that means.
- * @return The node that occurs after aNode in the
- * tree, skipping non-editable nodes if
- * aFindEditableNode is true. If there is no
- * next node, returns nullptr.
- */
- nsIContent* GetNextNodeInternal(nsINode& aNode,
- bool aFindEditableNode,
- bool aFindAnyDataNode,
- bool bNoBlockCrossing);
-
- /**
- * And another version that takes a point in DOM tree rather than a node.
- */
- nsIContent* GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
- bool aFindEditableNode,
- bool aFindAnyDataNode,
- bool aNoBlockCrossing);
-
-
- virtual nsresult InstallEventListeners();
- virtual void CreateEventListeners();
- virtual void RemoveEventListeners();
-
- /**
- * Return true if spellchecking should be enabled for this editor.
- */
- bool GetDesiredSpellCheckState();
-
- bool CanEnableSpellCheck()
- {
- // Check for password/readonly/disabled, which are not spellchecked
- // regardless of DOM. Also, check to see if spell check should be skipped
- // or not.
- return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() &&
- !ShouldSkipSpellCheck();
- }
-
- nsresult GetSelection(SelectionType aSelectionType,
- Selection** aSelection);
-
- /**
- * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
- * This set of methods are similar to the (Begin|End)Transaction(), but do
- * not use the transaction managers batching feature. Instead we use a
- * placeholder transaction to wrap up any further transaction while the
- * batch is open. The advantage of this is that placeholder transactions
- * can later merge, if needed. Merging is unavailable between transaction
- * manager batches.
- */
- void BeginPlaceholderTransaction(nsAtom* aTransactionName);
- void EndPlaceholderTransaction();
-
- /**
- * InitializeSelectionAncestorLimit() is called by InitializeSelection().
- * When this is called, each implementation has to call
- * aSelection.SetAncestorLimiter() with aAnotherLimit.
- *
- * @param aSelection The selection.
- * @param aAncestorLimit New ancestor limit of aSelection. This always
- * has parent node. So, it's always safe to
- * call SetAncestorLimit() with this node.
- */
- virtual void InitializeSelectionAncestorLimit(Selection& aSelection,
- nsIContent& aAncestorLimit);
-
-public:
- /**
- * PostCreate should be called after Init, and is the time that the editor
- * tells its documentStateObservers that the document has been created.
- */
- nsresult PostCreate();
-
- /**
- * PreDestroy is called before the editor goes away, and gives the editor a
- * chance to tell its documentStateObservers that the document is going away.
- * @param aDestroyingFrames set to true when the frames being edited
- * are being destroyed (so there is no need to modify any nsISelections,
- * nor is it safe to do so)
- */
- virtual void PreDestroy(bool aDestroyingFrames);
-
- /**
- * All editor operations which alter the doc should be prefaced
- * with a call to StartOperation, naming the action and direction.
- */
- virtual nsresult StartOperation(EditAction opID,
- nsIEditor::EDirection aDirection);
-
- /**
- * All editor operations which alter the doc should be followed
- * with a call to EndOperation.
- */
- virtual nsresult EndOperation();
-
- /**
- * Routines for managing the preservation of selection across
- * various editor actions.
- */
- bool ArePreservingSelection();
- void PreserveSelectionAcrossActions(Selection* aSel);
- nsresult RestorePreservedSelection(Selection* aSel);
- void StopPreservingSelection();
-
- /**
* DoSplitNode() creates a new node (left node) identical to an existing
* node (right node), and split the contents between the same point in both
* nodes.
*
* @param aStartOfRightNode The point to split. Its container will be
* the right node, i.e., become the new node's
* next sibling. And the point will be start
* of the right node.
@@ -1035,26 +1173,61 @@ public:
* same type.
* @param aParent The parent of aNodeToKeep
*/
nsresult DoJoinNodes(nsINode* aNodeToKeep,
nsINode* aNodeToJoin,
nsINode* aParent);
/**
- * Return the offset of aChild in aParent. Asserts fatally if parent or
- * child is null, or parent is not child's parent.
- * FYI: aChild must not be being removed from aParent. In such case, these
- * methods may return wrong index if aChild doesn't have previous
- * sibling or next sibling.
+ * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
+ *
+ * @param aMostAncestorToSplit The most ancestor node which should be
+ * split.
+ * @param aStartOfDeepestRightNode The start point of deepest right node.
+ * This point must be descendant of
+ * aMostAncestorToSplit.
+ * @param aSplitAtEdges Whether the caller allows this to
+ * create empty container element when
+ * split point is start or end of an
+ * element.
+ * @return SplitPoint() returns split point in
+ * aMostAncestorToSplit. The point must
+ * be good to insert something if the
+ * caller want to do it.
*/
- static int32_t GetChildOffset(nsIDOMNode* aChild,
- nsIDOMNode* aParent);
- static int32_t GetChildOffset(nsINode* aChild,
- nsINode* aParent);
+ template<typename PT, typename CT>
+ SplitNodeResult
+ SplitNodeDeepWithTransaction(
+ nsIContent& aMostAncestorToSplit,
+ const EditorDOMPointBase<PT, CT>& aDeepestStartOfRightNode,
+ SplitAtEdges aSplitAtEdges);
+
+ /**
+ * JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
+ * First, they are joined simply, then, new right node is assumed as the
+ * child at length of the left node before joined and new left node is
+ * assumed as its previous sibling. Then, they will be joined again.
+ * And then, these steps are repeated.
+ *
+ * @param aLeftNode The node which will be removed form the tree.
+ * @param aRightNode The node which will be inserted the contents of
+ * aLeftNode.
+ * @return The point of the first child of the last right node.
+ */
+ EditorDOMPoint JoinNodesDeepWithTransaction(nsIContent& aLeftNode,
+ nsIContent& aRightNode);
+
+ /**
+ * Note that aSelection is optional and can be nullptr.
+ */
+ nsresult DoTransaction(Selection* aSelection,
+ nsITransaction* aTxn);
+
+ virtual bool IsBlockNode(nsINode* aNode);
/**
* Set outOffset to the offset of aChild in the parent.
* Returns the parent of aChild.
*/
static nsINode* GetNodeLocation(nsINode* aChild, int32_t* aOffset);
/**
@@ -1278,24 +1451,16 @@ public:
if (!aNode.IsContent() || IsMozEditorBogusNode(&aNode)) {
return false;
}
return aNode.NodeType() == nsINode::ELEMENT_NODE ||
aNode.NodeType() == nsINode::TEXT_NODE;
}
/**
- * Returns true if selection is in an editable element and both the range
- * start and the range end are editable. E.g., even if the selection range
- * includes non-editable elements, returns true when one of common ancestors
- * of the range start and the range end is editable. Otherwise, false.
- */
- bool IsSelectionEditable();
-
- /**
* Returns true if aNode is a MozEditorBogus node.
*/
bool IsMozEditorBogusNode(const nsINode* aNode) const
{
return aNode && aNode->IsElement() &&
aNode->AsElement()->AttrValueIs(kNameSpaceID_None,
kMOZEditorBogusNodeAttrAtom, kMOZEditorBogusNodeValue,
eCaseMatters);
@@ -1307,112 +1472,21 @@ public:
uint32_t CountEditableChildren(nsINode* aNode);
/**
* Find the deep first and last children.
*/
nsINode* GetFirstEditableNode(nsINode* aRoot);
/**
- * Returns current composition.
- */
- TextComposition* GetComposition() const;
-
- /**
- * Returns true if there is composition string and not fixed.
- */
- bool IsIMEComposing() const;
-
- /**
* Returns true when inserting text should be a part of current composition.
*/
bool ShouldHandleIMEComposition() const;
/**
- * Returns number of undo or redo items.
- */
- size_t NumberOfUndoItems() const
- {
- return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
- }
- size_t NumberOfRedoItems() const
- {
- return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
- }
-
- /**
- * Returns true if this editor can store transactions for undo/redo.
- */
- bool IsUndoRedoEnabled() const
- {
- return !!mTransactionManager;
- }
-
- /**
- * Return true if it's possible to undo/redo right now.
- */
- bool CanUndo() const
- {
- return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
- }
- bool CanRedo() const
- {
- return IsUndoRedoEnabled() && NumberOfRedoItems() > 0;
- }
-
- /**
- * Enables or disables undo/redo feature. Returns true if it succeeded,
- * otherwise, e.g., we're undoing or redoing, returns false.
- */
- bool EnableUndoRedo(int32_t aMaxTransactionCount = -1)
- {
- if (!mTransactionManager) {
- mTransactionManager = new TransactionManager();
- }
- return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
- }
- bool DisableUndoRedo()
- {
- if (!mTransactionManager) {
- return true;
- }
- // XXX Even we clear the transaction manager, IsUndoRedoEnabled() keep
- // returning true...
- return mTransactionManager->DisableUndoRedo();
- }
- bool ClearUndoRedo()
- {
- if (!mTransactionManager) {
- return true;
- }
- return mTransactionManager->ClearUndoRedo();
- }
-
- /**
- * Adds or removes transaction listener to or from the transaction manager.
- * Note that TransactionManager does not check if the listener is in the
- * array. So, caller of AddTransactionListener() needs to manage if it's
- * already been registered to the transaction manager.
- */
- bool AddTransactionListener(nsITransactionListener& aListener)
- {
- if (!mTransactionManager) {
- return false;
- }
- return mTransactionManager->AddTransactionListener(aListener);
- }
- bool RemoveTransactionListener(nsITransactionListener& aListener)
- {
- if (!mTransactionManager) {
- return false;
- }
- return mTransactionManager->RemoveTransactionListener(aListener);
- }
-
- /**
* From html rules code - migration in progress.
*/
static nsAtom* GetTag(nsIDOMNode* aNode);
virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2);
static bool IsTextNode(nsIDOMNode* aNode);
static bool IsTextNode(nsINode* aNode)
@@ -1433,366 +1507,62 @@ public:
static nsIContent* GetNodeAtRangeOffsetPoint(const RawRangeBoundary& aPoint);
static EditorRawDOMPoint GetStartPoint(Selection* aSelection);
static EditorRawDOMPoint GetEndPoint(Selection* aSelection);
static nsresult GetEndChildNode(Selection* aSelection,
nsIContent** aEndNode);
- Selection* GetSelection(SelectionType aSelectionType =
- SelectionType::eNormal)
- {
- nsISelectionController* sc = GetSelectionController();
- if (!sc) {
- return nullptr;
- }
- Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
- return selection;
- }
-
/**
* CollapseSelectionToEnd() collapses the selection to the end of the editor.
*/
nsresult CollapseSelectionToEnd(Selection* aSelection);
/**
* Helpers to add a node to the selection.
* Used by table cell selection methods.
*/
nsresult CreateRange(nsINode* aStartContainer, int32_t aStartOffset,
nsINode* aEndContainer, int32_t aEndOffset,
nsRange** aRange);
- /**
- * Creates a range with just the supplied node and appends that to the
- * selection.
- */
- nsresult AppendNodeToSelectionAsRange(nsINode* aNode);
-
- /**
- * When you are using AppendNodeToSelectionAsRange(), call this first to
- * start a new selection.
- */
- nsresult ClearSelection();
-
static bool IsPreformatted(nsINode* aNode);
- /**
- * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
- *
- * @param aMostAncestorToSplit The most ancestor node which should be
- * split.
- * @param aStartOfDeepestRightNode The start point of deepest right node.
- * This point must be descendant of
- * aMostAncestorToSplit.
- * @param aSplitAtEdges Whether the caller allows this to
- * create empty container element when
- * split point is start or end of an
- * element.
- * @return SplitPoint() returns split point in
- * aMostAncestorToSplit. The point must
- * be good to insert something if the
- * caller want to do it.
- */
- template<typename PT, typename CT>
- SplitNodeResult
- SplitNodeDeepWithTransaction(
- nsIContent& aMostAncestorToSplit,
- const EditorDOMPointBase<PT, CT>& aDeepestStartOfRightNode,
- SplitAtEdges aSplitAtEdges);
-
- /**
- * JoinNodesDeepWithTransaction() joins aLeftNode and aRightNode "deeply".
- * First, they are joined simply, then, new right node is assumed as the
- * child at length of the left node before joined and new left node is
- * assumed as its previous sibling. Then, they will be joined again.
- * And then, these steps are repeated.
- *
- * @param aLeftNode The node which will be removed form the tree.
- * @param aRightNode The node which will be inserted the contents of
- * aLeftNode.
- * @return The point of the first child of the last right node.
- */
- EditorDOMPoint JoinNodesDeepWithTransaction(nsIContent& aLeftNode,
- nsIContent& aRightNode);
-
- nsresult GetString(const nsAString& name, nsAString& value);
-
- void BeginUpdateViewBatch();
- virtual nsresult EndUpdateViewBatch();
-
bool GetShouldTxnSetSelection();
- virtual nsresult HandleKeyPressEvent(WidgetKeyboardEvent* aKeyboardEvent);
-
nsresult HandleInlineSpellCheck(EditAction action,
Selection& aSelection,
nsINode* previousSelectedNode,
uint32_t previousSelectedOffset,
nsINode* aStartContainer,
uint32_t aStartOffset,
nsINode* aEndContainer,
uint32_t aEndOffset);
- virtual dom::EventTarget* GetDOMEventTarget() = 0;
-
- /**
- * Fast non-refcounting editor root element accessor
- */
- Element* GetRoot() const { return mRootElement; }
-
/**
* Likewise, but gets the editor's root instead, which is different for HTML
* editors.
*/
virtual Element* GetEditorRoot();
/**
* Likewise, but gets the text control element instead of the root for
* plaintext editors.
*/
Element* GetExposedRoot();
/**
- * Accessor methods to flags.
- */
- uint32_t Flags() const { return mFlags; }
-
- nsresult AddFlags(uint32_t aFlags)
- {
- const uint32_t kOldFlags = Flags();
- const uint32_t kNewFlags = (kOldFlags | aFlags);
- if (kNewFlags == kOldFlags) {
- return NS_OK;
- }
- return SetFlags(kNewFlags); // virtual call and may be expensive.
- }
- nsresult RemoveFlags(uint32_t aFlags)
- {
- const uint32_t kOldFlags = Flags();
- const uint32_t kNewFlags = (kOldFlags & ~aFlags);
- if (kNewFlags == kOldFlags) {
- return NS_OK;
- }
- return SetFlags(kNewFlags); // virtual call and may be expensive.
- }
- nsresult AddAndRemoveFlags(uint32_t aAddingFlags, uint32_t aRemovingFlags)
- {
- MOZ_ASSERT(!(aAddingFlags & aRemovingFlags),
- "Same flags are specified both adding and removing");
- const uint32_t kOldFlags = Flags();
- const uint32_t kNewFlags = ((kOldFlags | aAddingFlags) & ~aRemovingFlags);
- if (kNewFlags == kOldFlags) {
- return NS_OK;
- }
- return SetFlags(kNewFlags); // virtual call and may be expensive.
- }
-
- bool IsPlaintextEditor() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
- }
-
- bool IsSingleLineEditor() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) != 0;
- }
-
- bool IsPasswordEditor() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorPasswordMask) != 0;
- }
-
- // FYI: Both IsRightToLeft() and IsLeftToRight() may return false if
- // the editor inherits the content node's direction.
- bool IsRightToLeft() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorRightToLeft) != 0;
- }
- bool IsLeftToRight() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorLeftToRight) != 0;
- }
-
- bool IsReadonly() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorReadonlyMask) != 0;
- }
-
- bool IsDisabled() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorDisabledMask) != 0;
- }
-
- bool IsInputFiltered() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0;
- }
-
- bool IsMailEditor() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0;
- }
-
- bool IsWrapHackEnabled() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0;
- }
-
- bool IsFormWidget() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0;
- }
-
- bool NoCSS() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorNoCSSMask) != 0;
- }
-
- bool IsInteractionAllowed() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0;
- }
-
- bool DontEchoPassword() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
- }
-
- bool ShouldSkipSpellCheck() const
- {
- return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0;
- }
-
- bool IsTabbable() const
- {
- return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() ||
- IsInteractionAllowed();
- }
-
- bool HasIndependentSelection() const
- {
- return !!mSelectionController;
- }
-
- bool IsModifiable() const
- {
- return !IsReadonly();
- }
-
- /**
- * IsInEditAction() return true while the instance is handling an edit action.
- * Otherwise, false.
- */
- bool IsInEditAction() const { return mIsInEditAction; }
-
- /**
- * SuppressDispatchingInputEvent() suppresses or unsuppresses dispatching
- * "input" event.
- */
- void SuppressDispatchingInputEvent(bool aSuppress)
- {
- mDispatchInputEvent = !aSuppress;
- }
-
- /**
- * IsSuppressingDispatchingInputEvent() returns true if the editor stops
- * dispatching input event. Otherwise, false.
- */
- bool IsSuppressingDispatchingInputEvent() const
- {
- return !mDispatchInputEvent;
- }
-
- bool Destroyed() const
- {
- return mDidPreDestroy;
- }
-
- /**
- * Returns true if markNodeDirty() has any effect. Returns false if
- * markNodeDirty() is a no-op.
- */
- bool OutputsMozDirty() const
- {
- // Return true for Composer (!IsInteractionAllowed()) or mail
- // (IsMailEditor()), but false for webpages.
- return !IsInteractionAllowed() || IsMailEditor();
- }
-
- /**
- * Get the input event target. This might return null.
- */
- virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0;
-
- /**
- * Get the focused content, if we're focused. Returns null otherwise.
- */
- virtual nsIContent* GetFocusedContent();
-
- /**
- * Get the focused content for the argument of some IMEStateManager's
- * methods.
- */
- virtual already_AddRefed<nsIContent> GetFocusedContentForIME();
-
- /**
* Whether the editor is active on the DOM window. Note that when this
* returns true but GetFocusedContent() returns null, it means that this editor was
* focused when the DOM window was active.
*/
virtual bool IsActiveInDOMWindow();
/**
- * Whether the aGUIEvent should be handled by this editor or not. When this
- * returns false, The aGUIEvent shouldn't be handled on this editor,
- * i.e., The aGUIEvent should be handled by another inner editor or ancestor
- * elements.
- */
- virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent);
-
- /**
- * FindSelectionRoot() returns a selection root of this editor when aNode
- * gets focus. aNode must be a content node or a document node. When the
- * target isn't a part of this editor, returns nullptr. If this is for
- * designMode, you should set the document node to aNode except that an
- * element in the document has focus.
- */
- virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode);
-
- /**
- * Initializes selection and caret for the editor. If aEventTarget isn't
- * a host of the editor, i.e., the editor doesn't get focus, this does
- * nothing.
- */
- nsresult InitializeSelection(dom::EventTarget* aFocusEventTarget);
-
- /**
- * This method has to be called by EditorEventListener::Focus.
- * All actions that have to be done when the editor is focused needs to be
- * added here.
- */
- void OnFocus(dom::EventTarget* aFocusEventTarget);
-
- /**
- * Used to insert content from a data transfer into the editable area.
- * This is called for each item in the data transfer, with the index of
- * each item passed as aIndex.
- */
- virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer,
- int32_t aIndex,
- nsIDocument* aSourceDoc,
- nsINode* aDestinationNode,
- int32_t aDestOffset,
- bool aDoDeleteSelection) = 0;
-
- virtual nsresult InsertFromDrop(dom::DragEvent* aDropEvent) = 0;
-
- /**
* GetIMESelectionStartOffsetIn() returns the start offset of IME selection in
* the aTextNode. If there is no IME selection, returns -1.
*/
int32_t GetIMESelectionStartOffsetIn(nsINode* aTextNode);
/**
* FindBetterInsertionPoint() tries to look for better insertion point which
* is typically the nearest text node and offset in it.
@@ -1805,21 +1575,248 @@ public:
/**
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
* with nsCaret::RemoveForceHide(). This does NOT set visibility of
* nsCaret. Therefore, this is stateless.
*/
void HideCaret(bool aHide);
- /** Resyncs spellchecking state (enabled/disabled). This should be called
- * when anything that affects spellchecking state changes, such as the
- * spellcheck attribute value.
- */
- void SyncRealTimeSpell();
+protected: // Called by helper classes.
+ /**
+ * All editor operations which alter the doc should be prefaced
+ * with a call to StartOperation, naming the action and direction.
+ */
+ virtual nsresult StartOperation(EditAction opID,
+ nsIEditor::EDirection aDirection);
+
+ /**
+ * All editor operations which alter the doc should be followed
+ * with a call to EndOperation.
+ */
+ virtual nsresult EndOperation();
+
+ /**
+ * Routines for managing the preservation of selection across
+ * various editor actions.
+ */
+ bool ArePreservingSelection();
+ void PreserveSelectionAcrossActions(Selection* aSel);
+ nsresult RestorePreservedSelection(Selection* aSel);
+ void StopPreservingSelection();
+
+ /**
+ * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
+ * This set of methods are similar to the (Begin|End)Transaction(), but do
+ * not use the transaction managers batching feature. Instead we use a
+ * placeholder transaction to wrap up any further transaction while the
+ * batch is open. The advantage of this is that placeholder transactions
+ * can later merge, if needed. Merging is unavailable between transaction
+ * manager batches.
+ */
+ void BeginPlaceholderTransaction(nsAtom* aTransactionName);
+ void EndPlaceholderTransaction();
+
+ void BeginUpdateViewBatch();
+ virtual nsresult EndUpdateViewBatch();
+
+protected: // Shouldn't be used by friend classes
+ /**
+ * The default destructor. This should suffice. Should this be pure virtual
+ * for someone to derive from the EditorBase later? I don't believe so.
+ */
+ virtual ~EditorBase();
+
+ nsresult DetermineCurrentDirection();
+ void FireInputEvent();
+
+ /**
+ * Called after a transaction is done successfully.
+ */
+ void DoAfterDoTransaction(nsITransaction *aTxn);
+
+ /**
+ * Called after a transaction is undone successfully.
+ */
+
+ void DoAfterUndoTransaction();
+
+ /**
+ * Called after a transaction is redone successfully.
+ */
+ void DoAfterRedoTransaction();
+
+ /**
+ * Tell the doc state listeners that the doc state has changed.
+ */
+ enum TDocumentListenerNotification
+ {
+ eDocumentCreated,
+ eDocumentToBeDestroyed,
+ eDocumentStateChanged
+ };
+ nsresult NotifyDocumentListeners(
+ TDocumentListenerNotification aNotificationType);
+
+ /**
+ * Make the given selection span the entire document.
+ */
+ virtual nsresult SelectEntireDocument(Selection* aSelection);
+
+ /**
+ * Helper method for scrolling the selection into view after
+ * an edit operation. aScrollToAnchor should be true if you
+ * want to scroll to the point where the selection was started.
+ * If false, it attempts to scroll the end of the selection into view.
+ *
+ * Editor methods *should* call this method instead of the versions
+ * in the various selection interfaces, since this version makes sure
+ * that the editor's sync/async settings for reflowing, painting, and
+ * scrolling match.
+ */
+ nsresult ScrollSelectionIntoView(bool aScrollToAnchor);
+
+ /**
+ * Helper for GetPreviousNodeInternal() and GetNextNodeInternal().
+ */
+ nsIContent* FindNextLeafNode(nsINode* aCurrentNode,
+ bool aGoForward,
+ bool bNoBlockCrossing);
+ nsIContent* FindNode(nsINode* aCurrentNode,
+ bool aGoForward,
+ bool aEditableNode,
+ bool aFindAnyDataNode,
+ bool bNoBlockCrossing);
+
+ /**
+ * Get the node immediately previous node of aNode.
+ * @param atNode The node from which we start the search.
+ * @param aFindEditableNode If true, only return an editable node.
+ * @param aFindAnyDataNode If true, may return invisible data node
+ * like Comment.
+ * @param aNoBlockCrossing If true, don't move across "block" nodes,
+ * whatever that means.
+ * @return The node that occurs before aNode in
+ * the tree, skipping non-editable nodes if
+ * aFindEditableNode is true. If there is no
+ * previous node, returns nullptr.
+ */
+ nsIContent* GetPreviousNodeInternal(nsINode& aNode,
+ bool aFindEditableNode,
+ bool aFindAnyDataNode,
+ bool aNoBlockCrossing);
+
+ /**
+ * And another version that takes a point in DOM tree rather than a node.
+ */
+ nsIContent* GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
+ bool aFindEditableNode,
+ bool aFindAnyDataNode,
+ bool aNoBlockCrossing);
+
+ /**
+ * Get the node immediately next node of aNode.
+ * @param aNode The node from which we start the search.
+ * @param aFindEditableNode If true, only return an editable node.
+ * @param aFindAnyDataNode If true, may return invisible data node
+ * like Comment.
+ * @param aNoBlockCrossing If true, don't move across "block" nodes,
+ * whatever that means.
+ * @return The node that occurs after aNode in the
+ * tree, skipping non-editable nodes if
+ * aFindEditableNode is true. If there is no
+ * next node, returns nullptr.
+ */
+ nsIContent* GetNextNodeInternal(nsINode& aNode,
+ bool aFindEditableNode,
+ bool aFindAnyDataNode,
+ bool bNoBlockCrossing);
+
+ /**
+ * And another version that takes a point in DOM tree rather than a node.
+ */
+ nsIContent* GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
+ bool aFindEditableNode,
+ bool aFindAnyDataNode,
+ bool aNoBlockCrossing);
+
+
+ virtual nsresult InstallEventListeners();
+ virtual void CreateEventListeners();
+ virtual void RemoveEventListeners();
+
+ /**
+ * Return true if spellchecking should be enabled for this editor.
+ */
+ bool GetDesiredSpellCheckState();
+
+ bool CanEnableSpellCheck()
+ {
+ // Check for password/readonly/disabled, which are not spellchecked
+ // regardless of DOM. Also, check to see if spell check should be skipped
+ // or not.
+ return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() &&
+ !ShouldSkipSpellCheck();
+ }
+
+ /**
+ * InitializeSelectionAncestorLimit() is called by InitializeSelection().
+ * When this is called, each implementation has to call
+ * aSelection.SetAncestorLimiter() with aAnotherLimit.
+ *
+ * @param aSelection The selection.
+ * @param aAncestorLimit New ancestor limit of aSelection. This always
+ * has parent node. So, it's always safe to
+ * call SetAncestorLimit() with this node.
+ */
+ virtual void InitializeSelectionAncestorLimit(Selection& aSelection,
+ nsIContent& aAncestorLimit);
+
+ /**
+ * Return the offset of aChild in aParent. Asserts fatally if parent or
+ * child is null, or parent is not child's parent.
+ * FYI: aChild must not be being removed from aParent. In such case, these
+ * methods may return wrong index if aChild doesn't have previous
+ * sibling or next sibling.
+ */
+ static int32_t GetChildOffset(nsIDOMNode* aChild,
+ nsIDOMNode* aParent);
+ static int32_t GetChildOffset(nsINode* aChild,
+ nsINode* aParent);
+
+ /**
+ * Creates a range with just the supplied node and appends that to the
+ * selection.
+ */
+ nsresult AppendNodeToSelectionAsRange(nsINode* aNode);
+
+ /**
+ * When you are using AppendNodeToSelectionAsRange(), call this first to
+ * start a new selection.
+ */
+ nsresult ClearSelection();
+
+ /**
+ * Initializes selection and caret for the editor. If aEventTarget isn't
+ * a host of the editor, i.e., the editor doesn't get focus, this does
+ * nothing.
+ */
+ nsresult InitializeSelection(dom::EventTarget* aFocusEventTarget);
+
+ /**
+ * Used to insert content from a data transfer into the editable area.
+ * This is called for each item in the data transfer, with the index of
+ * each item passed as aIndex.
+ */
+ virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer,
+ int32_t aIndex,
+ nsIDocument* aSourceDoc,
+ nsINode* aDestinationNode,
+ int32_t aDestOffset,
+ bool aDoDeleteSelection) = 0;
private:
nsCOMPtr<nsISelectionController> mSelectionController;
nsCOMPtr<nsIDocument> mDocument;
protected:
enum Tristate
{
@@ -1905,22 +1902,34 @@ protected:
bool mIsInEditAction;
// Whether caret is hidden forcibly.
bool mHidingCaret;
// Whether spellchecker dictionary is initialized after focused.
bool mSpellCheckerDictionaryUpdated;
// Whether we are an HTML editor class.
bool mIsHTMLEditorClass;
- friend bool NSCanUnload(nsISupports* serviceMgr);
friend class AutoPlaceholderBatch;
friend class AutoRules;
friend class AutoSelectionRestorer;
friend class AutoTransactionsConserveSelection;
- friend class RangeUpdater;
+ friend class AutoUpdateViewBatch;
+ friend class CompositionTransaction;
+ friend class CreateElementTransaction;
+ friend class CSSEditUtils;
+ friend class DeleteTextTransaction;
+ friend class HTMLEditRules;
+ friend class HTMLEditUtils;
+ friend class InsertNodeTransaction;
+ friend class InsertTextTransaction;
+ friend class JoinNodeTransaction;
+ friend class SplitNodeTransaction;
+ friend class TextEditRules;
+ friend class TypeInState;
+ friend class WSRunObject;
friend class nsIEditor;
};
} // namespace mozilla
mozilla::EditorBase*
nsIEditor::AsEditorBase()
{