Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  tart.js   Sprache: JAVA

 
// TODO:
// V - Read transition duration from style instead of hardcoded 250ms (mconley)
// V - Remove caret from tart.html (unfocus url bar)
// V - Add fade-only tests (added icon @DPI2/current, simple @dpi current, lastTab @current. only icon@dpi2 runs on talos by default)
// V - Output JSON results (OK to log, check with MattN if that's enough)
// V - UI: Add tests descriptions, button to deselect all, Notice about profiling and Accurate 1st frame, copy JSON to clipboard.
// V - Add profiler markers as start/done:[test-name]
// V - Add custom subtests for talos by URL (tart.html)
// V - Change repeat order from column to row major
//     (now repeats each test N times then advances to next test - instead of repeating the entire set N times)
// V - Objectify
// V - make sure of window size (use pinned tart tab - enough even in scale 2 with australis)
// V - Make sure test-cases work on australis (min tab width for 8th tab)
// V - pref - disable paint starvation: docshell.event_starvation_delay_hint=1 -> will be set by talos or by the user
// V - For manual test: display: relevent prefs instructions (rate, starve hint), instructions for many-tabs
// V - allow API-less intervals recording (using rAF, since the API is b0rked with OMTC)
//     (but using rAF appears to record spurious very short intervals which I think are not really frames)
// V - Optimize cases (minimize test count without hurting cover):
//     - v1: only single tab, open + close, DPI1: about:blank, with-icon-and-long-title. DPI2: only the icon case
// V - Log output
// X - Support scroll into view (no end event)
// X - have preview images: hard to make work across versions
// - Tests:
//   V - With favicon
//   V - Different DPIs
//   V - with fade only (no tab open/close overhead)
//   X - tab drag
//   X - tab remove from the middle
//   X - Without add-tab button -> can be hidden while testing manually. in talos always with the button
ChromeUtils.defineESModuleGetters(this, {
  AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
});

/* globals res:true, sequenceArray:true */

function Tart() {}

