Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / testing / marionette / ChromeUtils.js
blobd51f96bc39ba2c6fb5cd2b5d59c7e176468ec5f7
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
6  * ChromeUtils.js is a set of mochitest utilities that are used to 
7  * synthesize events in the browser.  These are only used by 
8  * mochitest-chrome and browser-chrome tests.  Originally these functions were in 
9  * EventUtils.js, but when porting to specialPowers, we didn't want
10  * to move unnecessary functions.
11  *
12  * ChromeUtils.js depends on EventUtils.js being loaded.
13  *
14  */
16 /**
17  * Synthesize a query text content event.
18  *
19  * @param aOffset  The character offset.  0 means the first character in the
20  *                 selection root.
21  * @param aLength  The length of getting text.  If the length is too long,
22  *                 the extra length is ignored.
23  * @param aWindow  Optional (If null, current |window| will be used)
24  * @return         An nsIQueryContentEventResult object.  If this failed,
25  *                 the result might be null.
26  */
27 function synthesizeQueryTextContent(aOffset, aLength, aWindow)
29   var utils = _getDOMWindowUtils(aWindow);
30   if (!utils) {
31     return nullptr;
32   }
33   return utils.sendQueryContentEvent(utils.QUERY_TEXT_CONTENT,
34                                      aOffset, aLength, 0, 0);
37 /**
38  * Synthesize a query caret rect event.
39  *
40  * @param aOffset  The caret offset.  0 means left side of the first character
41  *                 in the selection root.
42  * @param aWindow  Optional (If null, current |window| will be used)
43  * @return         An nsIQueryContentEventResult object.  If this failed,
44  *                 the result might be null.
45  */
46 function synthesizeQueryCaretRect(aOffset, aWindow)
48   var utils = _getDOMWindowUtils(aWindow);
49   if (!utils) {
50     return nullptr;
51   }
52   return utils.sendQueryContentEvent(utils.QUERY_CARET_RECT,
53                                      aOffset, 0, 0, 0);
56 /**
57  * Synthesize a query text rect event.
58  *
59  * @param aOffset  The character offset.  0 means the first character in the
60  *                 selection root.
61  * @param aLength  The length of the text.  If the length is too long,
62  *                 the extra length is ignored.
63  * @param aWindow  Optional (If null, current |window| will be used)
64  * @return         An nsIQueryContentEventResult object.  If this failed,
65  *                 the result might be null.
66  */
67 function synthesizeQueryTextRect(aOffset, aLength, aWindow)
69   var utils = _getDOMWindowUtils(aWindow);
70   if (!utils) {
71     return nullptr;
72   }
73   return utils.sendQueryContentEvent(utils.QUERY_TEXT_RECT,
74                                      aOffset, aLength, 0, 0);
77 /**
78  * Synthesize a query editor rect event.
79  *
80  * @param aWindow  Optional (If null, current |window| will be used)
81  * @return         An nsIQueryContentEventResult object.  If this failed,
82  *                 the result might be null.
83  */
84 function synthesizeQueryEditorRect(aWindow)
86   var utils = _getDOMWindowUtils(aWindow);
87   if (!utils) {
88     return nullptr;
89   }
90   return utils.sendQueryContentEvent(utils.QUERY_EDITOR_RECT, 0, 0, 0, 0);
93 /**
94  * Synthesize a character at point event.
95  *
96  * @param aX, aY   The offset in the client area of the DOM window.
97  * @param aWindow  Optional (If null, current |window| will be used)
98  * @return         An nsIQueryContentEventResult object.  If this failed,
99  *                 the result might be null.
100  */
101 function synthesizeCharAtPoint(aX, aY, aWindow)
103   var utils = _getDOMWindowUtils(aWindow);
104   if (!utils) {
105     return nullptr;
106   }
107   return utils.sendQueryContentEvent(utils.QUERY_CHARACTER_AT_POINT,
108                                      0, 0, aX, aY);
112  * Emulate a dragstart event.
113  *  element - element to fire the dragstart event on
114  *  expectedDragData - the data you expect the data transfer to contain afterwards
115  *                      This data is in the format:
116  *                         [ [ {type: value, data: value, test: function}, ... ], ... ]
117  *                     can be null
118  *  aWindow - optional; defaults to the current window object.
119  *  x - optional; initial x coordinate
120  *  y - optional; initial y coordinate
121  * Returns null if data matches.
122  * Returns the event.dataTransfer if data does not match
124  * eqTest is an optional function if comparison can't be done with x == y;
125  *   function (actualData, expectedData) {return boolean}
126  *   @param actualData from dataTransfer
127  *   @param expectedData from expectedDragData
128  * see bug 462172 for example of use
130  */
131 function synthesizeDragStart(element, expectedDragData, aWindow, x, y)
133   if (!aWindow)
134     aWindow = window;
135   x = x || 2;
136   y = y || 2;
137   const step = 9;
139   var result = "trapDrag was not called";
140   var trapDrag = function(event) {
141     try {
142       var dataTransfer = event.dataTransfer;
143       result = null;
144       if (!dataTransfer)
145         throw "no dataTransfer";
146       if (expectedDragData == null ||
147           dataTransfer.mozItemCount != expectedDragData.length)
148         throw dataTransfer;
149       for (var i = 0; i < dataTransfer.mozItemCount; i++) {
150         var dtTypes = dataTransfer.mozTypesAt(i);
151         if (dtTypes.length != expectedDragData[i].length)
152           throw dataTransfer;
153         for (var j = 0; j < dtTypes.length; j++) {
154           if (dtTypes[j] != expectedDragData[i][j].type)
155             throw dataTransfer;
156           var dtData = dataTransfer.mozGetDataAt(dtTypes[j],i);
157           if (expectedDragData[i][j].eqTest) {
158             if (!expectedDragData[i][j].eqTest(dtData, expectedDragData[i][j].data))
159               throw dataTransfer;
160           }
161           else if (expectedDragData[i][j].data != dtData)
162             throw dataTransfer;
163         }
164       }
165     } catch(ex) {
166       result = ex;
167     }
168     event.preventDefault();
169     event.stopPropagation();
170   }
171   aWindow.addEventListener("dragstart", trapDrag, false);
172   synthesizeMouse(element, x, y, { type: "mousedown" }, aWindow);
173   x += step; y += step;
174   synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow);
175   x += step; y += step;
176   synthesizeMouse(element, x, y, { type: "mousemove" }, aWindow);
177   aWindow.removeEventListener("dragstart", trapDrag, false);
178   synthesizeMouse(element, x, y, { type: "mouseup" }, aWindow);
179   return result;
183  * Emulate a drop by emulating a dragstart and firing events dragenter, dragover, and drop.
184  *  srcElement - the element to use to start the drag, usually the same as destElement
185  *               but if destElement isn't suitable to start a drag on pass a suitable
186  *               element for srcElement
187  *  destElement - the element to fire the dragover, dragleave and drop events
188  *  dragData - the data to supply for the data transfer
189  *                     This data is in the format:
190  *                       [ [ {type: value, data: value}, ...], ... ]
191  *  dropEffect - the drop effect to set during the dragstart event, or 'move' if null
192  *  aWindow - optional; defaults to the current window object.
193  *  eventUtils - optional; allows you to pass in a reference to EventUtils.js. 
194  *               If the eventUtils parameter is not passed in, we assume EventUtils.js is 
195  *               in the scope. Used by browser-chrome tests.
197  * Returns the drop effect that was desired.
198  */
199 function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, eventUtils)
201   if (!aWindow)
202     aWindow = window;
204   var synthesizeMouseAtCenter = (eventUtils || window).synthesizeMouseAtCenter;
205   var synthesizeMouse = (eventUtils || window).synthesizeMouse;
207   var gWindowUtils  = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
208                              getInterface(Components.interfaces.nsIDOMWindowUtils);
209   var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
210            getService(Components.interfaces.nsIDragService);
212   var dataTransfer;
213   var trapDrag = function(event) {
214     dataTransfer = event.dataTransfer;
215     for (var i = 0; i < dragData.length; i++) {
216       var item = dragData[i];
217       for (var j = 0; j < item.length; j++) {
218         dataTransfer.mozSetDataAt(item[j].type, item[j].data, i);
219       }
220     }
221     dataTransfer.dropEffect = dropEffect || "move";
222     event.preventDefault();
223     event.stopPropagation();
224   }
226   ds.startDragSession();
228   try {
229     // need to use real mouse action
230     aWindow.addEventListener("dragstart", trapDrag, true);
231     synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow);
233     var rect = srcElement.getBoundingClientRect();
234     var x = rect.width / 2;
235     var y = rect.height / 2;
236     synthesizeMouse(srcElement, x, y, { type: "mousemove" }, aWindow);
237     synthesizeMouse(srcElement, x+10, y+10, { type: "mousemove" }, aWindow);
238     aWindow.removeEventListener("dragstart", trapDrag, true);
240     event = aWindow.document.createEvent("DragEvents");
241     event.initDragEvent("dragenter", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
242     gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
244     var event = aWindow.document.createEvent("DragEvents");
245     event.initDragEvent("dragover", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
246     if (gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true)) {
247       synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow);
248       return "none";
249     }
251     if (dataTransfer.dropEffect != "none") {
252       event = aWindow.document.createEvent("DragEvents");
253       event.initDragEvent("drop", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
254       gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
255     }
257     synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow);
259     return dataTransfer.dropEffect;
260   } finally {
261     ds.endDragSession(true);
262   }
265 var PluginUtils =
267   withTestPlugin : function(callback)
268   {
269     if (typeof Components == "undefined")
270     {
271       todo(false, "Not a Mozilla-based browser");
272       return false;
273     }
275     var ph = Components.classes["@mozilla.org/plugin/host;1"]
276                        .getService(Components.interfaces.nsIPluginHost);
277     var tags = ph.getPluginTags();
279     // Find the test plugin
280     for (var i = 0; i < tags.length; i++)
281     {
282       if (tags[i].name == "Test Plug-in")
283       {
284         callback(tags[i]);
285         return true;
286       }
287     }
288     todo(false, "Need a test plugin on this platform");
289     return false;
290   }