Bug 614800 - coalesce text attribute change events and fire caret move event for the document where event occurred, r=davidb, marcoz, a=davidb
authorAlexander Surkov <surkov.alexander@gmail.com>
Tue, 30 Nov 2010 00:03:29 +0800
changeset 58325 ff0e38477a8db97a3f59cf9fc9e7e8c6e7897fa4
parent 58324 21762517cdea401bd9a1399764a320adc976c6f6
child 58326 6f14ee0618153673f08cc30c9451abd189fa4ba6
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdavidb, marcoz, davidb
bugs614800
milestone2.0b8pre
Bug 614800 - coalesce text attribute change events and fire caret move event for the document where event occurred, r=davidb, marcoz, a=davidb
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccUtils.h
accessible/src/base/nsCaretAccessible.cpp
accessible/src/base/nsCaretAccessible.h
accessible/tests/mochitest/test_text_caret.html
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -400,18 +400,17 @@ PRBool
 nsAccUtils::IsARIASelected(nsAccessible *aAccessible)
 {
   return aAccessible->GetContent()->
     AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected,
                 nsAccessibilityAtoms::_true, eCaseMatters);
 }
 
 already_AddRefed<nsHyperTextAccessible>
-nsAccUtils::GetTextAccessibleFromSelection(nsISelection *aSelection,
-                                           nsINode **aNode)
+nsAccUtils::GetTextAccessibleFromSelection(nsISelection* aSelection)
 {
   // Get accessible from selection's focus DOM point (the DOM point where
   // selection is ended).
 
   nsCOMPtr<nsIDOMNode> focusDOMNode;
   aSelection->GetFocusNode(getter_AddRefs(focusDOMNode));
   if (!focusDOMNode)
     return nsnull;
@@ -430,22 +429,19 @@ nsAccUtils::GetTextAccessibleFromSelecti
   if (!accessible) {
     NS_NOTREACHED("No nsIAccessibleText for selection change event!");
     return nsnull;
   }
 
   do {
     nsHyperTextAccessible* textAcc = nsnull;
     CallQueryInterface(accessible, &textAcc);
-    if (textAcc) {
-      if (aNode)
-        NS_ADDREF(*aNode = accessible->GetNode());
+    if (textAcc)
+      return textAcc;
 
-      return textAcc;
-    }
   } while (accessible = accessible->GetParent());
 
   NS_NOTREACHED("We must reach document accessible implementing nsIAccessibleText!");
   return nsnull;
 }
 
 nsresult
 nsAccUtils::ConvertToScreenCoords(PRInt32 aX, PRInt32 aY,
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -218,22 +218,20 @@ public:
    */
   static PRBool IsARIASelected(nsAccessible *aAccessible);
 
   /**
    * Return text accessible containing focus point of the given selection.
    * Used for normal and misspelling selection changes processing.
    *
    * @param aSelection  [in] the given selection
-   * @param aNode       [out, optional] the DOM node of text accessible
    * @return            text accessible
    */
   static already_AddRefed<nsHyperTextAccessible>
-    GetTextAccessibleFromSelection(nsISelection *aSelection,
-                                   nsINode **aNode = nsnull);
+    GetTextAccessibleFromSelection(nsISelection* aSelection);
 
   /**
    * Converts the given coordinates to coordinates relative screen.
    *
    * @param aX               [in] the given x coord
    * @param aY               [in] the given y coord
    * @param aCoordinateType  [in] specifies coordinates origin (refer to
    *                         nsIAccessibleCoordinateType)
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -196,104 +196,102 @@ nsCaretAccessible::RemoveDocSelectionLis
                        getter_AddRefs(spellcheckSel));
   selPrivate = do_QueryInterface(spellcheckSel);
   NS_ENSURE_TRUE(selPrivate, NS_ERROR_FAILURE);
 
   return selPrivate->RemoveSelectionListener(this);
 }
 
 NS_IMETHODIMP
-nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc,
-                                          nsISelection *aSel,
+nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
+                                          nsISelection* aSelection,
                                           PRInt16 aReason)
 {
-  NS_ENSURE_ARG(aDoc);
+  NS_ENSURE_ARG(aDOMDocument);
+  NS_ENSURE_STATE(mRootAccessible);
 
-  nsCOMPtr<nsIDocument> document(do_QueryInterface(aDoc));
-  nsDocAccessible *docAccessible = GetAccService()->GetDocAccessible(document);
+  nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
+  nsDocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
 
   // Don't fire events until document is loaded.
-  if (!docAccessible || !docAccessible->IsContentLoaded())
+  if (!document || !document->IsContentLoaded())
     return NS_OK;
 
-  nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSel));
+  nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
 
   PRInt16 type = 0;
   sel2->GetType(&type);
 
   if (type == nsISelectionController::SELECTION_NORMAL)
-    return NormalSelectionChanged(aDoc, aSel);
+    NormalSelectionChanged(document, aSelection);
 
-  if (type == nsISelectionController::SELECTION_SPELLCHECK)
-    return SpellcheckSelectionChanged(aDoc, aSel);
+  else if (type == nsISelectionController::SELECTION_SPELLCHECK)
+    SpellcheckSelectionChanged(document, aSelection);
 
   return NS_OK;
 }
 
-nsresult
-nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
-                                          nsISelection *aSel)
+void
+nsCaretAccessible::NormalSelectionChanged(nsDocAccessible* aDocument,
+                                          nsISelection* aSelection)
 {
-  NS_ENSURE_TRUE(mRootAccessible, NS_ERROR_FAILURE);
-
-  mLastUsedSelection = do_GetWeakReference(aSel);
+  mLastUsedSelection = do_GetWeakReference(aSelection);
 
   PRInt32 rangeCount = 0;
-  nsresult rv = aSel->GetRangeCount(&rangeCount);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  aSelection->GetRangeCount(&rangeCount);
   if (rangeCount == 0) {
     mLastTextAccessible = nsnull;
-    return NS_OK; // No selection
+    return; // No selection
   }
 
-  nsCOMPtr<nsINode> textNode;
   nsRefPtr<nsHyperTextAccessible> textAcc =
-    nsAccUtils::GetTextAccessibleFromSelection(aSel, getter_AddRefs(textNode));
-  NS_ENSURE_STATE(textAcc);
+    nsAccUtils::GetTextAccessibleFromSelection(aSelection);
+  if (!textAcc)
+    return;
 
-  PRInt32 caretOffset;
-  rv = textAcc->GetCaretOffset(&caretOffset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt32 caretOffset = -1;
+  nsresult rv = textAcc->GetCaretOffset(&caretOffset);
+  if (NS_FAILED(rv))
+    return;
 
   if (textAcc == mLastTextAccessible && caretOffset == mLastCaretOffset) {
-    PRInt32 selectionCount;
+    PRInt32 selectionCount = 0;
     textAcc->GetSelectionCount(&selectionCount);   // Don't swallow similar events when selecting text
-    if (!selectionCount) {
-      return NS_OK;  // Swallow duplicate caret event
-    }
+    if (!selectionCount)
+      return;  // Swallow duplicate caret event
   }
+
   mLastCaretOffset = caretOffset;
   mLastTextAccessible.swap(textAcc);
 
-  nsRefPtr<AccEvent> event = new AccCaretMoveEvent(textNode);
-  NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
-
-  return mRootAccessible->FireDelayedAccessibleEvent(event);
+  nsRefPtr<AccEvent> event =
+    new AccCaretMoveEvent(mLastTextAccessible->GetNode());
+  if (event)
+    aDocument->FireDelayedAccessibleEvent(event);
 }
 
-nsresult
-nsCaretAccessible::SpellcheckSelectionChanged(nsIDOMDocument *aDoc,
-                                              nsISelection *aSel)
+void
+nsCaretAccessible::SpellcheckSelectionChanged(nsDocAccessible* aDocument,
+                                              nsISelection* aSelection)
 {
   // XXX: fire an event for accessible of focus node of the selection. If
   // spellchecking is enabled then we will fire the number of events for
   // the same accessible for newly appended range of the selection (for every
   // misspelled word). If spellchecking is disabled (for example,
   // @spellcheck="false" on html:body) then we won't fire any event.
 
   nsRefPtr<nsHyperTextAccessible> textAcc =
-    nsAccUtils::GetTextAccessibleFromSelection(aSel);
-  NS_ENSURE_STATE(textAcc);
+    nsAccUtils::GetTextAccessibleFromSelection(aSelection);
+  if (!textAcc)
+    return;
 
   nsRefPtr<AccEvent> event =
     new AccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED, textAcc);
-
-  nsEventShell::FireEvent(event);
-  return NS_OK;
+  if (event)
+    aDocument->FireDelayedAccessibleEvent(event);
 }
 
 nsIntRect
 nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
 {
   nsIntRect caretRect;
   NS_ENSURE_TRUE(aOutWidget, caretRect);
   *aOutWidget = nsnull;
--- a/accessible/src/base/nsCaretAccessible.h
+++ b/accessible/src/base/nsCaretAccessible.h
@@ -111,18 +111,28 @@ public:
    * the document, and in any case it is unavailable from the doc after a pagehide.
    * @param aShell   PresShell for document to no longer listen to selection events from.
    */
   nsresult RemoveDocSelectionListener(nsIPresShell *aShell);
 
   nsIntRect GetCaretRect(nsIWidget **aOutWidget);
 
 protected:
-  nsresult NormalSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
-  nsresult SpellcheckSelectionChanged(nsIDOMDocument *aDoc, nsISelection *aSel);
+  /**
+   * Process normal selection change and fire caret move event.
+   */
+  void NormalSelectionChanged(nsDocAccessible* aDocument,
+                              nsISelection* aSelection);
+
+  /**
+   * Process spellcheck selection change and fire text attribute changed event
+   * for invalid text attribute.
+   */
+  void SpellcheckSelectionChanged(nsDocAccessible* aDocument,
+                                  nsISelection* aSelection);
 
   /**
    * Return selection controller for the given node.
    */
   already_AddRefed<nsISelectionController>
     GetSelectionControllerForNode(nsIContent *aNode);
 
 private:
--- a/accessible/tests/mochitest/test_text_caret.html
+++ b/accessible/tests/mochitest/test_text_caret.html
@@ -38,25 +38,26 @@
      */
     function setCaretOffsetInvoker(aID, aOffset)
     {
       this.target = getAccessible(aID, [nsIAccessibleText]);
 
       this.invoke = function setCaretOffsetInvoker_invoke()
       {
         this.target.caretOffset = aOffset;
+        todo(false, "Enable focus event handling when bug 422744 is fixed.");
       }
 
       this.getID = function setCaretOffsetInvoker_getID()
       {
-        "nsIAccessibleText::caretOffset test"
+        return "nsIAccessibleText::caretOffset test";
       }
 
       this.eventSeq = [
-        new invokerChecker(EVENT_FOCUS, this.target),
+        // new invokerChecker(EVENT_FOCUS, this.target),
         new caretMovedChecker(this.target, aOffset)
       ];
     }
 
     /**
      * Do tests.
      */
     var gQueue = null;