Tart.prototype = {
  // Detector methods expect 'this' to be the detector object.
  // Detectors must support measureNow(e) which indicates to collect the intervals and stop the recording.
  // Detectors may support keepListening(e) to indicate to keep waiting before continuing to the next animation.

  tabDetector: {
    arm(handler, win) {
      win.gBrowser.tabContainer.addEventListener("transitionend", handler);
    },

    measureNow(e) {
      return e.type == "transitionend" && e.propertyName == "max-width";
    },

    cleanup(handler, win) {
      win.gBrowser.tabContainer.removeEventListener("transitionend", handler);
    },
  },

  customizeEnterDetector: {
    arm(handler, win) {
      win.gNavToolbox.addEventListener("customizationready", handler);
    },

    measureNow(e) {
      return e.type == "customizationready";
    },

    cleanup(handler, win) {
      win.gNavToolbox.removeEventListener("customizationready", handler);
    },
  },

  makeNewTabURLChangePromise(url) {
    let promise = new Promise(resolve => {
      Services.obs.addObserver(function observer(subject, topic, data) {
        Services.obs.removeObserver(observer, topic);
        if (data == url) {
          resolve();
        }
      }, "newtab-url-changed");
    });
    if (url === "about:newtab") {
      AboutNewTab.resetNewTabURL();
    } else {
      AboutNewTab.newTabURL = url;
    }
    return promise;
  },

  // Same as customizeEnterDetector, but stops recording when the CSS animation ends
  // The detector then waits until customizationready
  customizeEnterCssDetector: {
    arm(handler, win) {
      win.gNavToolbox.addEventListener("customizationready", handler);
      win.gNavToolbox.addEventListener("customization-transitionend", handler);
    },

    measureNow(e) {
      return e.type == "customization-transitionend";
    },

    keepListening(e) {
      return e.type != "customizationready";
    },

    cleanup(handler, win) {
      win.gNavToolbox.removeEventListener(
        "customization-transitionend",
        handler
      );
      win.gNavToolbox.removeEventListener("customizationready", handler);
    },
  },

  customizeExitDetector: {
    arm(handler, win) {
      win.gNavToolbox.addEventListener("aftercustomization", handler);
    },

    measureNow(e) {
      return e.type == "aftercustomization";
    },

    cleanup(handler, win) {
      win.gNavToolbox.removeEventListener("aftercustomization", handler);
    },
  },

  clickNewTab() {
    this._endDetection = this.tabDetector;
    this._win.BrowserCommands.openTab();
    // Modifying the style for each tab right after opening seems like it could regress performance,
    // However, overlaying a global style over browser.xhtml actually ends up having greater ovrehead,
    // especially while closing the last of many tabs (a noticeable ~250ms delay before expanding the rest).
    // To overlay the style globally, add at tart/chrome.manifest:
    // style chrome://browser/content/browser.xhtml chrome://tart/content/tab-min-width-1px.css
    // where the file tab-min-width-1px.css is:
    // .tabbrowser-tab[fadein]:not([pinned]) { min-width: 1px !important; }
    // Additionally, the global style overlay apparently messes with intervals recording when layout.frame_rate=10000:
    // Using the startFrameTimeRecording API, the first interval appears extra long (~1000ms) even with much widget tickling,
    // Per-tab min-width on open it is then.

    // --> many-tabs case which requires modified max-width will not go into v1. No need for now.
    // this._win.gBrowser.selectedTab.style.minWidth = "1px"; // Prevent overflow regrdless of DPI scale.

    return this._win.gBrowser.selectedTab;
  },

  clickCloseCurrentTab() {
    this._endDetection = this.tabDetector;
    this._win.BrowserCommands.closeTabOrWindow();
    return this._win.gBrowser.selectedTab;
  },

  fadeOutCurrentTab() {
    this._endDetection = this.tabDetector;
    this._win.gBrowser.selectedTab.removeAttribute("fadein");
  },

  fadeInCurrentTab() {
    this._endDetection = this.tabDetector;
    this._win.gBrowser.selectedTab.setAttribute("fadein""true");
  },

  addSomeChromeUriTab() {
    this._endDetection = this.tabDetector;
    this._win.gBrowser.selectedTab = this._win.gBrowser.addTrustedTab(
      "chrome://tart/content/blank.icon.html"
    );
  },

  triggerCustomizeEnter() {
    this._endDetection = this.customizeEnterDetector;
    this._win.gCustomizeMode.enter();
  },

  triggerCustomizeEnterCss() {
    this._endDetection = this.customizeEnterCssDetector;
    this._win.gCustomizeMode.enter();
  },

  triggerCustomizeExit() {
    this._endDetection = this.customizeExitDetector;
    this._win.gCustomizeMode.exit();
  },

  pinTart() {
    return this._win.gBrowser.pinTab(this._tartTab);
  },

  unpinTart() {
    return this._win.gBrowser.unpinTab(this._tartTab);
  },

  USE_RECORDING_API: true// true for Start[/Stop]FrameTimeRecording, otherwise record using rAF - which will also work with OMTC
  // but (currently) also records iterations without paint invalidations

  _win: undefined,
  _tartTab: undefined,
  _results: [],
  _config: {
    subtests: [],
    repeat: 1,
    rest: 500,
    tickle: true,
    controlProfiler: true,
  },

  _animate(
    preWaitMs,
    triggerFunc,
    onDoneCallback,
    isReportResult,
    name,
    referenceDuration
  ) {
    var self = this;
    var recordingHandle;
    var timeoutId = 0;
    var detector; // will be assigned after calling trigger.
    var rAF = window.requestAnimationFrame || window.mozRequestAnimationFrame;

    var _recording = [];
    var _abortRecording = false;
    var startRecordTimestamp;
    function startRecord() {
      if (self._config.controlProfiler) {
        if (isReportResult) {
          Profiler.subtestStart(name);
        }
      } else {
        Profiler.mark("Start: " + (isReportResult ? name : "[warmup]"), true);
      }
      startRecordTimestamp = window.performance.now();
      if (self.USE_RECORDING_API) {
        return window.windowUtils.startFrameTimeRecording();
      }

      _recording = [];
      _abortRecording = false;

      var last = performance.now();
      function rec() {
        // self._win.getComputedStyle(self._win.gBrowser.selectedTab).width; // force draw - not good - too much regression
        if (_abortRecording) {
          return;
        }

        var now = performance.now();
        _recording.push(now - last);
        last = now;
        rAF(rec);
      }

      rAF(rec);

      return 1; // dummy
    }

    var recordingAbsoluteDuration;
    function stopRecord() {
      recordingAbsoluteDuration =
        window.performance.now() - startRecordTimestamp;
      if (self._config.controlProfiler) {
        if (isReportResult) {
          Profiler.subtestEnd(name);
        }
      } else {
        Profiler.mark("End: " + (isReportResult ? name : "[warmup]"), true);
      }
      if (self.USE_RECORDING_API) {
        return window.windowUtils.stopFrameTimeRecording(recordingHandle);
      }

      _abortRecording = true;
      return _recording.slice(0); // clone
    }

    function addResult(intervals) {
      // For each animation sequence (intervals) we report 3 values:
      // 1. Average interval for the last 50% of the reference duration
      //    (e.g. if the reference duration is 250ms then average of the last 125ms,
      //     regardless of the actual animation duration in practice)
      // 2. Average interval for the entire animation.
      // 3. Absolute difference between reference duration to actual diration.

      var sumLastHalf = 0;
      var countLastHalf = 0;
      var sumMost = 0;
      var sum = 0;
      for (var i = intervals.length - 1; i >= 0; i--) {
        sum += intervals[i];
        if (sumLastHalf < referenceDuration / 2) {
          sumLastHalf += intervals[i];
          countLastHalf++;
        }
        if (sumMost < referenceDuration * 0.85) {
          sumMost += intervals[i];
        }
      }
      dump("overall: " + sum + "\n");

      var averageLastHalf = countLastHalf ? sumLastHalf / countLastHalf : 0;
      var averageOverall = intervals.length ? sum / intervals.length : 0;
      var durationDiff = Math.abs(
        recordingAbsoluteDuration - referenceDuration
      );

      self._results.push({ name: name + ".raw.TART", value: intervals }); // Just for display if running manually - Not collected for talos.
      self._results.push({ name: name + ".half.TART", value: averageLastHalf });
      self._results.push({ name: name + ".all.TART", value: averageOverall });
      self._results.push({ name: name + ".error.TART", value: durationDiff });
    }

    function transEnd(e) {
      if (e) {
        let isMeasureNow = detector.measureNow(e);

        if (isMeasureNow) {
          // Get the recorded frame intervals and append result if required
          let intervals = stopRecord();
          if (isReportResult) {
            addResult(intervals);
          }
        }

        // If detector supports keepListening, use it, otherwise - measurement indicates the end.
        if (
          detector.keepListening ? detector.keepListening(e) : !isMeasureNow
        ) {
          return;
        }
      } else {
        // No event == timeout
        dump("TART: TIMEOUT\n");
      }

      // Cleanup
      detector.cleanup(transEnd, self._win);
      clearTimeout(timeoutId);

      onDoneCallback();
    }

    function trigger(f) {
      if (!self.USE_RECORDING_API) {
        return rAF(f);
      }

      // When using the recording API, the first interval is to last frame, which could have been a while ago.
      // To make sure the first interval is counted correctly, we "tickle" a widget
      // and immidiatly afterwards start the test, such the last frame timestamp prior to the recording is now.
      // However, on some systems, modifying the widget once isn't always enough, hence the tickle loop.
      //
      var id = "back-button";
      var orig = self._win.document.getElementById(id).style.opacity;
      var i = 0;

      function tickleLoop() {
        if (i++ < (isReportResult && self._config.tickle ? 17 : 0)) {
          self._win.document.getElementById(id).style.opacity =
            (i % 10) / 10 + 0.05; // just some style modification which will force redraw
          return rAF(tickleLoop);
        }

        self._win.document.getElementById(id).style.opacity = orig;
        return rAF(f);
      }

      tickleLoop();

      return false;
    }

    setTimeout(function () {
      trigger(function () {
        timeoutId = setTimeout(transEnd, 3000);
        recordingHandle = startRecord();
        triggerFunc(); // also chooses detector
        detector = self._endDetection;
        detector.arm(transEnd, self._win);
      });
    }, preWaitMs);
  },

  _nextCommandIx: 0,
  _commands: [],
  _onSequenceComplete: 0,
  _nextCommand() {
    if (this._nextCommandIx >= this._commands.length) {
      this._onSequenceComplete();
      return;
    }
    this._commands[this._nextCommandIx++]();
  },
  // Each command at the array a function which must call nextCommand once it's done
  _doSequence(commands, onComplete) {
    this._commands = commands;
    this._onSequenceComplete = onComplete;
    this._results = [];
    this._nextCommandIx = 0;

    this._nextCommand();
  },

  _log(str) {
    if (window.MozillaFileLogger && window.MozillaFileLogger.log) {
      window.MozillaFileLogger.log(str);
    }

    window.dump(str);
  },

  _logLine(str) {
    return this._log(str + "\n");
  },

  _reportAllResults() {
    var out = "";
    for (var i in this._results) {
      res = this._results[i];
      var disp = []
        .concat(res.value)
        .map(function (a) {
          return isNaN(a) ? -1 : a.toFixed(1);
        })
        .join(" ");
      out += res.name + ": " + disp + "\n";
    }
    this._log("\n" + out);
  },

  _onTestComplete: null,

  _doneInternal() {
    this._logLine("TART_RESULTS_JSON=" + JSON.stringify(this._results));
    this._reportAllResults();
    this._win.gBrowser.selectedTab = this._tartTab;

    if (this._onTestComplete) {
      this._onTestComplete(JSON.parse(JSON.stringify(this._results))); // Clone results
    }
  },

  _startTest() {
    // Save prefs and states which will change during the test, to get restored when done.
    var origPreload = Services.prefs.getBoolPref("browser.newtab.preload");
    var origDpi = Services.prefs.getCharPref("layout.css.devPixelsPerPx");
    var origPinned = this._tartTab.pinned;

    var self = this;
    var animate = this._animate.bind(this);
    var addTab = this.clickNewTab.bind(this);
    var closeCurrentTab = this.clickCloseCurrentTab.bind(this);
    var fadein = this.fadeInCurrentTab.bind(this);
    var fadeout = this.fadeOutCurrentTab.bind(this);

    var addSomeTab = this.addSomeChromeUriTab.bind(this);
    var customizeEnter = this.triggerCustomizeEnter.bind(this);
    var customizeEnterCss = this.triggerCustomizeEnterCss.bind(this);
    var customizeExit = this.triggerCustomizeExit.bind(this);

    var next = this._nextCommand.bind(this);
    var rest = 500; // 500ms default rest before measuring an animation
    if (this._config.rest) {
      rest = this._config.rest;
    }

    // NOTE: causes a (slow) reflow, don't use right before measurements.
    function getMaxTabTransitionTimeMs(aTab) {
      let cstyle = window.getComputedStyle(aTab);
      try {
        return (
          1000 *
          Math.max.apply(
            null,
            cstyle.transitionDuration.split(", ").map(s => parseFloat(s, 10))
          )
        );
      } catch (e) {
        return 250;
      }
    }

    this.unpinTart();
    var tabRefDuration = getMaxTabTransitionTimeMs(this._tartTab);
    if (tabRefDuration < 20 || tabRefDuration > 2000) {
      // Hardcoded fallback in case the value doesn't make sense as tab animation duration.
      tabRefDuration = 250;
    }

    var custRefDuration = 0;

    var subtests = {
      init: [
        // This is called before each subtest, so it's safe to assume the following prefs:
        function () {
          Services.prefs.setBoolPref("browser.newtab.preload"false);
          self.pinTart();
          self.makeNewTabURLChangePromise("about:blank").then(next);
        },
      ],

      restore: [
        // Restore prefs which were modified during the test
        function () {
          Services.prefs.setBoolPref("browser.newtab.preload", origPreload);
          Services.prefs.setCharPref("layout.css.devPixelsPerPx", origDpi);
          if (origPinned) {
            self.pinTart();
          } else {
            self.unpinTart();
          }
          self.makeNewTabURLChangePromise("about:newtab").then(next);
        },
      ],

      simple: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""1");
          next();
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },

        function () {
          animate(rest, addTab, next, true"simple-open-DPI1", tabRefDuration);
        },
        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "simple-close-DPI1",
            tabRefDuration
          );
        },
      ],

      iconDpi1: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""1");
          self
            .makeNewTabURLChangePromise("chrome://tart/content/blank.icon.html")
            .then(next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },

        function () {
          animate(rest, addTab, next, true"icon-open-DPI1", tabRefDuration);
        },
        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "icon-close-DPI1",
            tabRefDuration
          );
        },
      ],

      iconDpi2: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""2");
          self
            .makeNewTabURLChangePromise("chrome://tart/content/blank.icon.html")
            .then(next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },

        function () {
          animate(rest, addTab, next, true"icon-open-DPI2", tabRefDuration);
        },
        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "icon-close-DPI2",
            tabRefDuration
          );
        },
      ],

      newtabNoPreload: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""-1");
          Services.prefs.setBoolPref("browser.newtab.preload"false);
          self.makeNewTabURLChangePromise("about:newtab").then(next);
        },
        function () {
          animate(
            rest,
            addTab,
            next,
            true,
            "newtab-open-preload-no",
            tabRefDuration
          );
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      newtabYesPreload: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""-1");
          Services.prefs.setBoolPref("browser.newtab.preload"true);
          self.makeNewTabURLChangePromise("about:newtab").then(next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },

        function () {
          animate(
            1000,
            addTab,
            next,
            true,
            "newtab-open-preload-yes",
            tabRefDuration
          );
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      simple3open3closeDpiCurrent: [
        function () {
          animate(
            rest,
            addTab,
            next,
            true,
            "simple3-1-open-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            addTab,
            next,
            true,
            "simple3-2-open-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            addTab,
            next,
            true,
            "simple3-3-open-DPIcurrent",
            tabRefDuration
          );
        },

        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "simple3-3-close-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "simple3-2-close-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            closeCurrentTab,
            next,
            true,
            "simple3-1-close-DPIcurrent",
            tabRefDuration
          );
        },
      ],

      multi: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""1.0");
          self
            .makeNewTabURLChangePromise("chrome://tart/content/blank.icon.html")
            .then(next);
        },

        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, addTab, next);
        },

        function () {
          animate(
            rest * 2,
            addTab,
            next,
            true,
            "multi-open-DPI1",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest * 2,
            closeCurrentTab,
            next,
            true,
            "multi-close-DPI1",
            tabRefDuration
          );
        },

        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""2");
          next();
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(
            rest * 2,
            addTab,
            next,
            true,
            "multi-open-DPI2",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest * 2,
            closeCurrentTab,
            next,
            true,
            "multi-close-DPI2",
            tabRefDuration
          );
        },

        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""-1");
          next();
        },

        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      simpleFadeDpiCurrent: [
        function () {
          self.makeNewTabURLChangePromise("about:blank").then(next);
        },

        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(
            rest,
            fadeout,
            next,
            true,
            "simpleFade-close-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            fadein,
            next,
            true,
            "simpleFade-open-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      iconFadeDpiCurrent: [
        function () {
          self
            .makeNewTabURLChangePromise("chrome://tart/content/blank.icon.html")
            .then(next);
        },

        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(
            rest,
            fadeout,
            next,
            true,
            "iconFade-close-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            fadein,
            next,
            true,
            "iconFade-open-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      iconFadeDpi2: [
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""2");
          self
            .makeNewTabURLChangePromise("chrome://tart/content/blank.icon.html")
            .then(next);
        },
        function () {
          animate(0, addTab, next);
        },
        function () {
          animate(
            rest,
            fadeout,
            next,
            true,
            "iconFade-close-DPI2",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            fadein,
            next,
            true,
            "iconFade-open-DPI2",
            tabRefDuration
          );
        },
        function () {
          animate(0, closeCurrentTab, next);
        },
      ],

      lastTabFadeDpiCurrent: [
        function () {
          self._win.gBrowser.selectedTab =
            self._win.gBrowser.tabs[gBrowser.tabs.length - 1];
          next();
        },
        function () {
          animate(
            rest,
            fadeout,
            next,
            true,
            "lastTabFade-close-DPIcurrent",
            tabRefDuration
          );
        },
        function () {
          animate(
            rest,
            fadein,
            next,
            true,
            "lastTabFade-open-DPIcurrent",
            tabRefDuration
          );
        },
      ],

      customize: [
        // Test australis customize mode animation with default DPI.
        function () {
          Services.prefs.setCharPref("layout.css.devPixelsPerPx""-1");
          next();
        },
        // Adding a non-newtab since the behavior of exiting customize mode which was entered on newtab may change. See bug 957202.
        function () {
          animate(0, addSomeTab, next);
        },

        // The prefixes 1- and 2- were added because talos cuts common prefixes on all "pages", which ends up as "customize-e" prefix.
        function () {
          animate(
            rest,
            customizeEnter,
            next,
            true,
            "1-customize-enter",
            custRefDuration
          );
        },
        function () {
          animate(
            rest,
            customizeExit,
            next,
            true,
            "2-customize-exit",
            custRefDuration
          );
        },

        // Measures the CSS-animation-only part of entering into customize mode
        function () {
          animate(
            rest,
            customizeEnterCss,
            next,
            true,
            "3-customize-enter-css",
            custRefDuration
          );
        },
        function () {
          animate(0, customizeExit, next);
        },

        function () {
          animate(0, closeCurrentTab, next);
        },
      ],
    };

    // Construct the sequence array: config.repeat times config.subtests,
    // where each subtest implicitly starts with init.
    sequenceArray = [];
    for (var i in this._config.subtests) {
      for (var r = 0; r < this._config.repeat; r++) {
        sequenceArray = sequenceArray.concat(subtests.init);
        sequenceArray = sequenceArray.concat(
          subtests[this._config.subtests[i]]
        );
      }
    }
    sequenceArray = sequenceArray.concat(subtests.restore);

    this._doSequence(sequenceArray, this._doneInternal);
  },

  startTest(doneCallback, config) {
    this._onTestComplete = function (results) {
      Profiler.mark("TART - end"true);
      doneCallback(results);
    };
    this._config = config;

    this._win = Services.wm.getMostRecentWindow("navigator:browser");
    this._tartTab = this._win.gBrowser.selectedTab;
    this._win.gBrowser.selectedBrowser.focus(); // Unfocus the URL bar to avoid caret blink

    Profiler.mark("TART - start"true);

    return this._startTest();
  },
};

Messung V0.5
C=93 H=94 G=93

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge