Bug 863430 - Teach the reftest harness about async spell checking. r=dbaron
authorDrew Willcoxon <adw@mozilla.com>
Wed, 05 Jun 2013 17:07:55 -0700
changeset 145667 b5138d0d688986c6f34db019cb4f20970956ebf1
parent 145666 3f4ad11d56da4b29ee44fe238ecce312204cdc85
child 145668 25847d9ef59037a4fbb77f239e435cc6eb837c3b
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs863430
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 863430 - Teach the reftest harness about async spell checking. r=dbaron
layout/tools/reftest/reftest-content.js
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -14,16 +14,17 @@ const XHTML_NS = "http://www.w3.org/1999
 const DEBUG_CONTRACTID = "@mozilla.org/xpcom/debug;1";
 const PRINTSETTINGS_CONTRACTID = "@mozilla.org/gfx/printsettings-service;1";
 const ENVIRONMENT_CONTRACTID = "@mozilla.org/process/environment;1";
 
 // "<!--CLEAR-->"
 const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E";
 
 CU.import("resource://gre/modules/Timer.jsm");
+CU.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
 
 var gBrowserIsRemote;
 var gHaveCanvasSnapshot = false;
 // Plugin layers can be updated asynchronously, so to make sure that all
 // layer surfaces have the right content, we need to listen for explicit
 // "MozPaintWait" and "MozPaintWaitFinished" events that signal when it's OK
 // to take snapshots. We cannot take a snapshot while the number of
 // "MozPaintWait" events fired exceeds the number of "MozPaintWaitFinished"
