Bug 390767. Support editable state and interface for contentEditable and designMode documents and their content. r=ginn.chen, a=dsicore
authoraaronleventhal@moonset.net
Tue, 14 Aug 2007 09:25:24 -0700
changeset 4625 bd426f31a48ec7de9e71b7e1502863fb42ab350d
parent 4624 175dd750af539d18c40fb01a5969cbb267f49b91
child 4626 66abcfbfbfd08f86cbeacbee4077c3e73a616f45
push idunknown
push userunknown
push dateunknown
reviewersginn.chen, dsicore
bugs390767
milestone1.9a8pre
Bug 390767. Support editable state and interface for contentEditable and designMode documents and their content. r=ginn.chen, a=dsicore
accessible/src/base/nsAccessibilityAtomList.h
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsDocAccessible.h
accessible/src/html/Makefile.in
accessible/src/html/nsHTMLFormControlAccessible.cpp
accessible/src/html/nsHTMLFormControlAccessible.h
accessible/src/html/nsHyperTextAccessible.cpp
accessible/src/html/nsHyperTextAccessible.h
accessible/src/xforms/nsXFormsAccessible.cpp
accessible/src/xforms/nsXFormsAccessible.h
accessible/src/xul/nsXULFormControlAccessible.cpp
accessible/src/xul/nsXULFormControlAccessible.h
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -148,16 +148,17 @@ ACCESSIBILITY_ATOM(labelledby, "labelled
 ACCESSIBILITY_ATOM(owns, "owns")
 
   // Alphabetical list of attributes
 ACCESSIBILITY_ATOM(acceltext, "acceltext")
 ACCESSIBILITY_ATOM(accesskey, "accesskey")
 ACCESSIBILITY_ATOM(alt, "alt")
 ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
 ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too
+ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
 ACCESSIBILITY_ATOM(control, "control")
 ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
 ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
 ACCESSIBILITY_ATOM(data, "data")
 ACCESSIBILITY_ATOM(disabled, "disabled")
 ACCESSIBILITY_ATOM(droppable, "droppable")   // XUL combo box
 ACCESSIBILITY_ATOM(editable, "editable")
 ACCESSIBILITY_ATOM(_for, "for")
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -238,17 +238,18 @@ nsDocAccessible::GetState(PRUint32 *aSta
   }
  
   if (frame != nsnull) {
     if (!CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
       *aState |= nsIAccessibleStates::STATE_INVISIBLE;
     }
   }
 
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (!editor) {
     *aState |= nsIAccessibleStates::STATE_READONLY;
   }
   else if (aExtraState) {
     *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
   }
 
   return NS_OK;
@@ -392,47 +393,43 @@ NS_IMETHODIMP nsDocAccessible::GetDocume
   if (domDoc) {
     NS_ADDREF(*aDOMDoc);
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
-void nsDocAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
+  NS_ENSURE_ARG_POINTER(aEditor);
 
-void nsDocAccessible::CheckForEditor()
-{
-  if (mEditor) {
-    return;  // Already have editor, don't need to check
-  }
-  if (!mDocument) {
-    return;  // No document -- we've been shut down
+  *aEditor = nsnull;
+  NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
+
+  if (!mDocument->HasFlag(NODE_IS_EDITABLE)) {
+    return NS_OK; // Document not editable
   }
 
   nsCOMPtr<nsISupports> container = mDocument->GetContainer();
   nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
   if (!editingSession)
-    return; // No editing session interface
+    return NS_OK; // No editing session interface
 
   nsCOMPtr<nsIEditor> editor;
-  editingSession->GetEditorForWindow(mDocument->GetWindow(),
-                                     getter_AddRefs(editor));
-  SetEditor(editor);
-  if (!editor)
-    return;
-
-  // State editable is now set, readonly is now clear
-  nsCOMPtr<nsIAccessibleStateChangeEvent> event =
-    new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
-                              PR_TRUE, PR_TRUE);
-  FireAccessibleEvent(event);
+  editingSession->GetEditorForWindow(mDocument->GetWindow(), getter_AddRefs(editor));
+  if (!editor) {
+    return NS_OK;
+  }
+  PRBool isEditable;
+  editor->GetIsDocumentEditable(&isEditable);
+  if (isEditable) {
+    NS_ADDREF(*aEditor = editor);
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::GetCachedAccessNode(void *aUniqueID, nsIAccessNode **aAccessNode)
 {
   GetCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode); // Addrefs for us
 #ifdef DEBUG_A11Y
   // All cached accessible nodes should be in the parent
   // It will assert if not all the children were created
@@ -526,18 +523,16 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
 {
   if (!mWeakShell) {
     return NS_OK;  // Already shutdown
   }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShellTreeItemFor(mDOMNode);
   ShutdownChildDocuments(treeItem);
 
-  mEditor = nsnull;
-
   if (mDocLoadTimer) {
     mDocLoadTimer->Cancel();
     mDocLoadTimer = nsnull;
   }
 
   RemoveEventListeners();
 
   mWeakShell = nsnull;  // Avoid reentrancy
@@ -648,24 +643,20 @@ nsresult nsDocAccessible::AddEventListen
   // Make sure we're a content docshell
   // We don't want to listen to chrome progress
   PRInt32 itemType;
   docShellTreeItem->GetItemType(&itemType);
 
   PRBool isContent = (itemType == nsIDocShellTreeItem::typeContent);
 
   if (isContent) {
-    CheckForEditor();
-
-    if (!mEditor) {
-      // We're not an editor yet, but we might become one
-      nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
-      if (commandManager) {
-        commandManager->AddCommandObserver(this, "obs_documentCreated");
-      }
+    // We're not an editor yet, but we might become one
+    nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
+    if (commandManager) {
+      commandManager->AddCommandObserver(this, "obs_documentCreated");
     }
   }
 
   nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
   if (rootTreeItem) {
     GetDocAccessibleFor(rootTreeItem, PR_TRUE); // Ensure root accessible is created;
     nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
@@ -893,19 +884,22 @@ NS_IMETHODIMP nsDocAccessible::ScrollPos
   }
   mScrollPositionChangedTicks = 1;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic,
                                        const PRUnichar *aData)
 {
-  if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {
-    CheckForEditor();
-    NS_ASSERTION(mEditor, "Should have editor if we see obs_documentCreated");
+  if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {    
+    // State editable will now be set, readonly is now clear
+    nsCOMPtr<nsIAccessibleStateChangeEvent> event =
+      new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
+                                PR_TRUE, PR_TRUE);
+    FireAccessibleEvent(event);
   }
 
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////
 // nsIDocumentObserver
 
@@ -1025,16 +1019,25 @@ nsDocAccessible::AttributeChanged(nsIDoc
                                 targetNode, nsnull);
         return;
       }
 
       FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
                                                   targetNode, nsnull);
     }
   }
+
+  if (aAttribute == nsAccessibilityAtoms::contenteditable) {
+    nsCOMPtr<nsIAccessibleStateChangeEvent> editableChangeEvent =
+      new nsAccStateChangeEvent(targetNode,
+                                nsIAccessibleStates::EXT_STATE_EDITABLE,
+                                PR_TRUE);
+    FireDelayedAccessibleEvent(editableChangeEvent);
+    return;
+  }
 }
 
 void
 nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
 {
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
   if (!targetNode)
     return;
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -94,16 +94,19 @@ class nsDocAccessible : public nsHyperTe
 
     // nsIAccessNode
     NS_IMETHOD Shutdown();
     NS_IMETHOD Init();
 
     // nsPIAccessNode
     NS_IMETHOD_(nsIFrame *) GetFrame(void);
 
+    // nsIAccessibleText
+    NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
     /**
       * Non-virtual method to fire a delayed event after a 0 length timeout
       *
       * @param aEvent - the nsIAccessibleEvent event ype
       * @param aDOMNode - DOM node the accesible event should be fired for
       * @param aData - any additional data for the event
       * @param aAllowDupes - set to PR_TRUE if more than one event of the same
       *                      type is allowed. By default this is false and events
@@ -134,19 +137,16 @@ class nsDocAccessible : public nsHyperTe
   protected:
     virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
     virtual nsresult AddEventListeners();
     virtual nsresult RemoveEventListeners();
     void AddScrollListener();
     void RemoveScrollListener();
     void RefreshNodes(nsIDOMNode *aStartNode);
     static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
-    void CheckForEditor();
-    virtual void SetEditor(nsIEditor *aEditor);
-    virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
 
     /**
      * Fires accessible events when ARIA attribute is chaned.
      *
      * @param aContent - node that attribute is changed for
      * @param aAttribute - changed attribute
      */
     void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
@@ -175,17 +175,16 @@ class nsDocAccessible : public nsHyperTe
     nsAccessNodeHashtable mAccessNodeCache;
     void *mWnd;
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITimer> mScrollWatchTimer;
     nsCOMPtr<nsITimer> mFireEventTimer;
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
-    nsCOMPtr<nsIEditor> mEditor;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
 
 private:
     static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
     nsCOMPtr<nsITimer> mDocLoadTimer;
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -42,17 +42,18 @@ srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
 LIBRARY_NAME = accessibility_html_s
 LIBXUL_LIBRARY = 1
 
-REQUIRES	= content \
+REQUIRES	= composer \
+		  content \
 		  docshell \
 		  dom \
 		  editor \
 		  gfx \
 		  imglib2 \
 		  intl \
 		  js \
 		  layout \
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -43,16 +43,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMNSHTMLButtonElement.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
+#include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsISelectionController.h"
 #include "jsapi.h"
 #include "nsIJSContextStack.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlFrame.h"
 
@@ -367,31 +368,16 @@ nsHTML4ButtonAccessible::GetState(PRUint
 
 // --- textfield -----
 
 nsHTMLTextFieldAccessible::nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
 nsHyperTextAccessibleWrap(aNode, aShell)
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLTextFieldAccessible, nsHyperTextAccessibleWrap,
-                             nsIAccessibleText)
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Init()
-{
-  CheckForEditor();
-  return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Shutdown()
-{
-  mEditor = nsnull;
-  return nsHyperTextAccessibleWrap::Shutdown();
-}
-
 NS_IMETHODIMP nsHTMLTextFieldAccessible::GetRole(PRUint32 *aRole)
 {
   *aRole = nsIAccessibleRole::ROLE_ENTRY;
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
   if (content &&
       content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
                            nsAccessibilityAtoms::password, eIgnoreCase)) {
     *aRole = nsIAccessibleRole::ROLE_PASSWORD_TEXT;
@@ -537,46 +523,39 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible:
     if ( element ) {
       return element->Focus();
     }
     return NS_ERROR_FAILURE;
   }
   return NS_ERROR_INVALID_ARG;
 }
 
-void nsHTMLTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
-
-void nsHTMLTextFieldAccessible::CheckForEditor()
-{
+  *aEditor = nsnull;
   nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mDOMNode));
-  if (!editableElt) {
-    return;
-  }
+  NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
 
   // nsGenericHTMLElement::GetEditor has a security check.
   // Make sure we're not restricted by the permissions of
   // whatever script is currently running.
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
 
   nsCOMPtr<nsIEditor> editor;
-  nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
-  if (NS_SUCCEEDED(rv)) {
-    SetEditor(editor);
-  }
+  nsresult rv = editableElt->GetEditor(aEditor);
 
   if (pushed) {
     JSContext* cx;
     stack->Pop(&cx);
     NS_ASSERTION(!cx, "context should be null");
   }
+
+  return rv;
 }
 
 // --- groupbox  -----
 
 /*
  * The HTML for this is <fieldset> <legend>box-title</legend> form elements </fieldset> 
  */
 
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -97,36 +97,28 @@ public:
 };
 
 class nsHTMLTextFieldAccessible : public nsHyperTextAccessibleWrap
 {
 
 public:
   enum { eAction_Click = 0 };
 
-  NS_DECL_ISUPPORTS_INHERITED
-
   nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
-  NS_IMETHOD Init(); 
-  NS_IMETHOD Shutdown(); 
   NS_IMETHOD GetRole(PRUint32 *_retval); 
   NS_IMETHOD GetName(nsAString& aName); 
   NS_IMETHOD GetValue(nsAString& _retval); 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
 
-protected:
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
-  void CheckForEditor();
-  nsCOMPtr<nsIEditor> mEditor;
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 };
 
 class nsHTMLGroupboxAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
   NS_IMETHOD GetRole(PRUint32 *aRole); 
   NS_IMETHOD GetName(nsAString& aName);
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -42,35 +42,39 @@
 #include "nsAccessibilityService.h"
 #include "nsAccessibleTreeWalker.h"
 #include "nsPIAccessNode.h"
 #include "nsIClipboard.h"
 #include "nsContentCID.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
