accessible/tests/mochitest/jsat/dom_helper.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/accessible/tests/mochitest/jsat/dom_helper.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,207 @@
     1.4 +'use strict';
     1.5 +
     1.6 +/* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker,
     1.7 +   SimpleTest, getBoundsForDOMElm, Point, Utils */
     1.8 +/* exported loadJSON, eventMap */
     1.9 +
    1.10 +const Ci = Components.interfaces;
    1.11 +const Cu = Components.utils;
    1.12 +
    1.13 +Cu.import('resource://gre/modules/accessibility/Utils.jsm');
    1.14 +Cu.import('resource://gre/modules/Geometry.jsm');
    1.15 +Cu.import("resource://gre/modules/accessibility/Gestures.jsm");
    1.16 +
    1.17 +var win = getMainChromeWindow(window);
    1.18 +
    1.19 +/**
    1.20 + * Convert inch based point coordinates into pixels.
    1.21 + * @param  {Array} aPoints Array of coordinates in inches.
    1.22 + * @return {Array} Array of coordinates in pixels.
    1.23 + */
    1.24 +function convertPointCoordinates(aPoints) {
    1.25 +  var dpi = Utils.dpi;
    1.26 +  return aPoints.map(function convert(aPoint) {
    1.27 +    return {
    1.28 +      x: aPoint.x * dpi,
    1.29 +      y: aPoint.y * dpi,
    1.30 +      identifier: aPoint.identifier
    1.31 +    };
    1.32 +  });
    1.33 +}
    1.34 +
    1.35 +/**
    1.36 + * For a given list of points calculate their coordinates in relation to the
    1.37 + * document body.
    1.38 + * @param  {Array} aTouchPoints An array of objects of the following format: {
    1.39 + *   base: {String}, // Id of an element to server as a base for the touch.
    1.40 + *   x: {Number},    // An optional x offset from the base element's geometric
    1.41 + *                   // centre.
    1.42 + *   y: {Number}     // An optional y offset from the base element's geometric
    1.43 + *                   // centre.
    1.44 + * }
    1.45 + * @return {JSON} An array of {x, y} coordinations.
    1.46 + */
    1.47 +function calculateTouchListCoordinates(aTouchPoints) {
    1.48 +  var coords = [];
    1.49 +  for (var i = 0, target = aTouchPoints[i]; i < aTouchPoints.length; ++i) {
    1.50 +    var bounds = getBoundsForDOMElm(target.base);
    1.51 +    var parentBounds = getBoundsForDOMElm('root');
    1.52 +    var point = new Point(target.x || 0, target.y || 0);
    1.53 +    point.scale(Utils.dpi);
    1.54 +    point.add(bounds[0], bounds[1]);
    1.55 +    point.add(bounds[2] / 2, bounds[3] / 2);
    1.56 +    point.subtract(parentBounds[0], parentBounds[0]);
    1.57 +    coords.push({
    1.58 +      x: point.x,
    1.59 +      y: point.y
    1.60 +    });
    1.61 +  }
    1.62 +  return coords;
    1.63 +}
    1.64 +
    1.65 +/**
    1.66 + * Send a touch event with specified touchPoints.
    1.67 + * @param  {Array} aTouchPoints An array of points to be associated with
    1.68 + * touches.
    1.69 + * @param  {String} aName A name of the touch event.
    1.70 + */
    1.71 +function sendTouchEvent(aTouchPoints, aName) {
    1.72 +  var touchList = sendTouchEvent.touchList;
    1.73 +  if (aName === 'touchend') {
    1.74 +    sendTouchEvent.touchList = null;
    1.75 +  } else {
    1.76 +    var coords = calculateTouchListCoordinates(aTouchPoints);
    1.77 +    var touches = [];
    1.78 +    for (var i = 0; i < coords.length; ++i) {
    1.79 +      var {x, y} = coords[i];
    1.80 +      var node = document.elementFromPoint(x, y);
    1.81 +      var touch = document.createTouch(window, node, aName === 'touchstart' ?
    1.82 +        1 : touchList.item(i).identifier, x, y, x, y);
    1.83 +      touches.push(touch);
    1.84 +    }
    1.85 +    touchList = document.createTouchList(touches);
    1.86 +    sendTouchEvent.touchList = touchList;
    1.87 +  }
    1.88 +  var evt = document.createEvent('TouchEvent');
    1.89 +  evt.initTouchEvent(aName, true, true, window, 0, false, false, false, false,
    1.90 +    touchList, touchList, touchList);
    1.91 +  document.dispatchEvent(evt);
    1.92 +}
    1.93 +
    1.94 +sendTouchEvent.touchList = null;
    1.95 +
    1.96 +/**
    1.97 + * A map of event names to the functions that actually send them.
    1.98 + * @type {Object}
    1.99 + */
   1.100 +var eventMap = {
   1.101 +  touchstart: sendTouchEvent,
   1.102 +  touchend: sendTouchEvent,
   1.103 +  touchmove: sendTouchEvent
   1.104 +};
   1.105 +
   1.106 +var originalDwellThreshold = GestureSettings.dwellThreshold;
   1.107 +var originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
   1.108 +
   1.109 +/**
   1.110 + * Attach a listener for the mozAccessFuGesture event that tests its
   1.111 + * type.
   1.112 + * @param  {Array} aExpectedGestures A stack of expected event types.
   1.113 + * Note: the listener is removed once the stack reaches 0.
   1.114 + */
   1.115 +function testMozAccessFuGesture(aExpectedGestures) {
   1.116 +  var types = typeof aExpectedGestures === "string" ?
   1.117 +    [aExpectedGestures] : aExpectedGestures;
   1.118 +  function handleGesture(aEvent) {
   1.119 +    if (aEvent.detail.type !== types[0]) {
   1.120 +      // The is not the event of interest.
   1.121 +      return;
   1.122 +    }
   1.123 +    ok(true, 'Received correct mozAccessFuGesture: ' + types.shift() + '.');
   1.124 +    if (types.length === 0) {
   1.125 +      win.removeEventListener('mozAccessFuGesture', handleGesture);
   1.126 +      if (AccessFuTest.sequenceCleanup) {
   1.127 +        AccessFuTest.sequenceCleanup();
   1.128 +      }
   1.129 +      AccessFuTest.nextTest();
   1.130 +    }
   1.131 +  }
   1.132 +  win.addEventListener('mozAccessFuGesture', handleGesture);
   1.133 +}
   1.134 +
   1.135 +/**
   1.136 + * Reset the thresholds and max delays that affect gesture rejection.
   1.137 + * @param {Number} aTimeStamp Gesture time stamp.
   1.138 + * @param {Boolean} aRemoveDwellThreshold An optional flag to reset dwell
   1.139 + * threshold.
   1.140 + * @param {Boolean} aRemoveSwipeMaxDuration An optional flag to reset swipe max
   1.141 + * duration.
   1.142 + */
   1.143 +function setTimers(aTimeStamp, aRemoveDwellThreshold, aRemoveSwipeMaxDuration) {
   1.144 +  if (!aRemoveDwellThreshold && !aRemoveSwipeMaxDuration) {
   1.145 +    return;
   1.146 +  }
   1.147 +  if (aRemoveDwellThreshold) {
   1.148 +    GestureSettings.dwellThreshold = 0;
   1.149 +  }
   1.150 +  if (aRemoveSwipeMaxDuration) {
   1.151 +    GestureSettings.swipeMaxDuration = 0;
   1.152 +  }
   1.153 +  GestureTracker.current.clearTimer();
   1.154 +  GestureTracker.current.startTimer(aTimeStamp);
   1.155 +}
   1.156 +
   1.157 +function resetTimers() {
   1.158 +  GestureSettings.dwellThreshold = originalDwellThreshold;
   1.159 +  GestureSettings.swipeMaxDuration = originalSwipeMaxDuration;
   1.160 +}
   1.161 +
   1.162 +/**
   1.163 + * An extention to AccessFuTest that adds an ability to test a sequence of
   1.164 + * pointer events and their expected mozAccessFuGesture events.
   1.165 + * @param {Object} aSequence An object that has a list of pointer events to be
   1.166 + * generated and the expected mozAccessFuGesture events.
   1.167 + */
   1.168 +AccessFuTest.addSequence = function AccessFuTest_addSequence(aSequence) {
   1.169 +  AccessFuTest.addFunc(function testSequence() {
   1.170 +    testMozAccessFuGesture(aSequence.expectedGestures);
   1.171 +    var events = aSequence.events;
   1.172 +    function fireEvent(aEvent) {
   1.173 +      var event = {
   1.174 +        points: convertPointCoordinates(aEvent.points),
   1.175 +        type: aEvent.type
   1.176 +      };
   1.177 +      var timeStamp = Date.now();
   1.178 +      resetTimers();
   1.179 +      GestureTracker.handle(event, timeStamp);
   1.180 +      setTimers(timeStamp, aEvent.removeDwellThreshold,
   1.181 +        aEvent.removeSwipeMaxDuration);
   1.182 +      processEvents();
   1.183 +    }
   1.184 +    function processEvents() {
   1.185 +      if (events.length === 0) {
   1.186 +        return;
   1.187 +      }
   1.188 +      var event = events.shift();
   1.189 +      SimpleTest.executeSoon(function() {
   1.190 +        fireEvent(event);
   1.191 +      });
   1.192 +    }
   1.193 +    processEvents();
   1.194 +  });
   1.195 +};
   1.196 +
   1.197 +/**
   1.198 + * A helper function that loads JSON files.
   1.199 + * @param {String} aPath A path to a JSON file.
   1.200 + * @param {Function} aCallback A callback to be called on success.
   1.201 + */
   1.202 +function loadJSON(aPath, aCallback) {
   1.203 +  var request = new XMLHttpRequest();
   1.204 +  request.open('GET', aPath, true);
   1.205 +  request.responseType = 'json';
   1.206 +  request.onload = function onload() {
   1.207 +    aCallback(request.response);
   1.208 +  };
   1.209 +  request.send();
   1.210 +}

mercurial