@@ -246,22 +247,25 @@ function getNoPaintElements(contentRootE
 
 // Initial state. When the document has loaded and all MozAfterPaint events and
 // all explicit paint waits are flushed, we can fire the MozReftestInvalidate
 // event and move to the next state.
 const STATE_WAITING_TO_FIRE_INVALIDATE_EVENT = 0;
 // When reftest-wait has been removed from the root element, we can move to the
 // next state.
 const STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL = 1;
+// When spell checking is done on all spell-checked elements, we can move to the
+// next state.
+const STATE_WAITING_FOR_SPELL_CHECKS = 2;
 // When all MozAfterPaint events and all explicit paint waits are flushed, we're
 // done and can move to the COMPLETED state.
-const STATE_WAITING_TO_FINISH = 2;
-const STATE_COMPLETED = 3;
+const STATE_WAITING_TO_FINISH = 3;
+const STATE_COMPLETED = 4;
 
-function WaitForTestEnd(contentRootElement, inPrintMode) {
+function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
     var stopAfterPaintReceived = false;
     var currentDoc = content.document;
     var state = STATE_WAITING_TO_FIRE_INVALIDATE_EVENT;
 
     function FlushRendering() {
         var anyPendingPaintsGeneratedInDescendants = false;
 
         function flushWindow(win) {
@@ -393,16 +397,30 @@ function WaitForTestEnd(contentRootEleme
 
         case STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL:
             LogInfo("MakeProgress: STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL");
             if (shouldWaitForReftestWaitRemoval(contentRootElement)) {
                 gFailureReason = "timed out waiting for reftest-wait to be removed";
                 LogInfo("MakeProgress: waiting for reftest-wait to be removed");
                 return;
             }
+
+            // Try next state
+            state = STATE_WAITING_FOR_SPELL_CHECKS;
+            MakeProgress();
+            return;
+
+        case STATE_WAITING_FOR_SPELL_CHECKS:
+            LogInfo("MakeProgress: STATE_WAITING_FOR_SPELL_CHECKS");
+            if (numPendingSpellChecks) {
+                gFailureReason = "timed out waiting for spell checks to end";
+                LogInfo("MakeProgress: waiting for spell checks to end");
+                return;
+            }
+
             state = STATE_WAITING_TO_FINISH;
             if (!inPrintMode && doPrintMode(contentRootElement)) {
                 LogInfo("MakeProgress: setting up print mode");
                 setupPrintMode();
             }
             // Try next state
             MakeProgress();
             return;
@@ -445,16 +463,31 @@ function WaitForTestEnd(contentRootEleme
     // If contentRootElement is null then shouldWaitForReftestWaitRemoval will
     // always return false so we don't need a listener anyway
     if (contentRootElement) {
       contentRootElement.addEventListener("DOMAttrModified", AttrModifiedListener, false);
     }
     gExplicitPendingPaintsCompleteHook = ExplicitPaintsCompleteListener;
     gTimeoutHook = RemoveListeners;
 
+    // Listen for spell checks on spell-checked elements.
+    var numPendingSpellChecks = spellCheckedElements.length;
+    function decNumPendingSpellChecks() {
+        --numPendingSpellChecks;
+        MakeProgress();
+    }
+    for (let editable of spellCheckedElements) {
+        try {
+            onSpellCheck(editable, decNumPendingSpellChecks);
+        } catch (err) {
+            // The element may not have an editor, so ignore it.
+            setTimeout(decNumPendingSpellChecks, 0);
+        }
+    }
+
     // Take a full snapshot now that all our listeners are set up. This
     // ensures it's impossible for us to miss updates between taking the snapshot
     // and adding our listeners.
     SendInitCanvasWithSnapshot();
     MakeProgress();
 }
 
 function OnDocumentLoad(event)
@@ -471,16 +504,29 @@ function OnDocumentLoad(event)
     }
 
     if (currentDoc.location.href != gCurrentURL) {
         LogInfo("OnDocumentLoad fired for previous document");
         // Ignore load events for previous documents.
         return;
     }
 
+    // Collect all editable, spell-checked elements.  It may be the case that
+    // not all the elements that match this selector will be spell checked: for
+    // example, a textarea without a spellcheck attribute may have a parent with
+    // spellcheck=false, or script may set spellcheck=false on an element whose
+    // markup sets it to true.  But that's OK since onSpellCheck detects the
+    // absence of spell checking, too.
+    var querySelector =
+        '*[class~="spell-checked"],' +
+        'textarea:not([spellcheck="false"]),' +
+        'input[spellcheck]:-moz-any([spellcheck=""],[spellcheck="true"]),' +
+        '*[contenteditable]:-moz-any([contenteditable=""],[contenteditable="true"])';
+    var spellCheckedElements = currentDoc.querySelectorAll(querySelector);
+
     var contentRootElement = currentDoc ? currentDoc.documentElement : null;
     currentDoc = null;
     setupZoom(contentRootElement);
     setupDisplayport(contentRootElement);
     var inPrintMode = false;
 
     function AfterOnLoadScripts() {
         // Regrab the root element, because the document may have changed.
@@ -496,30 +542,31 @@ function OnDocumentLoad(event)
         if (shouldWaitForExplicitPaintWaiters() ||
             (!inPrintMode && doPrintMode(contentRootElement)) ||
             // If we didn't force a paint above, in
             // InitCurrentCanvasWithSnapshot, so we should wait for a
             // paint before we consider them done.
             !painted) {
             LogInfo("AfterOnLoadScripts belatedly entering WaitForTestEnd");
             // Go into reftest-wait mode belatedly.
-            WaitForTestEnd(contentRootElement, inPrintMode);
+            WaitForTestEnd(contentRootElement, inPrintMode, []);
         } else {
             CheckForProcessCrashExpectation();
             RecordResult();
         }
     }
 
     if (shouldWaitForReftestWaitRemoval(contentRootElement) ||
-        shouldWaitForExplicitPaintWaiters()) {
+        shouldWaitForExplicitPaintWaiters() ||
+        spellCheckedElements.length) {
         // Go into reftest-wait mode immediately after painting has been
         // unsuppressed, after the onload event has finished dispatching.
         gFailureReason = "timed out waiting for test to complete (trying to get into WaitForTestEnd)";
         LogInfo("OnDocumentLoad triggering WaitForTestEnd");
-        setTimeout(function () { WaitForTestEnd(contentRootElement, inPrintMode); }, 0);
+        setTimeout(function () { WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements); }, 0);
     } else {
         if (doPrintMode(contentRootElement)) {
             LogInfo("OnDocumentLoad setting up print mode");
             setupPrintMode();
             inPrintMode = true;
         }
 
         // Since we can't use a bubbling-phase load listener from chrome,