+#include "nsPIDOMWindow.h"        
 #include "nsIDOMDocumentView.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMXULDocument.h"
+#include "nsIEditingSession.h"
+#include "nsIEditor.h"
 #include "nsIFontMetrics.h"
 #include "nsIFrame.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIServiceManager.h"
 #include "nsTextFragment.h"
 #include "gfxSkipChars.h"
 
 static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
 
 // ------------
 // nsHyperTextAccessible
 // ------------
 
-NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessible)
-NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessible)
+NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
+NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
 
 nsresult nsHyperTextAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
 {
   *aInstancePtr = nsnull;
 
   if (aIID.Equals(NS_GET_IID(nsHyperTextAccessible))) {
     *aInstancePtr = static_cast<nsHyperTextAccessible*>(this);
     NS_ADDREF_THIS();
@@ -164,17 +168,18 @@ NS_IMETHODIMP
 nsHyperTextAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   nsresult rv = nsAccessibleWrap::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!aExtraState)
     return NS_OK;
 
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor) {
     PRUint32 flags;
     editor->GetFlags(&flags);
     if (0 == (flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
     }
   }
 
@@ -190,18 +195,26 @@ nsHyperTextAccessible::GetState(PRUint32
 void nsHyperTextAccessible::CacheChildren()
 {
   if (!mWeakShell) {
     // This node has been shut down
     mAccChildCount = eChildCountUninitialized;
     return;
   }
 
+  // Special case for text entry fields, go directly to editor's root for children
   if (mAccChildCount == eChildCountUninitialized) {
-    nsCOMPtr<nsIEditor> editor = GetEditor();
+    PRUint32 role;
+    GetRole(&role);
+    if (role != nsIAccessibleRole::ROLE_ENTRY && role != nsIAccessibleRole::ROLE_PASSWORD_TEXT) {
+      nsAccessible::CacheChildren();
+      return;
+    }
+    nsCOMPtr<nsIEditor> editor;
+    GetAssociatedEditor(getter_AddRefs(editor));
     if (!editor) {
       nsAccessible::CacheChildren();
       return;
     }
     nsCOMPtr<nsIDOMElement> editorRoot;
     editor->GetRootElement(getter_AddRefs(editorRoot));
     nsCOMPtr<nsIDOMNode> editorRootDOMNode = do_QueryInterface(editorRoot);
     if (!editorRootDOMNode) {
@@ -1147,69 +1160,91 @@ NS_IMETHODIMP nsHyperTextAccessible::Set
     return InsertText(aText, 0);
   }
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
 {
   if (NS_SUCCEEDED(SetCaretOffset(aPosition))) {
-    nsCOMPtr<nsIEditor> editor = GetEditor();
+    nsCOMPtr<nsIEditor> editor;
+    GetAssociatedEditor(getter_AddRefs(editor));
     nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
     return peditor ? peditor->InsertText(aText) : NS_ERROR_FAILURE;
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->Copy();
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->Cut();
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
     return editor->DeleteSelection(nsIEditor::eNone);
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsHyperTextAccessible::PasteText(PRInt32 aPosition)
 {
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor && NS_SUCCEEDED(SetCaretOffset(aPosition)))
     return editor->Paste(nsIClipboard::kGlobalClipboard);
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsHyperTextAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
-  nsCOMPtr<nsIEditor> editor(GetEditor());
-  NS_IF_ADDREF(*aEditor = editor);
+  *aEditor = nsnull;
+  nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
+  NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
+
+  if (!content->HasFlag(NODE_IS_EDITABLE)) {
+    return NS_OK;
+  }
 
-  return NS_OK;
+  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = GetDocShellTreeItemFor(mDOMNode);
+  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
+  if (!editingSession)
+    return NS_OK; // No editing session interface
+
+  nsCOMPtr<nsIPresShell> shell = GetPresShell();
+  NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIDocument> doc = shell->GetDocument();
+  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIEditor> editor;
+  return editingSession->GetEditorForWindow(doc->GetWindow(), aEditor);
 }
 
 /**
   * =================== Caret & Selection ======================
   */
 
 nsresult nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos)
 {
@@ -1271,17 +1306,18 @@ nsresult nsHyperTextAccessible::GetSelec
 {
   if (aSelCon) {
     *aSelCon = nsnull;
   }
   if (aDomSel) {
     *aDomSel = nsnull;
   }
   
-  nsCOMPtr<nsIEditor> editor = GetEditor();
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
   if (editor) {
     if (aSelCon) {
       editor->GetSelectionController(aSelCon);
       NS_ENSURE_TRUE(*aSelCon, NS_ERROR_FAILURE);
     }
 
     if (aDomSel) {
       editor->GetSelection(aDomSel);
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,17 +40,16 @@
 #ifndef _nsHyperTextAccessible_H_
 #define _nsHyperTextAccessible_H_
 
 #include "nsAccessibleWrap.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsIAccessibleEditableText.h"
 #include "nsAccessibleEventData.h"
-#include "nsIEditor.h"
 #include "nsFrameSelection.h"
 #include "nsISelectionController.h"
 
 enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
 
 // This character marks where in the text returned via nsIAccessibleText(),
 // that embedded object characters exist
 const PRUnichar kEmbeddedObjectChar = 0xfffc;
@@ -152,20 +151,16 @@ protected:
     * @param aBoundsRect (optional), return the bounds rectangle for this substring
     * @return the start frame for this substring
     */
   nsIFrame* GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText = nsnull,
                           nsIFrame **aEndFrame = nsnull, nsIntRect *aBoundsRect = nsnull);
 
   nsIntRect GetBoundsForString(nsIFrame *aFrame, PRUint32 aStartRenderedOffset, PRUint32 aEndRenderedOffset);
 
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor) { return; }
-  virtual already_AddRefed<nsIEditor> GetEditor() { return nsnull; }
-
   // Selection helpers
   nsresult GetSelections(nsISelectionController **aSelCon, nsISelection **aDomSel);
   nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXFormsAccessible.h"
 
 #include "nscore.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNodeList.h"
+#include "nsIEditor.h"
 #include "nsIMutableArray.h"
 #include "nsIXFormsUtilityService.h"
 #include "nsIPlaintextEditor.h"
 
 // nsXFormsAccessibleBase
 
 nsIXFormsUtilityService *nsXFormsAccessibleBase::sXFormsService = nsnull;
 
@@ -304,72 +305,50 @@ nsXFormsEditableAccessible::
 NS_IMETHODIMP
 nsXFormsEditableAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
   nsresult rv = nsXFormsAccessible::GetState(aState, aExtraState);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (!aExtraState || !mEditor)
+  if (!aExtraState)
     return NS_OK;
 
   PRBool isReadonly = PR_FALSE;
   rv = sXFormsService->IsReadonly(mDOMNode, &isReadonly);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!isReadonly) {
     PRBool isRelevant = PR_FALSE;
     rv = sXFormsService->IsRelevant(mDOMNode, &isRelevant);
     NS_ENSURE_SUCCESS(rv, rv);
     if (isRelevant) {
       *aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE |
                       nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT;
     }
   }
 
+  nsCOMPtr<nsIEditor> editor;
+  GetAssociatedEditor(getter_AddRefs(editor));
+  NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE);
   PRUint32 flags;
-  mEditor->GetFlags(&flags);
+  editor->GetFlags(&flags);
   if (flags & nsIPlaintextEditor::eEditorSingleLineMask)
     *aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
   else
     *aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXFormsEditableAccessible::Init()
-{
-  nsCOMPtr<nsIEditor> editor;
-  sXFormsService->GetEditor(mDOMNode, getter_AddRefs(editor));
-  SetEditor(editor);
-
-  return nsXFormsAccessible::Init();
-}
-
-NS_IMETHODIMP
-nsXFormsEditableAccessible::Shutdown()
+nsXFormsEditableAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  SetEditor(nsnull);
-  return nsXFormsAccessible::Shutdown();
-}
-
-already_AddRefed<nsIEditor>
-nsXFormsEditableAccessible::GetEditor()
-{
-  nsIEditor *editor = mEditor;
-  NS_IF_ADDREF(editor);
-  return editor;
-}
-
-void
-nsXFormsEditableAccessible::SetEditor(nsIEditor *aEditor)
-{
-  mEditor = aEditor;
+  return sXFormsService->GetEditor(mDOMNode, aEditor);
 }
 
 // nsXFormsSelectableAccessible
 
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsSelectableAccessible,
                              nsXFormsEditableAccessible,
                              nsIAccessibleSelectable)
--- a/accessible/src/xforms/nsXFormsAccessible.h
+++ b/accessible/src/xforms/nsXFormsAccessible.h
@@ -142,25 +142,18 @@ public:
  */
 class nsXFormsEditableAccessible : public nsXFormsAccessible
 {
 public:
   nsXFormsEditableAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell);
 
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
 
-  NS_IMETHOD Init();
-  NS_IMETHOD Shutdown();
-
-protected:
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor();
-
-private:
-  nsCOMPtr<nsIEditor> mEditor;
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
 };
 
 
 /**
  * The class is base for accessible objects for XForms select and XForms
  * select1 elements.
  */
 class nsXFormsSelectableAccessible : public nsXFormsEditableAccessible
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -45,16 +45,17 @@
 #include "nsXULMenuAccessible.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULTextboxElement.h"
+#include "nsIEditor.h"
 #include "nsIFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsITextControlFrame.h"
 #include "nsIPresShell.h"
 
 /**
   * XUL Button: can contain arbitrary HTML content
   */
@@ -758,31 +759,16 @@ nsXULToolbarSeparatorAccessible::GetStat
   * XUL Textfield
   */
 
 nsXULTextFieldAccessible::nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
  nsHyperTextAccessibleWrap(aNode, aShell)
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsXULTextFieldAccessible, nsHyperTextAccessible,
-                             nsIAccessibleText)
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Init()
-{
-  CheckForEditor();
-  return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Shutdown()
-{
-  mEditor = nsnull;
-  return nsHyperTextAccessibleWrap::Shutdown();
-}
-
 NS_IMETHODIMP nsXULTextFieldAccessible::GetValue(nsAString& aValue)
 {
   PRUint32 state;
   GetState(&state, nsnull);
   if (state & nsIAccessibleStates::STATE_PROTECTED)    // Don't return password text!
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mDOMNode));
@@ -930,27 +916,16 @@ NS_IMETHODIMP nsXULTextFieldAccessible::
 
 NS_IMETHODIMP
 nsXULTextFieldAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
 {
   *aAllowsAnonChildren = PR_FALSE;
   return NS_OK;
 }
 
-void nsXULTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsXULTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
 {
-  mEditor = aEditor;
-}
-
-void nsXULTextFieldAccessible::CheckForEditor()
-{
+  *aEditor = nsnull;
   nsCOMPtr<nsIDOMNode> inputField = GetInputField();
   nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
-  if (!editableElt) {
-    return;
-  }
-
-  nsCOMPtr<nsIEditor> editor;
-  nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
-  if (NS_SUCCEEDED(rv)) {
-    SetEditor(editor);
-  }
+  NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
+  return editableElt->GetEditor(aEditor);
 }
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -156,35 +156,28 @@ public:
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
 };
 
 class nsXULTextFieldAccessible : public nsHyperTextAccessibleWrap
 {
 public:
   enum { eAction_Click = 0 };
 
-  NS_DECL_ISUPPORTS_INHERITED
-
   nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
 
-  NS_IMETHOD Init();
-  NS_IMETHOD Shutdown();
   NS_IMETHOD GetValue(nsAString& aValue);
   NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
   NS_IMETHOD GetRole(PRUint32 *aRole);
   NS_IMETHOD GetNumActions(PRUint8 *_retval);
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 index);
   NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
 
+  // nsIAccessibleEditableText
+  NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
 protected:
   already_AddRefed<nsIDOMNode> GetInputField();
-
-  // Editor helpers, subclasses of nsHyperTextAccessible may have editor
-  virtual void SetEditor(nsIEditor *aEditor);
-  virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
-  void CheckForEditor();
-  nsCOMPtr<nsIEditor> mEditor;
 };
 
 
 #endif