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 +}