mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound.
This commit is contained in:
commit
8b8be2a46a
@ -35,7 +35,7 @@ RUN_TIMEOUT = 1.5 * 60 * 60 # 1.5 Hour
|
||||
# Maximum time we'll wait for tests to emit output, in seconds.
|
||||
# The purpose of this timeout is to recover from hangs. It should be longer
|
||||
# than the amount of time any test takes to report results.
|
||||
OUTPUT_TIMEOUT = 60 # one minute
|
||||
OUTPUT_TIMEOUT = 60 * 5 # five minutes
|
||||
|
||||
def follow_file(filename):
|
||||
"""
|
||||
|
@ -30,27 +30,37 @@ if (app.is('Firefox')) {
|
||||
url: 'about:addons',
|
||||
onReady: function(tab) {
|
||||
tab.attach({
|
||||
contentScript: 'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
|
||||
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
|
||||
'self.postMessage({\n' +
|
||||
'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[title=\'some-title\']")),\n' +
|
||||
'myInteger: getAttributes(unsafeWindow.document.querySelector("setting[title=\'my-int\']")),\n' +
|
||||
'myHiddenInt: getAttributes(unsafeWindow.document.querySelector("setting[title=\'hidden-int\']"))\n' +
|
||||
'});\n' +
|
||||
'}, 250);\n' +
|
||||
'}, false);\n' +
|
||||
'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
|
||||
'});\n' +
|
||||
'function getAttributes(ele) {\n' +
|
||||
'if (!ele) return {};\n' +
|
||||
'return {\n' +
|
||||
'pref: ele.getAttribute("pref"),\n' +
|
||||
'type: ele.getAttribute("type"),\n' +
|
||||
'title: ele.getAttribute("title"),\n' +
|
||||
'desc: ele.getAttribute("desc")\n' +
|
||||
contentScriptWhen: 'end',
|
||||
contentScript: 'function onLoad() {\n' +
|
||||
'unsafeWindow.removeEventListener("load", onLoad, false);\n' +
|
||||
'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
|
||||
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
|
||||
'self.postMessage({\n' +
|
||||
'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[title=\'some-title\']")),\n' +
|
||||
'myInteger: getAttributes(unsafeWindow.document.querySelector("setting[title=\'my-int\']")),\n' +
|
||||
'myHiddenInt: getAttributes(unsafeWindow.document.querySelector("setting[title=\'hidden-int\']"))\n' +
|
||||
'});\n' +
|
||||
'}, 250);\n' +
|
||||
'}, false);\n' +
|
||||
'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
|
||||
'});\n' +
|
||||
'function getAttributes(ele) {\n' +
|
||||
'if (!ele) return {};\n' +
|
||||
'return {\n' +
|
||||
'pref: ele.getAttribute("pref"),\n' +
|
||||
'type: ele.getAttribute("type"),\n' +
|
||||
'title: ele.getAttribute("title"),\n' +
|
||||
'desc: ele.getAttribute("desc")\n' +
|
||||
'}\n' +
|
||||
'}\n' +
|
||||
'}\n' +
|
||||
// Wait for the load event ?
|
||||
'if (document.readyState == "complete") {\n' +
|
||||
'onLoad()\n' +
|
||||
'} else {\n' +
|
||||
'unsafeWindow.addEventListener("load", onLoad, false);\n' +
|
||||
'}\n',
|
||||
onMessage: function(msg) {
|
||||
// test somePreference
|
||||
|
@ -834,18 +834,29 @@ exports.testAttachUnwrapped = function (test) {
|
||||
|
||||
exports['test window focus changes active tab'] = function(test) {
|
||||
test.waitUntilDone();
|
||||
|
||||
let url1 = "data:text/html;charset=utf-8," + encodeURIComponent("test window focus changes active tab</br><h1>Window #1");
|
||||
|
||||
let win1 = openBrowserWindow(function() {
|
||||
test.pass("window 1 is open");
|
||||
|
||||
let win2 = openBrowserWindow(function() {
|
||||
tabs.on("activate", function onActivate() {
|
||||
test.pass("window 2 is open");
|
||||
|
||||
tabs.on("activate", function onActivate(tab) {
|
||||
tabs.removeListener("activate", onActivate);
|
||||
test.pass("activate was called on windows focus change.");
|
||||
closeBrowserWindow(win1, function() {
|
||||
closeBrowserWindow(win2, function() { test.done(); });
|
||||
});
|
||||
test.assertEqual(tab.url, url1, 'the activated tab url is correct');
|
||||
|
||||
close(win2).then(function() {
|
||||
test.pass('window 2 was closed');
|
||||
return close(win1);
|
||||
}).then(test.done.bind(test));
|
||||
});
|
||||
|
||||
win1.focus();
|
||||
}, "data:text/html;charset=utf-8,test window focus changes active tab</br><h1>Window #2");
|
||||
}, "data:text/html;charset=utf-8,test window focus changes active tab</br><h1>Window #1");
|
||||
}, url1);
|
||||
};
|
||||
|
||||
exports['test ready event on new window tab'] = function(test) {
|
||||
|
@ -129,11 +129,12 @@ exports["test Show Hide Panel"] = function(assert, done) {
|
||||
exports["test Document Reload"] = function(assert, done) {
|
||||
const { Panel } = require('sdk/panel');
|
||||
|
||||
let url2 = "data:text/html;charset=utf-8,page2";
|
||||
let content =
|
||||
"<script>" +
|
||||
"window.onload = function() {" +
|
||||
" setTimeout(function () {" +
|
||||
" window.location = 'about:blank';" +
|
||||
" window.location = '" + url2 + "';" +
|
||||
" }, 0);" +
|
||||
"}" +
|
||||
"</script>";
|
||||
@ -144,11 +145,13 @@ exports["test Document Reload"] = function(assert, done) {
|
||||
contentScript: "self.postMessage(window.location.href)",
|
||||
onMessage: function (message) {
|
||||
messageCount++;
|
||||
assert.notEqual(message, 'about:blank', 'about:blank is not a message ' + messageCount);
|
||||
|
||||
if (messageCount == 1) {
|
||||
assert.ok(/data:text\/html/.test(message), "First document had a content script " + message);
|
||||
}
|
||||
else if (messageCount == 2) {
|
||||
assert.equal(message, "about:blank", "Second document too");
|
||||
assert.equal(message, url2, "Second document too");
|
||||
panel.destroy();
|
||||
done();
|
||||
}
|
||||
|
@ -301,7 +301,10 @@ let FormAssistant = {
|
||||
break;
|
||||
}
|
||||
|
||||
if (target instanceof HTMLDocument || target == content) {
|
||||
if (target instanceof HTMLDocument ||
|
||||
// Bug 811177, we don't support editing the entire document.
|
||||
target instanceof HTMLBodyElement ||
|
||||
target == content) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -335,12 +338,20 @@ let FormAssistant = {
|
||||
break;
|
||||
|
||||
case 'mousedown':
|
||||
if (!this.focusedElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We only listen for this event on the currently focused element.
|
||||
// When the mouse goes down, note the cursor/selection position
|
||||
this.updateSelection();
|
||||
break;
|
||||
|
||||
case 'mouseup':
|
||||
if (!this.focusedElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We only listen for this event on the currently focused element.
|
||||
// When the mouse goes up, see if the cursor has moved (or the
|
||||
// selection changed) since the mouse went down. If it has, we
|
||||
@ -524,11 +535,8 @@ let FormAssistant = {
|
||||
}
|
||||
|
||||
case "Forms:GetText": {
|
||||
let isPlainTextField = target instanceof HTMLInputElement ||
|
||||
target instanceof HTMLTextAreaElement;
|
||||
let value = isPlainTextField ?
|
||||
target.value :
|
||||
getContentEditableText(target);
|
||||
let value = isContentEditable(target) ? getContentEditableText(target)
|
||||
: target.value;
|
||||
|
||||
if (json.offset && json.length) {
|
||||
value = value.substr(json.offset, json.length);
|
||||
@ -633,12 +641,8 @@ let FormAssistant = {
|
||||
let element = this.focusedElement;
|
||||
let range = getSelectionRange(element);
|
||||
|
||||
let isPlainTextField = element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement;
|
||||
|
||||
let text = isPlainTextField ?
|
||||
element.value :
|
||||
getContentEditableText(element);
|
||||
let text = isContentEditable(element) ? getContentEditableText(element)
|
||||
: element.value;
|
||||
|
||||
let textAround = getTextAroundCursor(text, range);
|
||||
|
||||
@ -691,6 +695,15 @@ function isContentEditable(element) {
|
||||
return element.ownerDocument && element.ownerDocument.designMode == "on";
|
||||
}
|
||||
|
||||
function isPlainTextField(element) {
|
||||
if (!element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement;
|
||||
}
|
||||
|
||||
function getJSON(element, focusCounter) {
|
||||
let type = element.type || "";
|
||||
let value = element.value || "";
|
||||
@ -832,7 +845,7 @@ function getDocumentEncoder(element) {
|
||||
|
||||
// Get the visible content text of a content editable element
|
||||
function getContentEditableText(element) {
|
||||
if (!element) {
|
||||
if (!element || !isContentEditable(element)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -847,8 +860,7 @@ function getContentEditableText(element) {
|
||||
function getSelectionRange(element) {
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
if (element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement) {
|
||||
if (isPlainTextField(element)) {
|
||||
// Get the selection range of <input> and <textarea> elements
|
||||
start = element.selectionStart;
|
||||
end = element.selectionEnd;
|
||||
@ -856,8 +868,12 @@ function getSelectionRange(element) {
|
||||
// Get the selection range of contenteditable elements
|
||||
let win = element.ownerDocument.defaultView;
|
||||
let sel = win.getSelection();
|
||||
start = getContentEditableSelectionStart(element, sel);
|
||||
end = start + getContentEditableSelectionLength(element, sel);
|
||||
if (sel) {
|
||||
start = getContentEditableSelectionStart(element, sel);
|
||||
end = start + getContentEditableSelectionLength(element, sel);
|
||||
} else {
|
||||
dump("Failed to get window.getSelection()\n");
|
||||
}
|
||||
}
|
||||
return [start, end];
|
||||
}
|
||||
@ -879,18 +895,17 @@ function getContentEditableSelectionLength(element, selection) {
|
||||
}
|
||||
|
||||
function setSelectionRange(element, start, end) {
|
||||
let isPlainTextField = element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement;
|
||||
let isTextField = isPlainTextField(element);
|
||||
|
||||
// Check the parameters
|
||||
|
||||
if (!isPlainTextField && !isContentEditable(element)) {
|
||||
if (!isTextField && !isContentEditable(element)) {
|
||||
// Skip HTMLOptionElement and HTMLSelectElement elements, as they don't
|
||||
// support the operation of setSelectionRange
|
||||
return;
|
||||
}
|
||||
|
||||
let text = isPlainTextField ? element.value : getContentEditableText(element);
|
||||
let text = isTextField ? element.value : getContentEditableText(element);
|
||||
let length = text.length;
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
@ -902,7 +917,7 @@ function setSelectionRange(element, start, end) {
|
||||
start = end;
|
||||
}
|
||||
|
||||
if (isPlainTextField) {
|
||||
if (isTextField) {
|
||||
// Set the selection range of <input> and <textarea> elements
|
||||
element.setSelectionRange(start, end, "forward");
|
||||
} else {
|
||||
@ -936,8 +951,7 @@ function setSelectionRange(element, start, end) {
|
||||
function getPlaintextEditor(element) {
|
||||
let editor = null;
|
||||
// Get nsIEditor
|
||||
if (element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement) {
|
||||
if (isPlainTextField(element)) {
|
||||
// Get from the <input> and <textarea> elements
|
||||
editor = element.QueryInterface(Ci.nsIDOMNSEditableElement).editor;
|
||||
} else if (isContentEditable(element)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "47daabb93939a38f1f8efa7fdb1cd22ef8445600",
|
||||
"revision": "58c6fafc2ed4884ccc1617896f3371bc2762c75e",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -7,9 +7,7 @@
|
||||
}
|
||||
|
||||
.highlighter-controls {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.highlighter-outline-container {
|
||||
|
@ -222,8 +222,9 @@ if test "$CPU_ARCH" = "arm"; then
|
||||
dnl This matches media/webrtc/trunk/webrtc/build/common.gypi.
|
||||
if test -n "$ARM_ARCH"; then
|
||||
if test "$ARM_ARCH" -lt 7; then
|
||||
BUILD_ARM_NEON=0
|
||||
BUILD_ARM_NEON=
|
||||
else
|
||||
AC_DEFINE(BUILD_ARM_NEON)
|
||||
BUILD_ARM_NEON=1
|
||||
fi
|
||||
fi
|
||||
|
@ -706,6 +706,7 @@ GK_ATOM(ondragover, "ondragover")
|
||||
GK_ATOM(ondragstart, "ondragstart")
|
||||
GK_ATOM(ondrop, "ondrop")
|
||||
GK_ATOM(onenabled, "onenabled")
|
||||
GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
|
||||
GK_ATOM(onerror, "onerror")
|
||||
GK_ATOM(onfailed, "onfailed")
|
||||
GK_ATOM(onfocus, "onfocus")
|
||||
|
@ -1544,35 +1544,6 @@ nsEventStateManager::GetChildProcessOffset(nsFrameLoader* aFrameLoader,
|
||||
return LayoutDeviceIntPoint::FromAppUnitsToNearest(pt, presContext->AppUnitsPerDevPixel());
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
nsEventStateManager::MapEventCoordinatesForChildProcess(
|
||||
const LayoutDeviceIntPoint& aOffset, nsEvent* aEvent)
|
||||
{
|
||||
if (aEvent->eventStructType != NS_TOUCH_EVENT) {
|
||||
aEvent->refPoint = aOffset;
|
||||
} else {
|
||||
aEvent->refPoint = LayoutDeviceIntPoint();
|
||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||
// Then offset all the touch points by that distance, to put them
|
||||
// in the space where top-left is 0,0.
|
||||
const nsTArray< nsRefPtr<Touch> >& touches = touchEvent->touches;
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
Touch* touch = touches[i];
|
||||
if (touch) {
|
||||
touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
nsEventStateManager::MapEventCoordinatesForChildProcess(nsFrameLoader* aFrameLoader,
|
||||
nsEvent* aEvent)
|
||||
{
|
||||
LayoutDeviceIntPoint offset = GetChildProcessOffset(aFrameLoader, *aEvent);
|
||||
MapEventCoordinatesForChildProcess(offset, aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
CrossProcessSafeEvent(const nsEvent& aEvent)
|
||||
{
|
||||
@ -1686,8 +1657,6 @@ nsEventStateManager::HandleCrossProcessEvent(nsEvent *aEvent,
|
||||
continue;
|
||||
}
|
||||
|
||||
MapEventCoordinatesForChildProcess(frameLoader, aEvent);
|
||||
|
||||
dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
|
||||
}
|
||||
return dispatched;
|
||||
|
@ -197,12 +197,6 @@ public:
|
||||
static LayoutDeviceIntPoint GetChildProcessOffset(nsFrameLoader* aFrameLoader,
|
||||
const nsEvent& aEvent);
|
||||
|
||||
static void MapEventCoordinatesForChildProcess(nsFrameLoader* aFrameLoader,
|
||||
nsEvent* aEvent);
|
||||
|
||||
static void MapEventCoordinatesForChildProcess(const LayoutDeviceIntPoint& aOffset,
|
||||
nsEvent* aEvent);
|
||||
|
||||
// Holds the point in screen coords that a mouse event was dispatched to,
|
||||
// before we went into pointer lock mode. This is constantly updated while
|
||||
// the pointer is not locked, but we don't update it while the pointer is
|
||||
|
@ -4,7 +4,11 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/arm.h"
|
||||
#include "AudioNodeEngine.h"
|
||||
#ifdef BUILD_ARM_NEON
|
||||
#include "AudioNodeEngineNEON.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -58,6 +62,12 @@ void AudioBufferAddWithScale(const float* aInput,
|
||||
float* aOutput,
|
||||
uint32_t aSize)
|
||||
{
|
||||
#ifdef BUILD_ARM_NEON
|
||||
if (mozilla::supports_neon()) {
|
||||
AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (aScale == 1.0f) {
|
||||
for (uint32_t i = 0; i < aSize; ++i) {
|
||||
aOutput[i] += aInput[i];
|
||||
@ -85,6 +95,12 @@ AudioBlockCopyChannelWithScale(const float* aInput,
|
||||
if (aScale == 1.0f) {
|
||||
memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE*sizeof(float));
|
||||
} else {
|
||||
#ifdef BUILD_ARM_NEON
|
||||
if (mozilla::supports_neon()) {
|
||||
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
|
||||
aOutput[i] = aInput[i]*aScale;
|
||||
}
|
||||
@ -114,6 +130,12 @@ AudioBlockCopyChannelWithScale(const float aInput[WEBAUDIO_BLOCK_SIZE],
|
||||
const float aScale[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutput[WEBAUDIO_BLOCK_SIZE])
|
||||
{
|
||||
#ifdef BUILD_ARM_NEON
|
||||
if (mozilla::supports_neon()) {
|
||||
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
|
||||
aOutput[i] = aInput[i]*aScale[i];
|
||||
}
|
||||
@ -136,6 +158,12 @@ AudioBufferInPlaceScale(float* aBlock,
|
||||
if (aScale == 1.0f) {
|
||||
return;
|
||||
}
|
||||
#ifdef BUILD_ARM_NEON
|
||||
if (mozilla::supports_neon()) {
|
||||
AudioBufferInPlaceScale_NEON(aBlock, aChannelCount, aScale, aSize);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (uint32_t i = 0; i < aSize * aChannelCount; ++i) {
|
||||
*aBlock++ *= aScale;
|
||||
}
|
||||
@ -158,6 +186,15 @@ AudioBlockPanStereoToStereo(const float aInputL[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutputL[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutputR[WEBAUDIO_BLOCK_SIZE])
|
||||
{
|
||||
#ifdef BUILD_ARM_NEON
|
||||
if (mozilla::supports_neon()) {
|
||||
AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
|
||||
aGainL, aGainR, aIsOnTheLeft,
|
||||
aOutputL, aOutputR);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t i;
|
||||
|
||||
if (aIsOnTheLeft) {
|
||||
|
250
content/media/AudioNodeEngineNEON.cpp
Normal file
250
content/media/AudioNodeEngineNEON.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* this source code form is subject to the terms of the mozilla public
|
||||
* license, v. 2.0. if a copy of the mpl was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AudioNodeEngineNEON.h"
|
||||
#include <arm_neon.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ASSERT_ALIGNED(ptr) \
|
||||
MOZ_ASSERT((((uintptr_t)ptr + 15) & ~0x0F) == (uintptr_t)ptr, \
|
||||
#ptr " has to be aligned 16-bytes aligned.");
|
||||
#else
|
||||
#define ASSERT_ALIGNED(ptr)
|
||||
#endif
|
||||
|
||||
#define ADDRESS_OF(array, index) ((float32_t*)&array[index])
|
||||
|
||||
namespace mozilla {
|
||||
void AudioBufferAddWithScale_NEON(const float* aInput,
|
||||
float aScale,
|
||||
float* aOutput,
|
||||
uint32_t aSize)
|
||||
{
|
||||
ASSERT_ALIGNED(aInput);
|
||||
ASSERT_ALIGNED(aOutput);
|
||||
|
||||
float32x4_t vin0, vin1, vin2, vin3;
|
||||
float32x4_t vout0, vout1, vout2, vout3;
|
||||
float32x4_t vscale = vmovq_n_f32(aScale);
|
||||
|
||||
uint32_t dif = aSize % 16;
|
||||
aSize -= dif;
|
||||
unsigned i = 0;
|
||||
for (; i < aSize; i+=16) {
|
||||
vin0 = vld1q_f32(ADDRESS_OF(aInput, i));
|
||||
vin1 = vld1q_f32(ADDRESS_OF(aInput, i+4));
|
||||
vin2 = vld1q_f32(ADDRESS_OF(aInput, i+8));
|
||||
vin3 = vld1q_f32(ADDRESS_OF(aInput, i+12));
|
||||
|
||||
vout0 = vld1q_f32(ADDRESS_OF(aOutput, i));
|
||||
vout1 = vld1q_f32(ADDRESS_OF(aOutput, i+4));
|
||||
vout2 = vld1q_f32(ADDRESS_OF(aOutput, i+8));
|
||||
vout3 = vld1q_f32(ADDRESS_OF(aOutput, i+12));
|
||||
|
||||
vout0 = vmlaq_f32(vout0, vin0, vscale);
|
||||
vout1 = vmlaq_f32(vout1, vin1, vscale);
|
||||
vout2 = vmlaq_f32(vout2, vin2, vscale);
|
||||
vout3 = vmlaq_f32(vout3, vin3, vscale);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i), vout0);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+4), vout1);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+8), vout2);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+12), vout3);
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < dif; ++i, ++j) {
|
||||
aOutput[i] += aInput[i]*aScale;
|
||||
}
|
||||
}
|
||||
void
|
||||
AudioBlockCopyChannelWithScale_NEON(const float* aInput,
|
||||
float aScale,
|
||||
float* aOutput)
|
||||
{
|
||||
ASSERT_ALIGNED(aInput);
|
||||
ASSERT_ALIGNED(aOutput);
|
||||
|
||||
float32x4_t vin0, vin1, vin2, vin3;
|
||||
float32x4_t vout0, vout1, vout2, vout3;
|
||||
float32x4_t vscale = vmovq_n_f32(aScale);
|
||||
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
|
||||
vin0 = vld1q_f32(ADDRESS_OF(aInput, i));
|
||||
vin1 = vld1q_f32(ADDRESS_OF(aInput, i+4));
|
||||
vin2 = vld1q_f32(ADDRESS_OF(aInput, i+8));
|
||||
vin3 = vld1q_f32(ADDRESS_OF(aInput, i+12));
|
||||
|
||||
vout0 = vmulq_f32(vin0, vscale);
|
||||
vout1 = vmulq_f32(vin1, vscale);
|
||||
vout2 = vmulq_f32(vin2, vscale);
|
||||
vout3 = vmulq_f32(vin3, vscale);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i), vout0);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+4), vout1);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+8), vout2);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+12), vout3);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioBlockCopyChannelWithScale_NEON(const float aInput[WEBAUDIO_BLOCK_SIZE],
|
||||
const float aScale[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutput[WEBAUDIO_BLOCK_SIZE])
|
||||
{
|
||||
ASSERT_ALIGNED(aInput);
|
||||
ASSERT_ALIGNED(aScale);
|
||||
ASSERT_ALIGNED(aOutput);
|
||||
|
||||
float32x4_t vin0, vin1, vin2, vin3;
|
||||
float32x4_t vout0, vout1, vout2, vout3;
|
||||
float32x4_t vscale0, vscale1, vscale2, vscale3;
|
||||
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
|
||||
vin0 = vld1q_f32(ADDRESS_OF(aInput, i));
|
||||
vin1 = vld1q_f32(ADDRESS_OF(aInput, i+4));
|
||||
vin2 = vld1q_f32(ADDRESS_OF(aInput, i+8));
|
||||
vin3 = vld1q_f32(ADDRESS_OF(aInput, i+12));
|
||||
|
||||
vscale0 = vld1q_f32(ADDRESS_OF(aScale, i));
|
||||
vscale1 = vld1q_f32(ADDRESS_OF(aScale, i+4));
|
||||
vscale2 = vld1q_f32(ADDRESS_OF(aScale, i+8));
|
||||
vscale3 = vld1q_f32(ADDRESS_OF(aScale, i+12));
|
||||
|
||||
vout0 = vmulq_f32(vin0, vscale0);
|
||||
vout1 = vmulq_f32(vin1, vscale1);
|
||||
vout2 = vmulq_f32(vin2, vscale2);
|
||||
vout3 = vmulq_f32(vin3, vscale3);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i), vout0);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+4), vout1);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+8), vout2);
|
||||
vst1q_f32(ADDRESS_OF(aOutput, i+12), vout3);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioBufferInPlaceScale_NEON(float* aBlock,
|
||||
uint32_t aChannelCount,
|
||||
float aScale,
|
||||
uint32_t aSize)
|
||||
{
|
||||
ASSERT_ALIGNED(aBlock);
|
||||
|
||||
float32x4_t vin0, vin1, vin2, vin3;
|
||||
float32x4_t vout0, vout1, vout2, vout3;
|
||||
float32x4_t vscale = vmovq_n_f32(aScale);
|
||||
|
||||
uint32_t totalSize = aSize * aChannelCount;
|
||||
uint32_t dif = totalSize % 16;
|
||||
totalSize -= dif;
|
||||
uint32_t i = 0;
|
||||
for (; i < totalSize; i+=16) {
|
||||
vin0 = vld1q_f32(ADDRESS_OF(aBlock, i));
|
||||
vin1 = vld1q_f32(ADDRESS_OF(aBlock, i+4));
|
||||
vin2 = vld1q_f32(ADDRESS_OF(aBlock, i+8));
|
||||
vin3 = vld1q_f32(ADDRESS_OF(aBlock, i+12));
|
||||
|
||||
vout0 = vmulq_f32(vin0, vscale);
|
||||
vout1 = vmulq_f32(vin1, vscale);
|
||||
vout2 = vmulq_f32(vin2, vscale);
|
||||
vout3 = vmulq_f32(vin3, vscale);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aBlock, i), vout0);
|
||||
vst1q_f32(ADDRESS_OF(aBlock, i+4), vout1);
|
||||
vst1q_f32(ADDRESS_OF(aBlock, i+8), vout2);
|
||||
vst1q_f32(ADDRESS_OF(aBlock, i+12), vout3);
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < dif; ++i, ++j) {
|
||||
aBlock[i] *= aScale;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioBlockPanStereoToStereo_NEON(const float aInputL[WEBAUDIO_BLOCK_SIZE],
|
||||
const float aInputR[WEBAUDIO_BLOCK_SIZE],
|
||||
float aGainL, float aGainR, bool aIsOnTheLeft,
|
||||
float aOutputL[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutputR[WEBAUDIO_BLOCK_SIZE])
|
||||
{
|
||||
ASSERT_ALIGNED(aInputL);
|
||||
ASSERT_ALIGNED(aInputR);
|
||||
ASSERT_ALIGNED(aOutputL);
|
||||
ASSERT_ALIGNED(aOutputR);
|
||||
|
||||
float32x4_t vinL0, vinL1, vinL2, vinL3;
|
||||
float32x4_t vinR0, vinR1, vinR2, vinR3;
|
||||
float32x4_t voutL0, voutL1, voutL2, voutL3;
|
||||
float32x4_t voutR0, voutR1, voutR2, voutR3;
|
||||
float32x4_t vscaleL = vmovq_n_f32(aGainL);
|
||||
float32x4_t vscaleR = vmovq_n_f32(aGainR);
|
||||
|
||||
if (aIsOnTheLeft) {
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
|
||||
vinL0 = vld1q_f32(ADDRESS_OF(aInputL, i));
|
||||
vinL1 = vld1q_f32(ADDRESS_OF(aInputL, i+4));
|
||||
vinL2 = vld1q_f32(ADDRESS_OF(aInputL, i+8));
|
||||
vinL3 = vld1q_f32(ADDRESS_OF(aInputL, i+12));
|
||||
|
||||
vinR0 = vld1q_f32(ADDRESS_OF(aInputR, i));
|
||||
vinR1 = vld1q_f32(ADDRESS_OF(aInputR, i+4));
|
||||
vinR2 = vld1q_f32(ADDRESS_OF(aInputR, i+8));
|
||||
vinR3 = vld1q_f32(ADDRESS_OF(aInputR, i+12));
|
||||
|
||||
voutL0 = vmlaq_f32(vinL0, vinR0, vscaleL);
|
||||
voutL1 = vmlaq_f32(vinL1, vinR1, vscaleL);
|
||||
voutL2 = vmlaq_f32(vinL2, vinR2, vscaleL);
|
||||
voutL3 = vmlaq_f32(vinL3, vinR3, vscaleL);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i), voutL0);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+4), voutL1);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+8), voutL2);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+12), voutL3);
|
||||
|
||||
voutR0 = vmulq_f32(vinR0, vscaleR);
|
||||
voutR1 = vmulq_f32(vinR1, vscaleR);
|
||||
voutR2 = vmulq_f32(vinR2, vscaleR);
|
||||
voutR3 = vmulq_f32(vinR3, vscaleR);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i), voutR0);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+4), voutR1);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+8), voutR2);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+12), voutR3);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
|
||||
vinL0 = vld1q_f32(ADDRESS_OF(aInputL, i));
|
||||
vinL1 = vld1q_f32(ADDRESS_OF(aInputL, i+4));
|
||||
vinL2 = vld1q_f32(ADDRESS_OF(aInputL, i+8));
|
||||
vinL3 = vld1q_f32(ADDRESS_OF(aInputL, i+12));
|
||||
|
||||
vinR0 = vld1q_f32(ADDRESS_OF(aInputR, i));
|
||||
vinR1 = vld1q_f32(ADDRESS_OF(aInputR, i+4));
|
||||
vinR2 = vld1q_f32(ADDRESS_OF(aInputR, i+8));
|
||||
vinR3 = vld1q_f32(ADDRESS_OF(aInputR, i+12));
|
||||
|
||||
voutL0 = vmulq_f32(vinL0, vscaleL);
|
||||
voutL1 = vmulq_f32(vinL1, vscaleL);
|
||||
voutL2 = vmulq_f32(vinL2, vscaleL);
|
||||
voutL3 = vmulq_f32(vinL3, vscaleL);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i), voutL0);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+4), voutL1);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+8), voutL2);
|
||||
vst1q_f32(ADDRESS_OF(aOutputL, i+12), voutL3);
|
||||
|
||||
voutR0 = vmlaq_f32(vinR0, vinL0, vscaleR);
|
||||
voutR1 = vmlaq_f32(vinR1, vinL1, vscaleR);
|
||||
voutR2 = vmlaq_f32(vinR2, vinL2, vscaleR);
|
||||
voutR3 = vmlaq_f32(vinR3, vinL3, vscaleR);
|
||||
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i), voutR0);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+4), voutR1);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+8), voutR2);
|
||||
vst1q_f32(ADDRESS_OF(aOutputR, i+12), voutR3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
content/media/AudioNodeEngineNEON.h
Normal file
41
content/media/AudioNodeEngineNEON.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* this source code form is subject to the terms of the mozilla public
|
||||
* license, v. 2.0. if a copy of the mpl was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_AUDIONODEENGINENEON_H_
|
||||
#define MOZILLA_AUDIONODEENGINENEON_H_
|
||||
|
||||
#include "AudioNodeEngine.h"
|
||||
|
||||
namespace mozilla {
|
||||
void AudioBufferAddWithScale_NEON(const float* aInput,
|
||||
float aScale,
|
||||
float* aOutput,
|
||||
uint32_t aSize);
|
||||
|
||||
void
|
||||
AudioBlockCopyChannelWithScale_NEON(const float* aInput,
|
||||
float aScale,
|
||||
float* aOutput);
|
||||
|
||||
void
|
||||
AudioBlockCopyChannelWithScale_NEON(const float aInput[WEBAUDIO_BLOCK_SIZE],
|
||||
const float aScale[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutput[WEBAUDIO_BLOCK_SIZE]);
|
||||
|
||||
void
|
||||
AudioBufferInPlaceScale_NEON(float* aBlock,
|
||||
uint32_t aChannelCount,
|
||||
float aScale,
|
||||
uint32_t aSize);
|
||||
|
||||
void
|
||||
AudioBlockPanStereoToStereo_NEON(const float aInputL[WEBAUDIO_BLOCK_SIZE],
|
||||
const float aInputR[WEBAUDIO_BLOCK_SIZE],
|
||||
float aGainL, float aGainR, bool aIsOnTheLeft,
|
||||
float aOutputL[WEBAUDIO_BLOCK_SIZE],
|
||||
float aOutputR[WEBAUDIO_BLOCK_SIZE]);
|
||||
}
|
||||
|
||||
#endif /* MOZILLA_AUDIONODEENGINENEON_H_ */
|
@ -29,3 +29,5 @@ endif
|
||||
|
||||
CFLAGS += $(GSTREAMER_CFLAGS)
|
||||
CXXFLAGS += $(GSTREAMER_CFLAGS)
|
||||
|
||||
AudioNodeEngineNEON.$(OBJ_SUFFIX): CXXFLAGS += -mfpu=neon
|
||||
|
@ -272,11 +272,10 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
|
||||
if (!chunk.IsNull()) {
|
||||
// Append the interleaved data to the end of pcm buffer.
|
||||
InterleaveTrackData(chunk, frameToCopy, mChannels,
|
||||
pcm.Elements() + frameCopied);
|
||||
pcm.Elements() + frameCopied * mChannels);
|
||||
} else {
|
||||
for (int i = 0; i < frameToCopy * mChannels; i++) {
|
||||
pcm.AppendElement(0);
|
||||
}
|
||||
memset(pcm.Elements() + frameCopied * mChannels, 0,
|
||||
frameToCopy * mChannels * sizeof(AudioDataValue));
|
||||
}
|
||||
|
||||
frameCopied += frameToCopy;
|
||||
@ -301,9 +300,8 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
|
||||
// Append null data to pcm buffer if the leftover data is not enough for
|
||||
// opus encoder.
|
||||
if (frameCopied < GetPacketDuration() && mEndOfStream) {
|
||||
for (int i = frameCopied * mChannels; i < GetPacketDuration() * mChannels; i++) {
|
||||
pcm.AppendElement(0);
|
||||
}
|
||||
memset(pcm.Elements() + frameCopied * mChannels, 0,
|
||||
(GetPacketDuration()-frameCopied)*mChannels*sizeof(AudioDataValue));
|
||||
}
|
||||
|
||||
// Encode the data with Opus Encoder.
|
||||
|
@ -130,3 +130,8 @@ CPP_SOURCES += [
|
||||
'VideoUtils.cpp',
|
||||
'WebVTTLoadListener.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
|
||||
CPP_SOURCES += [
|
||||
'AudioNodeEngineNEON.cpp',
|
||||
]
|
||||
|
@ -599,6 +599,39 @@ TabParent::SendKeyEvent(const nsAString& aType,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::MapEventCoordinatesForChildProcess(nsEvent* aEvent)
|
||||
{
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
if (!frameLoader) {
|
||||
return false;
|
||||
}
|
||||
LayoutDeviceIntPoint offset = nsEventStateManager::GetChildProcessOffset(frameLoader, *aEvent);
|
||||
MapEventCoordinatesForChildProcess(offset, aEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::MapEventCoordinatesForChildProcess(
|
||||
const LayoutDeviceIntPoint& aOffset, nsEvent* aEvent)
|
||||
{
|
||||
if (aEvent->eventStructType != NS_TOUCH_EVENT) {
|
||||
aEvent->refPoint = aOffset;
|
||||
} else {
|
||||
aEvent->refPoint = LayoutDeviceIntPoint();
|
||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||
// Then offset all the touch points by that distance, to put them
|
||||
// in the space where top-left is 0,0.
|
||||
const nsTArray< nsRefPtr<Touch> >& touches = touchEvent->touches;
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
Touch* touch = touches[i];
|
||||
if (touch) {
|
||||
touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TabParent::SendRealMouseEvent(nsMouseEvent& event)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
@ -606,6 +639,9 @@ bool TabParent::SendRealMouseEvent(nsMouseEvent& event)
|
||||
}
|
||||
nsMouseEvent e(event);
|
||||
MaybeForwardEventToRenderFrame(event, &e);
|
||||
if (!MapEventCoordinatesForChildProcess(&e)) {
|
||||
return false;
|
||||
}
|
||||
return PBrowserParent::SendRealMouseEvent(e);
|
||||
}
|
||||
|
||||
@ -616,6 +652,9 @@ bool TabParent::SendMouseWheelEvent(WheelEvent& event)
|
||||
}
|
||||
WheelEvent e(event);
|
||||
MaybeForwardEventToRenderFrame(event, &e);
|
||||
if (!MapEventCoordinatesForChildProcess(&e)) {
|
||||
return false;
|
||||
}
|
||||
return PBrowserParent::SendMouseWheelEvent(event);
|
||||
}
|
||||
|
||||
@ -626,6 +665,9 @@ bool TabParent::SendRealKeyEvent(nsKeyEvent& event)
|
||||
}
|
||||
nsKeyEvent e(event);
|
||||
MaybeForwardEventToRenderFrame(event, &e);
|
||||
if (!MapEventCoordinatesForChildProcess(&e)) {
|
||||
return false;
|
||||
}
|
||||
return PBrowserParent::SendRealKeyEvent(e);
|
||||
}
|
||||
|
||||
@ -668,6 +710,9 @@ bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
|
||||
}
|
||||
|
||||
MaybeForwardEventToRenderFrame(event, &e);
|
||||
|
||||
MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &e);
|
||||
|
||||
return (e.message == NS_TOUCH_MOVE) ?
|
||||
PBrowserParent::SendRealTouchMoveEvent(e) :
|
||||
PBrowserParent::SendRealTouchEvent(e);
|
||||
@ -704,9 +749,6 @@ TabParent::TryCapture(const nsGUIEvent& aEvent)
|
||||
return false;
|
||||
}
|
||||
|
||||
nsEventStateManager::MapEventCoordinatesForChildProcess(
|
||||
mChildProcessOffsetAtTouchStart, &event);
|
||||
|
||||
SendRealTouchEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
@ -187,6 +187,10 @@ public:
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
bool MapEventCoordinatesForChildProcess(nsEvent* aEvent);
|
||||
void MapEventCoordinatesForChildProcess(const LayoutDeviceIntPoint& aOffset,
|
||||
nsEvent* aEvent);
|
||||
|
||||
void SendMouseEvent(const nsAString& aType, float aX, float aY,
|
||||
int32_t aButton, int32_t aClickCount,
|
||||
int32_t aModifiers, bool aIgnoreRootScrollFrame);
|
||||
|
@ -21,6 +21,7 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMCFStateChangeEvent.idl',
|
||||
'nsIDOMMobileConnection.idl',
|
||||
'nsIDOMMozEmergencyCbModeEvent.idl',
|
||||
'nsIDOMNetworkStats.idl',
|
||||
'nsIDOMNetworkStatsManager.idl',
|
||||
'nsIMobileConnectionProvider.idl',
|
||||
|
@ -11,7 +11,7 @@ interface nsIDOMMozMobileNetworkInfo;
|
||||
interface nsIDOMMozMobileCellInfo;
|
||||
interface nsIDOMMozMobileCFInfo;
|
||||
|
||||
[scriptable, builtinclass, uuid(ae82dac0-d1a0-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, builtinclass, uuid(35fbab20-ee07-454d-943d-090a9378f5cf)]
|
||||
interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
{
|
||||
const long ICC_SERVICE_CLASS_VOICE = (1 << 0);
|
||||
@ -268,7 +268,7 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
*
|
||||
* @param clirMode
|
||||
* Is one of the CLIR_* constants.
|
||||
*
|
||||
*
|
||||
* If successful, the request's onsuccess will be called.
|
||||
*
|
||||
* Otherwise, the request's onerror will be called, and the request's error
|
||||
@ -289,6 +289,16 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
*/
|
||||
nsIDOMDOMRequest getCallingLineIdRestriction();
|
||||
|
||||
/**
|
||||
* Exit emergency callback mode.
|
||||
*
|
||||
* If successful, the request's onsuccess will be called.
|
||||
*
|
||||
* Otherwise, the request's onerror will be called, and the request's error
|
||||
* will be either 'RequestNotSupported' or 'GenericFailure'.
|
||||
*/
|
||||
nsIDOMDOMRequest exitEmergencyCbMode();
|
||||
|
||||
/**
|
||||
* The 'voicechange' event is notified whenever the voice connection object
|
||||
* changes.
|
||||
@ -318,6 +328,12 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget
|
||||
* state changes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval oncfstatechange;
|
||||
|
||||
/**
|
||||
* The 'emergencycbmodechange' event is notified whenever the emergency
|
||||
* callback mode changes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onemergencycbmodechange;
|
||||
};
|
||||
|
||||
[scriptable, uuid(49706beb-a160-40b7-b745-50f62e389a2c)]
|
||||
|
31
dom/network/interfaces/nsIDOMMozEmergencyCbModeEvent.idl
Normal file
31
dom/network/interfaces/nsIDOMMozEmergencyCbModeEvent.idl
Normal file
@ -0,0 +1,31 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIDOMEvent.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(15cc1010-f051-11e2-945c-60a44c237d2b)]
|
||||
interface nsIDOMMozEmergencyCbModeEvent : nsIDOMEvent
|
||||
{
|
||||
/**
|
||||
* Whether the mode is activated.
|
||||
*/
|
||||
readonly attribute boolean active;
|
||||
|
||||
/**
|
||||
* Automatically exit the mode after the timeoutMs ms.
|
||||
*/
|
||||
readonly attribute unsigned long timeoutMs;
|
||||
|
||||
[noscript] void initMozEmergencyCbModeEvent(in DOMString aType,
|
||||
in boolean aCanBubble,
|
||||
in boolean aCancelable,
|
||||
in boolean aActive,
|
||||
in unsigned long aTimeoutMs);
|
||||
};
|
||||
|
||||
dictionary MozEmergencyCbModeEventInit : EventInit
|
||||
{
|
||||
boolean active;
|
||||
unsigned long timeoutMs;
|
||||
};
|
@ -10,7 +10,7 @@ interface nsIDOMMozMobileConnectionInfo;
|
||||
interface nsIDOMMozMobileNetworkInfo;
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(74361840-c913-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, uuid(7da2d9f6-eba1-4339-bde1-dc6732d42cdf)]
|
||||
interface nsIMobileConnectionListener : nsISupports
|
||||
{
|
||||
void notifyVoiceChanged();
|
||||
@ -24,13 +24,15 @@ interface nsIMobileConnectionListener : nsISupports
|
||||
in DOMString number,
|
||||
in unsigned short timeSeconds,
|
||||
in unsigned short serviceClass);
|
||||
void notifyEmergencyCbModeChanged(in boolean active,
|
||||
in unsigned long timeoutMs);
|
||||
};
|
||||
|
||||
/**
|
||||
* XPCOM component (in the content process) that provides the mobile
|
||||
* network information.
|
||||
*/
|
||||
[scriptable, uuid(12705160-d1b6-11e2-8b8b-0800200c9a66)]
|
||||
[scriptable, uuid(a16681a5-a7f1-4340-a478-e0326a49e988)]
|
||||
interface nsIMobileConnectionProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -73,4 +75,6 @@ interface nsIMobileConnectionProvider : nsISupports
|
||||
nsIDOMDOMRequest setCallingLineIdRestriction(in nsIDOMWindow window,
|
||||
in unsigned short clirMode);
|
||||
nsIDOMDOMRequest getCallingLineIdRestriction(in nsIDOMWindow window);
|
||||
|
||||
nsIDOMDOMRequest exitEmergencyCbMode(in nsIDOMWindow window);
|
||||
};
|
||||
|
@ -3,14 +3,16 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MobileConnection.h"
|
||||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsIDOMUSSDReceivedEvent.h"
|
||||
#include "nsIDOMDataErrorEvent.h"
|
||||
#include "nsIDOMCFStateChangeEvent.h"
|
||||
|
||||
#include "GeneratedEvents.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsIDOMCFStateChangeEvent.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIDOMDataErrorEvent.h"
|
||||
#include "nsIDOMMozEmergencyCbModeEvent.h"
|
||||
#include "nsIDOMUSSDReceivedEvent.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
|
||||
#include "nsJSUtils.h"
|
||||
@ -73,6 +75,7 @@ NS_IMPL_EVENT_HANDLER(MobileConnection, datachange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, dataerror)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, cfstatechange)
|
||||
NS_IMPL_EVENT_HANDLER(MobileConnection, emergencycbmodechange)
|
||||
|
||||
MobileConnection::MobileConnection()
|
||||
{
|
||||
@ -437,6 +440,22 @@ MobileConnection::SetCallingLineIdRestriction(unsigned short aClirMode,
|
||||
return mProvider->SetCallingLineIdRestriction(GetOwner(), aClirMode, aRequest);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::ExitEmergencyCbMode(nsIDOMDOMRequest** aRequest)
|
||||
{
|
||||
*aRequest = nullptr;
|
||||
|
||||
if (!CheckPermission("mobileconnection")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mProvider) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return mProvider->ExitEmergencyCbMode(GetOwner(), aRequest);
|
||||
}
|
||||
|
||||
// nsIMobileConnectionListener
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -521,3 +540,25 @@ MobileConnection::NotifyCFStateChange(bool aSuccess,
|
||||
|
||||
return DispatchTrustedEvent(ce);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileConnection::NotifyEmergencyCbModeChanged(bool aActive,
|
||||
uint32_t aTimeoutMs)
|
||||
{
|
||||
if (!CheckPermission("mobileconnection")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
NS_NewDOMMozEmergencyCbModeEvent(getter_AddRefs(event), this, nullptr,
|
||||
nullptr);
|
||||
MOZ_ASSERT(event);
|
||||
|
||||
nsCOMPtr<nsIDOMMozEmergencyCbModeEvent> ce = do_QueryInterface(event);
|
||||
nsresult rv = ce->InitMozEmergencyCbModeEvent(
|
||||
NS_LITERAL_STRING("emergencycbmodechange"), false, false,
|
||||
aActive, aTimeoutMs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return DispatchTrustedEvent(ce);
|
||||
}
|
||||
|
@ -97,6 +97,8 @@ function testUnregistered() {
|
||||
is(connection.voice.emergencyCallsOnly, false);
|
||||
is(connection.voice.roaming, false);
|
||||
is(connection.voice.cell, null);
|
||||
is(connection.voice.signalStrength, null);
|
||||
is(connection.voice.relSignalStrength, null);
|
||||
|
||||
testSearching();
|
||||
});
|
||||
@ -113,6 +115,8 @@ function testSearching() {
|
||||
is(connection.voice.emergencyCallsOnly, false);
|
||||
is(connection.voice.roaming, false);
|
||||
is(connection.voice.cell, null);
|
||||
is(connection.voice.signalStrength, null);
|
||||
is(connection.voice.relSignalStrength, null);
|
||||
|
||||
testDenied();
|
||||
});
|
||||
@ -129,6 +133,8 @@ function testDenied() {
|
||||
is(connection.voice.emergencyCallsOnly, false);
|
||||
is(connection.voice.roaming, false);
|
||||
is(connection.voice.cell, null);
|
||||
is(connection.voice.signalStrength, null);
|
||||
is(connection.voice.relSignalStrength, null);
|
||||
|
||||
testRoaming();
|
||||
});
|
||||
@ -145,6 +151,10 @@ function testRoaming() {
|
||||
is(connection.voice.emergencyCallsOnly, false);
|
||||
is(connection.voice.roaming, true);
|
||||
|
||||
// Android emulator initializes the signal strength to -99 dBm
|
||||
is(connection.voice.signalStrength, -99);
|
||||
is(connection.voice.relSignalStrength, 44);
|
||||
|
||||
testHome();
|
||||
});
|
||||
}
|
||||
@ -160,6 +170,10 @@ function testHome() {
|
||||
is(connection.voice.emergencyCallsOnly, false);
|
||||
is(connection.voice.roaming, false);
|
||||
|
||||
// Android emulator initializes the signal strength to -99 dBm
|
||||
is(connection.voice.signalStrength, -99);
|
||||
is(connection.voice.relSignalStrength, 44);
|
||||
|
||||
cleanUp();
|
||||
});
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:SelectNetwork",
|
||||
"RIL:SelectNetworkAuto",
|
||||
"RIL:CallStateChanged",
|
||||
"RIL:EmergencyCbModeChanged",
|
||||
"RIL:VoicemailNotification",
|
||||
"RIL:VoicemailInfoChanged",
|
||||
"RIL:CallError",
|
||||
@ -104,7 +105,8 @@ const RIL_IPC_MSG_NAMES = [
|
||||
"RIL:UpdateIccContact",
|
||||
"RIL:SetRoamingPreference",
|
||||
"RIL:GetRoamingPreference",
|
||||
"RIL:CdmaCallWaiting"
|
||||
"RIL:CdmaCallWaiting",
|
||||
"RIL:ExitEmergencyCbMode"
|
||||
];
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
@ -1136,6 +1138,24 @@ RILContentHelper.prototype = {
|
||||
return request;
|
||||
},
|
||||
|
||||
exitEmergencyCbMode: function exitEmergencyCbMode(window) {
|
||||
if (window == null) {
|
||||
throw Components.Exception("Can't get window object",
|
||||
Cr.NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
let request = Services.DOMRequest.createRequest(window);
|
||||
let requestId = this.getRequestId(request);
|
||||
|
||||
cpmm.sendAsyncMessage("RIL:ExitEmergencyCbMode", {
|
||||
clientId: 0,
|
||||
data: {
|
||||
requestId: requestId,
|
||||
}
|
||||
});
|
||||
|
||||
return request;
|
||||
},
|
||||
|
||||
_mobileConnectionListeners: null,
|
||||
_telephonyListeners: null,
|
||||
_cellBroadcastListeners: null,
|
||||
@ -1606,6 +1626,15 @@ RILContentHelper.prototype = {
|
||||
"notifyCdmaCallWaiting",
|
||||
[msg.json.data]);
|
||||
break;
|
||||
case "RIL:ExitEmergencyCbMode":
|
||||
this.handleExitEmergencyCbMode(msg.json);
|
||||
break;
|
||||
case "RIL:EmergencyCbModeChanged":
|
||||
let data = msg.json.data;
|
||||
this._deliverEvent("_mobileConnectionListeners",
|
||||
"notifyEmergencyCbModeChanged",
|
||||
[data.active, data.timeoutMs]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1791,6 +1820,20 @@ RILContentHelper.prototype = {
|
||||
this.fireRequestSuccess(message.requestId, status);
|
||||
},
|
||||
|
||||
handleExitEmergencyCbMode: function handleExitEmergencyCbMode(message) {
|
||||
let requestId = message.requestId;
|
||||
let request = this.takeRequest(requestId);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message.success) {
|
||||
Services.DOMRequest.fireError(request, message.errorMsg);
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
},
|
||||
|
||||
handleSendCancelMMI: function handleSendCancelMMI(message) {
|
||||
debug("handleSendCancelMMI " + JSON.stringify(message));
|
||||
let request = this.takeRequest(message.requestId);
|
||||
|
@ -110,7 +110,8 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
|
||||
"RIL:SetCallingLineIdRestriction",
|
||||
"RIL:GetCallingLineIdRestriction",
|
||||
"RIL:SetRoamingPreference",
|
||||
"RIL:GetRoamingPreference"
|
||||
"RIL:GetRoamingPreference",
|
||||
"RIL:ExitEmergencyCbMode"
|
||||
];
|
||||
|
||||
const RIL_IPC_ICCMANAGER_MSG_NAMES = [
|
||||
@ -856,6 +857,27 @@ RadioInterface.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A utility function to compare objects. The srcInfo may contain
|
||||
* 'rilMessageType', should ignore it.
|
||||
*/
|
||||
isInfoChanged: function isInfoChanged(srcInfo, destInfo) {
|
||||
if (!destInfo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let key in srcInfo) {
|
||||
if (key === 'rilMessageType') {
|
||||
continue;
|
||||
}
|
||||
if (srcInfo[key] !== destInfo[key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process a message from the content process.
|
||||
*/
|
||||
@ -988,6 +1010,9 @@ RadioInterface.prototype = {
|
||||
case "RIL:GetCallingLineIdRestriction":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "getCLIR");
|
||||
break;
|
||||
case "RIL:ExitEmergencyCbMode":
|
||||
this.workerMessenger.sendWithIPCMessage(msg, "exitEmergencyCbMode");
|
||||
break;
|
||||
case "RIL:GetVoicemailInfo":
|
||||
// This message is sync.
|
||||
return this.voicemailInfo;
|
||||
@ -1023,6 +1048,9 @@ RadioInterface.prototype = {
|
||||
case "suppSvcNotification":
|
||||
this.handleSuppSvcNotification(message);
|
||||
break;
|
||||
case "emergencyCbModeChange":
|
||||
this.handleEmergencyCbModeChange(message);
|
||||
break;
|
||||
case "networkinfochanged":
|
||||
this.updateNetworkInfo(message);
|
||||
break;
|
||||
@ -1095,6 +1123,9 @@ RadioInterface.prototype = {
|
||||
let lock = gSettingsService.createLock();
|
||||
lock.set("ril.radio.disabled", !message.on, null, null);
|
||||
break;
|
||||
case "exitEmergencyCbMode":
|
||||
this.handleExitEmergencyCbMode(message);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Don't know about this message type: " +
|
||||
message.rilMessageType);
|
||||
@ -1118,6 +1149,7 @@ RadioInterface.prototype = {
|
||||
let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
|
||||
let operatorMessage = message[RIL.NETWORK_INFO_OPERATOR];
|
||||
let selectionMessage = message[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE];
|
||||
let signalMessage = message[RIL.NETWORK_INFO_SIGNAL];
|
||||
|
||||
// Batch the *InfoChanged messages together
|
||||
if (voiceMessage) {
|
||||
@ -1132,17 +1164,21 @@ RadioInterface.prototype = {
|
||||
this.handleOperatorChange(operatorMessage, true);
|
||||
}
|
||||
|
||||
if (signalMessage) {
|
||||
this.handleSignalStrengthChange(signalMessage, true);
|
||||
}
|
||||
|
||||
let voice = this.rilContext.voice;
|
||||
let data = this.rilContext.data;
|
||||
|
||||
this.checkRoamingBetweenOperators(voice);
|
||||
this.checkRoamingBetweenOperators(data);
|
||||
|
||||
if (voiceMessage || operatorMessage) {
|
||||
if (voiceMessage || operatorMessage || signalMessage) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
||||
this.clientId, voice);
|
||||
}
|
||||
if (dataMessage || operatorMessage) {
|
||||
if (dataMessage || operatorMessage || signalMessage) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, data);
|
||||
}
|
||||
@ -1325,34 +1361,37 @@ RadioInterface.prototype = {
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
handleSignalStrengthChange: function handleSignalStrengthChange(message) {
|
||||
/**
|
||||
* Handle signal strength changes.
|
||||
*
|
||||
* @param message The new signal strength.
|
||||
* @param batch When batch is true, the RIL:VoiceInfoChanged and
|
||||
* RIL:DataInfoChanged message will not be sent.
|
||||
*/
|
||||
handleSignalStrengthChange: function handleSignalStrengthChange(message, batch) {
|
||||
let voiceInfo = this.rilContext.voice;
|
||||
if (voiceInfo.signalStrength != message.voice.signalStrength ||
|
||||
voiceInfo.relSignalStrength != message.voice.relSignalStrength) {
|
||||
voiceInfo.signalStrength = message.voice.signalStrength;
|
||||
voiceInfo.relSignalStrength = message.voice.relSignalStrength;
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
||||
this.clientId, voiceInfo);
|
||||
// If the voice is not registered, need not to update signal information.
|
||||
if (voiceInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
|
||||
this.isInfoChanged(message.voice, voiceInfo)) {
|
||||
this.updateInfo(message.voice, voiceInfo);
|
||||
if (!batch) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
|
||||
this.clientId, voiceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
let dataInfo = this.rilContext.data;
|
||||
if (dataInfo.signalStrength != message.data.signalStrength ||
|
||||
dataInfo.relSignalStrength != message.data.relSignalStrength) {
|
||||
dataInfo.signalStrength = message.data.signalStrength;
|
||||
dataInfo.relSignalStrength = message.data.relSignalStrength;
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, dataInfo);
|
||||
// If the data is not registered, need not to update signal information.
|
||||
if (dataInfo.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
|
||||
this.isInfoChanged(message.data, dataInfo)) {
|
||||
this.updateInfo(message.data, dataInfo);
|
||||
if (!batch) {
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
|
||||
this.clientId, dataInfo);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
networkChanged: function networkChanged(srcNetwork, destNetwork) {
|
||||
return !destNetwork ||
|
||||
destNetwork.longName != srcNetwork.longName ||
|
||||
destNetwork.shortName != srcNetwork.shortName ||
|
||||
destNetwork.mnc != srcNetwork.mnc ||
|
||||
destNetwork.mcc != srcNetwork.mcc;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle operator information changes.
|
||||
*
|
||||
@ -1365,7 +1404,7 @@ RadioInterface.prototype = {
|
||||
let voice = this.rilContext.voice;
|
||||
let data = this.rilContext.data;
|
||||
|
||||
if (this.networkChanged(message, operatorInfo)) {
|
||||
if (this.isInfoChanged(message, operatorInfo)) {
|
||||
this.updateInfo(message, operatorInfo);
|
||||
|
||||
// Update lastKnownNetwork
|
||||
@ -1738,6 +1777,15 @@ RadioInterface.prototype = {
|
||||
this.clientId, message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle emergency callback mode change.
|
||||
*/
|
||||
handleEmergencyCbModeChange: function handleEmergencyCbModeChange(message) {
|
||||
if (DEBUG) this.debug("handleEmergencyCbModeChange: " + JSON.stringify(message));
|
||||
gMessageManager.sendMobileConnectionMessage("RIL:EmergencyCbModeChanged",
|
||||
this.clientId, message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle call error.
|
||||
*/
|
||||
@ -2097,6 +2145,11 @@ RadioInterface.prototype = {
|
||||
gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
|
||||
},
|
||||
|
||||
handleExitEmergencyCbMode: function handleExitEmergencyCbMode(message) {
|
||||
if (DEBUG) this.debug("handleExitEmergencyCbMode: " + JSON.stringify(message));
|
||||
gMessageManager.sendRequestResults("RIL:ExitEmergencyCbMode", message);
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
|
||||
observe: function observe(subject, topic, data) {
|
||||
@ -2141,7 +2194,7 @@ RadioInterface.prototype = {
|
||||
}
|
||||
break;
|
||||
case kScreenStateChangedTopic:
|
||||
this.workerMessenger.send("setScreenState", { on: (state === "on") });
|
||||
this.workerMessenger.send("setScreenState", { on: (data === "on") });
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -419,13 +419,23 @@ function nextNetdCommand() {
|
||||
|
||||
function setInterfaceUp(params, callback) {
|
||||
let command = "interface setcfg " + params.ifname + " " + params.ip + " " +
|
||||
params.prefix + " " + "[" + params.link + "]";
|
||||
params.prefix + " ";
|
||||
if (SDK_VERSION >= 16) {
|
||||
command += params.link;
|
||||
} else {
|
||||
command += "[" + params.link + "]";
|
||||
}
|
||||
return doCommand(command, callback);
|
||||
}
|
||||
|
||||
function setInterfaceDown(params, callback) {
|
||||
let command = "interface setcfg " + params.ifname + " " + params.ip + " " +
|
||||
params.prefix + " " + "[" + params.link + "]";
|
||||
params.prefix + " ";
|
||||
if (SDK_VERSION >= 16) {
|
||||
command += params.link;
|
||||
} else {
|
||||
command += "[" + params.link + "]";
|
||||
}
|
||||
return doCommand(command, callback);
|
||||
}
|
||||
|
||||
|
@ -382,11 +382,13 @@ this.NETWORK_INFO_VOICE_REGISTRATION_STATE = "voiceRegistrationState";
|
||||
this.NETWORK_INFO_DATA_REGISTRATION_STATE = "dataRegistrationState";
|
||||
this.NETWORK_INFO_OPERATOR = "operator";
|
||||
this.NETWORK_INFO_NETWORK_SELECTION_MODE = "networkSelectionMode";
|
||||
this.NETWORK_INFO_SIGNAL = "signal";
|
||||
this.NETWORK_INFO_MESSAGE_TYPES = [
|
||||
NETWORK_INFO_VOICE_REGISTRATION_STATE,
|
||||
NETWORK_INFO_DATA_REGISTRATION_STATE,
|
||||
NETWORK_INFO_OPERATOR,
|
||||
NETWORK_INFO_NETWORK_SELECTION_MODE
|
||||
NETWORK_INFO_NETWORK_SELECTION_MODE,
|
||||
NETWORK_INFO_SIGNAL
|
||||
];
|
||||
|
||||
this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM = "wcdma/gsm";
|
||||
|
@ -62,6 +62,9 @@ const PDU_HEX_OCTET_SIZE = 4;
|
||||
|
||||
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
||||
|
||||
// Timeout value for emergency callback mode.
|
||||
const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000; // 5 mins = 300000 ms.
|
||||
|
||||
const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
|
||||
|
||||
// MMI match groups
|
||||
@ -786,6 +789,11 @@ let RIL = {
|
||||
*/
|
||||
this._isCdma = false;
|
||||
|
||||
/**
|
||||
* True if we are in emergency callback mode.
|
||||
*/
|
||||
this._isInEmergencyCbMode = false;
|
||||
|
||||
/**
|
||||
* Set when radio is ready but radio tech is unknown. That is, we are
|
||||
* waiting for REQUEST_VOICE_RADIO_TECH
|
||||
@ -1450,6 +1458,58 @@ let RIL = {
|
||||
Buf.sendParcel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Query call waiting status via MMI.
|
||||
*/
|
||||
_handleQueryMMICallWaiting: function _handleQueryMMICallWaiting(options) {
|
||||
function callback(options) {
|
||||
options.length = Buf.readUint32();
|
||||
options.enabled = (Buf.readUint32() === 1);
|
||||
let services = Buf.readUint32();
|
||||
if (options.enabled) {
|
||||
options.statusMessage = MMI_SM_KS_SERVICE_ENABLED_FOR;
|
||||
let serviceClass = [];
|
||||
for (let serviceClassMask = 1;
|
||||
serviceClassMask <= ICC_SERVICE_CLASS_MAX;
|
||||
serviceClassMask <<= 1) {
|
||||
if ((serviceClassMask & services) !== 0) {
|
||||
serviceClass.push(MMI_KS_SERVICE_CLASS_MAPPING[serviceClassMask]);
|
||||
}
|
||||
}
|
||||
options.additionalInformation = serviceClass;
|
||||
} else {
|
||||
options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
|
||||
}
|
||||
|
||||
// Prevent DataCloneError when sending chrome messages.
|
||||
delete options.callback;
|
||||
this.sendChromeMessage(options);
|
||||
}
|
||||
|
||||
options.callback = callback;
|
||||
this.queryCallWaiting(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set call waiting status via MMI.
|
||||
*/
|
||||
_handleSetMMICallWaiting: function _handleSetMMICallWaiting(options) {
|
||||
function callback(options) {
|
||||
if (options.enabled) {
|
||||
options.statusMessage = MMI_SM_KS_SERVICE_ENABLED;
|
||||
} else {
|
||||
options.statusMessage = MMI_SM_KS_SERVICE_DISABLED;
|
||||
}
|
||||
|
||||
// Prevent DataCloneError when sending chrome messages.
|
||||
delete options.callback;
|
||||
this.sendChromeMessage(options);
|
||||
}
|
||||
|
||||
options.callback = callback;
|
||||
this.setCallWaiting(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Query call waiting status.
|
||||
*
|
||||
@ -1473,7 +1533,8 @@ let RIL = {
|
||||
Buf.newParcel(REQUEST_SET_CALL_WAITING, options);
|
||||
Buf.writeUint32(2);
|
||||
Buf.writeUint32(options.enabled ? 1 : 0);
|
||||
Buf.writeUint32(ICC_SERVICE_CLASS_VOICE);
|
||||
Buf.writeUint32(options.serviceClass !== undefined ?
|
||||
options.serviceClass : ICC_SERVICE_CLASS_VOICE);
|
||||
Buf.sendParcel();
|
||||
},
|
||||
|
||||
@ -1606,6 +1667,7 @@ let RIL = {
|
||||
this.getDataRegistrationState(); //TODO only GSM
|
||||
this.getOperator();
|
||||
this.getNetworkSelectionMode();
|
||||
this.getSignalStrength();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1758,6 +1820,21 @@ let RIL = {
|
||||
Buf.simpleRequest(REQUEST_BASEBAND_VERSION);
|
||||
},
|
||||
|
||||
sendExitEmergencyCbModeRequest: function sendExitEmergencyCbModeRequest(options) {
|
||||
Buf.simpleRequest(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, options);
|
||||
},
|
||||
|
||||
exitEmergencyCbMode: function exitEmergencyCbMode(options) {
|
||||
// The function could be called by an API from RadioInterfaceLayer or by
|
||||
// ril_worker itself. From ril_worker, we won't pass the parameter
|
||||
// 'options'. In this case, it is marked as internal.
|
||||
if (!options) {
|
||||
options = {internal: true};
|
||||
}
|
||||
this._cancelEmergencyCbModeTimeout();
|
||||
this.sendExitEmergencyCbModeRequest(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cache the request for making an emergency call when radio is off. The
|
||||
* request shall include two types of callback functions. 'callback' is
|
||||
@ -1812,6 +1889,11 @@ let RIL = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit emergency callback mode when user dial a non-emergency call.
|
||||
if (this._isInEmergencyCbMode) {
|
||||
this.exitEmergencyCbMode();
|
||||
}
|
||||
|
||||
options.request = REQUEST_DIAL;
|
||||
this.sendDialRequest(options);
|
||||
},
|
||||
@ -2662,9 +2744,31 @@ let RIL = {
|
||||
}
|
||||
this.setICCFacilityLock(options);
|
||||
return;
|
||||
|
||||
// Call waiting
|
||||
case MMI_SC_CALL_WAITING:
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
if (!_isRadioAvailable(MMI_KS_SC_CALL_WAITING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_CALL_WAITING;
|
||||
|
||||
if (mmi.procedure === MMI_PROCEDURE_INTERROGATION) {
|
||||
this._handleQueryMMICallWaiting(options);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mmi.procedure === MMI_PROCEDURE_ACTIVATION) {
|
||||
options.enabled = true;
|
||||
} else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
|
||||
options.enabled = false;
|
||||
} else {
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CALL_WAITING);
|
||||
return;
|
||||
}
|
||||
|
||||
options.serviceClass = this._siToServiceClass(mmi.sia);
|
||||
this._handleSetMMICallWaiting(options);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3325,7 +3429,6 @@ let RIL = {
|
||||
|
||||
// This was moved down from CARD_APPSTATE_READY
|
||||
this.requestNetworkInfo();
|
||||
this.getSignalStrength();
|
||||
if (newCardState == GECKO_CARDSTATE_READY) {
|
||||
// For type SIM, we need to check EF_phase first.
|
||||
// Other types of ICC we can send Terminal_Profile immediately.
|
||||
@ -3568,7 +3671,7 @@ let RIL = {
|
||||
}
|
||||
|
||||
info.rilMessageType = "signalstrengthchange";
|
||||
this.sendChromeMessage(info);
|
||||
this._sendNetworkInfoMessage(NETWORK_INFO_SIGNAL, info);
|
||||
|
||||
if (this.cachedDialRequest && info.voice.signalStrength) {
|
||||
// Radio is ready for making the cached emergency call.
|
||||
@ -3981,6 +4084,39 @@ let RIL = {
|
||||
this.sendChromeMessage(message);
|
||||
},
|
||||
|
||||
_cancelEmergencyCbModeTimeout: function _cancelEmergencyCbModeTimeout() {
|
||||
if (this._exitEmergencyCbModeTimeoutID) {
|
||||
clearTimeout(this._exitEmergencyCbModeTimeoutID);
|
||||
this._exitEmergencyCbModeTimeoutID = null;
|
||||
}
|
||||
},
|
||||
|
||||
_handleChangedEmergencyCbMode: function _handleChangedEmergencyCbMode(active) {
|
||||
if (this._isInEmergencyCbMode === active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
// Start a new timeout event when enter the mode.
|
||||
let ril = this;
|
||||
this._cancelEmergencyCbModeTimeout();
|
||||
this._exitEmergencyCbModeTimeoutID = setTimeout(function() {
|
||||
ril.exitEmergencyCbMode();
|
||||
}, EMERGENCY_CB_MODE_TIMEOUT_MS);
|
||||
} else {
|
||||
// Clear the timeout event when exit mode.
|
||||
this._cancelEmergencyCbModeTimeout();
|
||||
}
|
||||
|
||||
// Keep current mode and write to property.
|
||||
this._isInEmergencyCbMode = active;
|
||||
|
||||
let message = {rilMessageType: "emergencyCbModeChange",
|
||||
active: active,
|
||||
timeoutMs: EMERGENCY_CB_MODE_TIMEOUT_MS};
|
||||
this.sendChromeMessage(message);
|
||||
},
|
||||
|
||||
_processNetworks: function _processNetworks() {
|
||||
let strings = Buf.readStringList();
|
||||
let networks = [];
|
||||
@ -5148,6 +5284,8 @@ RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length
|
||||
}
|
||||
};
|
||||
RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) {
|
||||
this._receivedNetworkInfo(NETWORK_INFO_SIGNAL);
|
||||
|
||||
if (options.rilRequestError) {
|
||||
return;
|
||||
}
|
||||
@ -5483,6 +5621,12 @@ RIL[REQUEST_QUERY_CALL_WAITING] =
|
||||
this.sendChromeMessage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.callback) {
|
||||
options.callback.call(this, options);
|
||||
return;
|
||||
}
|
||||
|
||||
options.length = Buf.readUint32();
|
||||
options.enabled = ((Buf.readUint32() == 1) &&
|
||||
((Buf.readUint32() & ICC_SERVICE_CLASS_VOICE) == 0x01));
|
||||
@ -5493,7 +5637,15 @@ RIL[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, option
|
||||
options.success = (options.rilRequestError === 0);
|
||||
if (!options.success) {
|
||||
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||
this.sendChromeMessage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.callback) {
|
||||
options.callback.call(this, options);
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendChromeMessage(options);
|
||||
};
|
||||
RIL[REQUEST_SMS_ACKNOWLEDGE] = null;
|
||||
@ -5917,7 +6069,17 @@ RIL[REQUEST_DEVICE_IDENTITY] = function REQUEST_DEVICE_IDENTITY(length, options)
|
||||
this.ESN = result[2];
|
||||
this.MEID = result[3];
|
||||
};
|
||||
RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = null;
|
||||
RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = function REQUEST_EXIT_EMERGENCY_CALLBACK_MODE(length, options) {
|
||||
if (options.internal) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.success = (options.rilRequestError === 0);
|
||||
if (!options.success) {
|
||||
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||
}
|
||||
this.sendChromeMessage(options);
|
||||
};
|
||||
RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) {
|
||||
if (options.rilRequestError) {
|
||||
return;
|
||||
@ -6227,7 +6389,9 @@ RIL[UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS] = function UNSOLICITED_RESPONSE_NEW_
|
||||
};
|
||||
RIL[UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL] = null;
|
||||
RIL[UNSOLICITED_RESTRICTED_STATE_CHANGED] = null;
|
||||
RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = null;
|
||||
RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE() {
|
||||
this._handleChangedEmergencyCbMode(true);
|
||||
};
|
||||
RIL[UNSOLICITED_CDMA_CALL_WAITING] = function UNSOLICITED_CDMA_CALL_WAITING(length) {
|
||||
let call = {};
|
||||
call.number = Buf.readString();
|
||||
@ -6246,6 +6410,9 @@ RIL[UNSOLICITED_CDMA_INFO_REC] = null;
|
||||
RIL[UNSOLICITED_OEM_HOOK_RAW] = null;
|
||||
RIL[UNSOLICITED_RINGBACK_TONE] = null;
|
||||
RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
|
||||
RIL[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE() {
|
||||
this._handleChangedEmergencyCbMode(false);
|
||||
};
|
||||
RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
|
||||
// Prevent response id collision between UNSOLICITED_RIL_CONNECTED and
|
||||
// UNSOLICITED_VOICE_RADIO_TECH_CHANGED for Akami on gingerbread branch.
|
||||
@ -6261,6 +6428,8 @@ RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
|
||||
}
|
||||
|
||||
this.initRILState();
|
||||
// Always ensure that we are not in emergency callback mode when init.
|
||||
this.exitEmergencyCbMode();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ function add_test_incoming_parcel(parcel, handler) {
|
||||
if (!parcel) {
|
||||
parcel = newIncomingParcel(-1,
|
||||
worker.RESPONSE_TYPE_UNSOLICITED,
|
||||
worker.REQUEST_REGISTRATION_STATE,
|
||||
worker.REQUEST_VOICE_REGISTRATION_STATE,
|
||||
[0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ add_test(function test_incoming_parcel_buffer_overwritten() {
|
||||
}
|
||||
|
||||
// Do nothing in handleParcel().
|
||||
let request = worker.REQUEST_REGISTRATION_STATE;
|
||||
let request = worker.REQUEST_VOICE_REGISTRATION_STATE;
|
||||
worker.RIL[request] = null;
|
||||
|
||||
// Prepare two parcels, whose sizes are both smaller than the incoming buffer
|
||||
|
179
dom/system/gonk/tests/test_ril_worker_ecm.js
Normal file
179
dom/system/gonk/tests/test_ril_worker_ecm.js
Normal file
@ -0,0 +1,179 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function _getWorker() {
|
||||
let _postedMessage;
|
||||
let _worker = newWorker({
|
||||
postRILMessage: function fakePostRILMessage(data) {
|
||||
},
|
||||
postMessage: function fakePostMessage(message) {
|
||||
_postedMessage = message;
|
||||
}
|
||||
});
|
||||
return {
|
||||
get postedMessage() {
|
||||
return _postedMessage;
|
||||
},
|
||||
get worker() {
|
||||
return _worker;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var timeoutCallback = null;
|
||||
var timeoutDelayMs = 0;
|
||||
var TIMER_ID = 1234;
|
||||
|
||||
// No window in xpcshell-test. Create our own timer mechanism.
|
||||
|
||||
function setTimeout(callback, timeoutMs) {
|
||||
timeoutCallback = callback;
|
||||
timeoutDelayMs = timeoutMs;
|
||||
do_check_eq(timeoutMs, 300000); // 5 mins.
|
||||
return TIMER_ID;
|
||||
}
|
||||
|
||||
function clearTimeout(timeoutId) {
|
||||
do_check_eq(timeoutId, TIMER_ID);
|
||||
timeoutCallback = null;
|
||||
}
|
||||
|
||||
function fireTimeout() {
|
||||
do_check_neq(timeoutCallback, null);
|
||||
if (timeoutCallback) {
|
||||
timeoutCallback();
|
||||
timeoutCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_enter_emergencyCbMode() {
|
||||
let workerHelper = _getWorker();
|
||||
let worker = workerHelper.worker;
|
||||
|
||||
worker.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
|
||||
let postedMessage = workerHelper.postedMessage;
|
||||
|
||||
// Should store the mode.
|
||||
do_check_eq(worker.RIL._isInEmergencyCbMode, true);
|
||||
|
||||
// Should notify change.
|
||||
do_check_eq(postedMessage.rilMessageType, "emergencyCbModeChange");
|
||||
do_check_eq(postedMessage.active, true);
|
||||
do_check_eq(postedMessage.timeoutMs, 300000);
|
||||
|
||||
// Should start timer.
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_exit_emergencyCbMode() {
|
||||
let workerHelper = _getWorker();
|
||||
let worker = workerHelper.worker;
|
||||
|
||||
worker.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
|
||||
worker.RIL[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE]();
|
||||
let postedMessage = workerHelper.postedMessage;
|
||||
|
||||
// Should store the mode.
|
||||
do_check_eq(worker.RIL._isInEmergencyCbMode, false);
|
||||
|
||||
// Should notify change.
|
||||
do_check_eq(postedMessage.rilMessageType, "emergencyCbModeChange");
|
||||
do_check_eq(postedMessage.active, false);
|
||||
|
||||
// Should clear timer.
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, null);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_request_exit_emergencyCbMode_when_timeout() {
|
||||
let workerHelper = _getWorker();
|
||||
let worker = workerHelper.worker;
|
||||
|
||||
worker.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
|
||||
do_check_eq(worker.RIL._isInEmergencyCbMode, true);
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
|
||||
|
||||
let parcelTypes = [];
|
||||
worker.Buf.newParcel = function(type, options) {
|
||||
parcelTypes.push(type);
|
||||
};
|
||||
|
||||
// Timeout.
|
||||
fireTimeout();
|
||||
|
||||
// Should clear timeout event.
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, null);
|
||||
|
||||
// Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE.
|
||||
do_check_neq(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_request_exit_emergencyCbMode_when_dial() {
|
||||
let workerHelper = _getWorker();
|
||||
let worker = workerHelper.worker;
|
||||
|
||||
worker.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
|
||||
do_check_eq(worker.RIL._isInEmergencyCbMode, true);
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
|
||||
|
||||
let parcelTypes = [];
|
||||
worker.Buf.newParcel = function(type, options) {
|
||||
parcelTypes.push(type);
|
||||
};
|
||||
|
||||
// Dial non-emergency call.
|
||||
worker.RIL.dial({number: "0912345678",
|
||||
isDialEmergency: false});
|
||||
|
||||
// Should clear timeout event.
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, null);
|
||||
|
||||
// Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE.
|
||||
do_check_neq(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_request_exit_emergencyCbMode_explicitly() {
|
||||
let workerHelper = _getWorker();
|
||||
let worker = workerHelper.worker;
|
||||
|
||||
worker.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
|
||||
do_check_eq(worker.RIL._isInEmergencyCbMode, true);
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
|
||||
|
||||
let parcelTypes = [];
|
||||
worker.Buf.newParcel = function(type, options) {
|
||||
parcelTypes.push(type);
|
||||
};
|
||||
|
||||
worker.RIL.handleChromeMessage({rilMessageType: "exitEmergencyCbMode"});
|
||||
worker.RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE](1, {
|
||||
rilMessageType: "exitEmergencyCbMode",
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
let postedMessage = workerHelper.postedMessage;
|
||||
|
||||
// Should clear timeout event.
|
||||
do_check_eq(worker.RIL._exitEmergencyCbModeTimeoutID, null);
|
||||
|
||||
// Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE.
|
||||
do_check_neq(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1);
|
||||
|
||||
// Send back the response.
|
||||
do_check_eq(postedMessage.rilMessageType, "exitEmergencyCbMode");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -46,7 +46,7 @@ function testSendMMI(mmi, error) {
|
||||
do_print("worker.postMessage " + worker.postMessage);
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: mmi});
|
||||
worker.RIL.sendMMI({rilMessageType: "sendMMI", mmi: mmi});
|
||||
|
||||
let postedMessage = workerhelper.postedMessage;
|
||||
|
||||
@ -380,7 +380,7 @@ add_test(function test_sendMMI_short_code() {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "**"});
|
||||
@ -549,7 +549,7 @@ add_test(function test_sendMMI_change_PIN() {
|
||||
worker.RIL[REQUEST_ENTER_SIM_PIN](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "**04*1234*4567*4567#"});
|
||||
@ -594,7 +594,7 @@ add_test(function test_sendMMI_change_PIN2() {
|
||||
worker.RIL[REQUEST_ENTER_SIM_PIN2](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "**042*1234*4567*4567#"});
|
||||
@ -639,7 +639,7 @@ add_test(function test_sendMMI_unblock_PIN() {
|
||||
worker.RIL[REQUEST_ENTER_SIM_PUK](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "**05*1234*4567*4567#"});
|
||||
@ -684,7 +684,7 @@ add_test(function test_sendMMI_unblock_PIN2() {
|
||||
worker.RIL[REQUEST_ENTER_SIM_PUK2](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "**052*1234*4567*4567#"});
|
||||
@ -731,13 +731,13 @@ add_test(function test_sendMMI_get_IMEI() {
|
||||
worker.RIL[REQUEST_SEND_USSD](0, {
|
||||
rilRequestError: ERROR_SUCCESS,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.sendMMI({mmi: "*#06#"});
|
||||
|
||||
let postedMessage = workerhelper.postedMessage;
|
||||
|
||||
do_check_true(mmiOptions.mmi);
|
||||
do_check_neq(mmiOptions.mmi, null);
|
||||
do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
|
||||
do_check_true(postedMessage.success);
|
||||
|
||||
@ -754,13 +754,13 @@ add_test(function test_sendMMI_get_IMEI_error() {
|
||||
worker.RIL[REQUEST_SEND_USSD](0, {
|
||||
rilRequestError: ERROR_RADIO_NOT_AVAILABLE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.sendMMI({mmi: "*#06#"});
|
||||
|
||||
let postedMessage = workerhelper.postedMessage;
|
||||
|
||||
do_check_true(mmiOptions.mmi);
|
||||
do_check_neq(mmiOptions.mmi, null);
|
||||
do_check_eq (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
|
||||
do_check_false(postedMessage.success);
|
||||
|
||||
@ -781,7 +781,7 @@ add_test(function test_sendMMI_call_barring_BAIC_interrogation_voice() {
|
||||
rilMessageType: "sendMMI",
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "*#33#"});
|
||||
@ -810,7 +810,7 @@ add_test(function test_sendMMI_call_barring_BAIC_activation() {
|
||||
procedure: MMI_PROCEDURE_ACTIVATION,
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "*33#"});
|
||||
@ -837,7 +837,7 @@ add_test(function test_sendMMI_call_barring_BAIC_deactivation() {
|
||||
procedure: MMI_PROCEDURE_DEACTIVATION,
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "#33#"});
|
||||
@ -857,12 +857,6 @@ add_test(function test_sendMMI_call_barring_BAIC_procedure_not_supported() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_call_waiting() {
|
||||
testSendMMI("*43#", MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_USSD() {
|
||||
let workerhelper = getWorker();
|
||||
let worker = workerhelper.worker;
|
||||
@ -873,7 +867,7 @@ add_test(function test_sendMMI_USSD() {
|
||||
worker.RIL[REQUEST_SEND_USSD](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "*123#"});
|
||||
@ -898,7 +892,7 @@ add_test(function test_sendMMI_USSD_error() {
|
||||
worker.RIL[REQUEST_SEND_USSD](0, {
|
||||
rilRequestError: ERROR_GENERIC_FAILURE
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "*123#"});
|
||||
@ -912,3 +906,77 @@ add_test(function test_sendMMI_USSD_error() {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function setCallWaitingSuccess(mmi) {
|
||||
let workerhelper = getWorker();
|
||||
let worker = workerhelper.worker;
|
||||
|
||||
worker.RIL.setCallWaiting = function fakeSetCallWaiting(options) {
|
||||
worker.RIL[REQUEST_SET_CALL_WAITING](0, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: mmi});
|
||||
|
||||
let postedMessage = workerhelper.postedMessage;
|
||||
|
||||
do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
|
||||
do_check_true(postedMessage.success);
|
||||
}
|
||||
|
||||
add_test(function test_sendMMI_call_waiting_activation() {
|
||||
setCallWaitingSuccess("*43*10#");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_call_waiting_deactivation() {
|
||||
setCallWaitingSuccess("#43#");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_call_waiting_registration() {
|
||||
testSendMMI("**43#", MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_call_waiting_erasure() {
|
||||
testSendMMI("##43#", MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_sendMMI_call_waiting_interrogation() {
|
||||
let workerhelper = getWorker();
|
||||
let worker = workerhelper.worker;
|
||||
|
||||
worker.Buf.readUint32 = function fakeReadUint32() {
|
||||
return worker.Buf.int32Array.pop();
|
||||
};
|
||||
|
||||
worker.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) {
|
||||
worker.Buf.int32Array = [
|
||||
7, // serviceClass
|
||||
1, // enabled
|
||||
2 // length
|
||||
];
|
||||
worker.RIL[REQUEST_QUERY_CALL_WAITING](1, {
|
||||
rilRequestError: ERROR_SUCCESS
|
||||
});
|
||||
};
|
||||
|
||||
worker.RIL.radioState = GECKO_RADIOSTATE_READY;
|
||||
worker.RIL.sendMMI({mmi: "*#43#"});
|
||||
|
||||
let postedMessage = workerhelper.postedMessage;
|
||||
|
||||
do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
|
||||
do_check_true(postedMessage.success);
|
||||
do_check_eq(postedMessage.length, 2);
|
||||
do_check_true(postedMessage.enabled);
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -14,3 +14,4 @@ tail =
|
||||
[test_ril_worker_clir.js]
|
||||
[test_ril_worker_clip.js]
|
||||
[test_ril_worker_ssn.js]
|
||||
[test_ril_worker_ecm.js]
|
||||
|
20
dom/webidl/MozEmergencyCbModeEvent.webidl
Normal file
20
dom/webidl/MozEmergencyCbModeEvent.webidl
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type,
|
||||
optional MozEmergencyCbModeEventInit eventInitDict),
|
||||
HeaderFile="GeneratedEventClasses.h"]
|
||||
interface MozEmergencyCbModeEvent : Event
|
||||
{
|
||||
readonly attribute boolean active;
|
||||
readonly attribute unsigned long timeoutMs;
|
||||
};
|
||||
|
||||
dictionary MozEmergencyCbModeEventInit : EventInit
|
||||
{
|
||||
boolean active = false;
|
||||
unsigned long timeoutMs = 0;
|
||||
};
|
@ -492,6 +492,7 @@ webidl_files += \
|
||||
DataErrorEvent.webidl \
|
||||
IccCardLockErrorEvent.webidl \
|
||||
MozCellBroadcastEvent.webidl \
|
||||
MozEmergencyCbModeEvent.webidl \
|
||||
MozVoicemailEvent.webidl \
|
||||
MozWifiConnectionInfoEvent.webidl \
|
||||
MozWifiStatusChangeEvent.webidl \
|
||||
|
@ -87,9 +87,6 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
|
||||
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
|
||||
{
|
||||
// Accumulate the CSS transform between layers that have an APZC
|
||||
aTransform = aTransform * aLayer->GetTransform();
|
||||
|
||||
ContainerLayer* container = aLayer->AsContainerLayer();
|
||||
AsyncPanZoomController* controller = nullptr;
|
||||
if (container) {
|
||||
@ -121,9 +118,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
|
||||
|
||||
LayerRect visible = container->GetFrameMetrics().mViewport * container->GetFrameMetrics().LayersPixelsPerCSSPixel();
|
||||
controller->SetLayerHitTestData(visible, aTransform);
|
||||
// Reset the accumulated transform once we hit a layer with an APZC
|
||||
aTransform = gfx3DMatrix();
|
||||
controller->SetLayerHitTestData(visible, aTransform, aLayer->GetTransform());
|
||||
APZC_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
|
||||
visible.width, visible.height,
|
||||
controller);
|
||||
@ -145,6 +140,15 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
container->SetAsyncPanZoomController(controller);
|
||||
}
|
||||
|
||||
// Accumulate the CSS transform between layers that have an APZC, but exclude any
|
||||
// any layers that do have an APZC, and reset the accumulation at those layers.
|
||||
if (controller) {
|
||||
aTransform = gfx3DMatrix();
|
||||
} else {
|
||||
// Multiply child layer transforms on the left so they get applied first
|
||||
aTransform = aLayer->GetTransform() * aTransform;
|
||||
}
|
||||
|
||||
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
|
||||
AsyncPanZoomController* next = nullptr;
|
||||
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
@ -165,31 +169,69 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
||||
return aNextSibling;
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::PointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = result.x;
|
||||
aPoint->y = result.y;
|
||||
}
|
||||
|
||||
/*static*/ template<class T> void
|
||||
ApplyTransform(gfx::IntPointTyped<T>* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
|
||||
{
|
||||
gfxPoint result = aMatrix.Transform(gfxPoint(aPoint->x, aPoint->y));
|
||||
aPoint->x = NS_lround(result.x);
|
||||
aPoint->y = NS_lround(result.y);
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
|
||||
{
|
||||
nsRefPtr<AsyncPanZoomController> apzc;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToScreen;
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
|
||||
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
|
||||
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(multiTouchInput);
|
||||
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} case PINCHGESTURE_INPUT: {
|
||||
const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
|
||||
apzc = GetTargetAPZC(pinchInput.mFocusPoint);
|
||||
apzc = GetTargetAPZC(pinchInput.mFocusPoint, transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
PinchGestureInput inputForApzc(pinchInput);
|
||||
ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc);
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} case TAPGESTURE_INPUT: {
|
||||
const TapGestureInput& tapInput = aEvent.AsTapGestureInput();
|
||||
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint));
|
||||
break;
|
||||
} default: {
|
||||
// leave apzc as nullptr
|
||||
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint), transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
TapGestureInput inputForApzc(tapInput);
|
||||
ApplyTransform(&(inputForApzc.mPoint), transformToApzc);
|
||||
apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (apzc) {
|
||||
return apzc->ReceiveInputEvent(aEvent);
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
@ -200,27 +242,51 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<AsyncPanZoomController> apzc;
|
||||
gfx3DMatrix transformToApzc;
|
||||
gfx3DMatrix transformToScreen;
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
const nsTouchEvent& touchEvent = static_cast<const nsTouchEvent&>(aEvent);
|
||||
if (touchEvent.touches.Length() > 0) {
|
||||
nsIntPoint point = touchEvent.touches[0]->mRefPoint;
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)));
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(point.x, point.y)),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(touchEvent);
|
||||
for (int i = inputForApzc.mTouches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
|
||||
}
|
||||
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
|
||||
nsTouchEvent* outEvent = static_cast<nsTouchEvent*>(aOutEvent);
|
||||
for (int i = outEvent->touches.Length() - 1; i >= 0; i--) {
|
||||
ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform);
|
||||
}
|
||||
|
||||
return apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} case NS_MOUSE_EVENT: {
|
||||
const nsMouseEvent& mouseEvent = static_cast<const nsMouseEvent&>(aEvent);
|
||||
apzc = GetTargetAPZC(ScreenPoint::FromUnknownPoint(gfx::Point(mouseEvent.refPoint.x,
|
||||
mouseEvent.refPoint.y)));
|
||||
mouseEvent.refPoint.y)),
|
||||
transformToApzc, transformToScreen);
|
||||
if (apzc) {
|
||||
MultiTouchInput inputForApzc(mouseEvent);
|
||||
ApplyTransform(&(inputForApzc.mTouches[0].mScreenPoint), transformToApzc);
|
||||
|
||||
gfx3DMatrix outTransform = transformToApzc * transformToScreen;
|
||||
ApplyTransform(&(static_cast<nsMouseEvent*>(aOutEvent)->refPoint), outTransform);
|
||||
|
||||
return apzc->ReceiveInputEvent(inputForApzc);
|
||||
}
|
||||
break;
|
||||
} default: {
|
||||
// leave apzc as nullptr
|
||||
// Ignore other event types
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (apzc) {
|
||||
return apzc->ReceiveInputEvent(aEvent, aOutEvent);
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
@ -334,15 +400,84 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
/* This function returns the AsyncPanZoomController instance that hit testing determines
|
||||
is under the given ScreenPoint.
|
||||
|
||||
In addition, the aTransformToApzcOut and aTransformToScreenOut out-parameters are filled
|
||||
with some useful transformations that input events may need applied. This is best
|
||||
illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
|
||||
is the layer that corresponds to the returned APZC instance, and layer R is the root
|
||||
of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
|
||||
When layer L is displayed to the screen by the compositor, the set of transforms that
|
||||
are applied to L are (in order from top to bottom):
|
||||
|
||||
L's CSS transform (hereafter referred to as transform matrix LC)
|
||||
L's async transform (hereafter referred to as transform matrix LA)
|
||||
M's CSS transform (hereafter referred to as transform matrix MC)
|
||||
M's async transform (hereafter referred to as transform matrix MA)
|
||||
...
|
||||
R's CSS transform (hereafter referred to as transform matrix RC)
|
||||
R's async transform (hereafter referred to as transform matrix RA)
|
||||
|
||||
Therefore, if we want user input to modify L's async transform, we have to first convert
|
||||
user input from screen space to the coordinate space of L's async transform. Doing this
|
||||
involves applying the following transforms (in order from top to bottom):
|
||||
RA.Inverse()
|
||||
RC.Inverse()
|
||||
...
|
||||
MA.Inverse()
|
||||
MC.Inverse()
|
||||
This combined transformation is returned in the aTransformToApzcOut out-parameter.
|
||||
|
||||
Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip
|
||||
out all of the async transforms that are involved in this chain. This is because async
|
||||
transforms are stored only in the compositor and gecko does not account for them when
|
||||
doing display-list-based hit-testing for event dispatching. Therefore, given a user input
|
||||
in screen space, the following transforms need to be applied (in order from top to bottom):
|
||||
RA.Inverse()
|
||||
RC.Inverse()
|
||||
...
|
||||
MA.Inverse()
|
||||
MC.Inverse()
|
||||
LA.Inverse()
|
||||
LC.Inverse()
|
||||
LC
|
||||
MC
|
||||
...
|
||||
RC
|
||||
This sequence can be simplified and refactored to the following:
|
||||
aTransformToApzcOut
|
||||
LA.Inverse()
|
||||
MC
|
||||
...
|
||||
RC
|
||||
Since aTransformToApzcOut is already one of the out-parameters, we set aTransformToScreenOut
|
||||
to the remaining transforms (LA.Inverse() * MC * ... * RC), so that the caller code can
|
||||
combine it with aTransformToApzcOut to get the final transform required in this case.
|
||||
|
||||
Note that for many of these layers, there will be no AsyncPanZoomController attached, and
|
||||
so the async transform will be the identity transform. So, in the example above, if layers
|
||||
L and P have APZC instances attached, MA, NA, OA, QA, and RA will be identity transforms.
|
||||
Additionally, for space-saving purposes, each APZC instance stores its layers individual
|
||||
CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for
|
||||
layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC).
|
||||
The APZCs also obviously have LA and PA, so all of the above transformation combinations
|
||||
required can be generated.
|
||||
|
||||
Note that this function may return null, in which case the matrix out-parameters are
|
||||
left unmodified.
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController>
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
|
||||
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToScreenOut)
|
||||
{
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
nsRefPtr<AsyncPanZoomController> target;
|
||||
// The root may have siblings, so check those too
|
||||
gfxPoint point(aPoint.x, aPoint.y);
|
||||
for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
|
||||
target = GetAPZCAtPoint(apzc, point);
|
||||
target = GetAPZCAtPoint(apzc, point, aTransformToApzcOut, aTransformToScreenOut);
|
||||
if (target) {
|
||||
break;
|
||||
}
|
||||
@ -368,23 +503,52 @@ APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableL
|
||||
}
|
||||
|
||||
AsyncPanZoomController*
|
||||
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint)
|
||||
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut)
|
||||
{
|
||||
gfx3DMatrix transform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()) * aApzc->GetCSSTransform();
|
||||
gfx3DMatrix untransform = transform.Inverse();
|
||||
gfxPoint untransformed = untransform.ProjectPoint(aHitTestPoint);
|
||||
// The comments below assume there is a chain of layers L..R with L and P having APZC instances as
|
||||
// explained in the comment on GetTargetAPZC. This function will recurse with aApzc at L and P, and the
|
||||
// comments explain what values are stored in the variables at these two levels. All the comments
|
||||
// use standard matrix notation where the leftmost matrix in a multiplication is applied first.
|
||||
|
||||
// ancestorUntransform is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
|
||||
// and RC.Inverse() * QC.Inverse() at recursion level for P.
|
||||
gfx3DMatrix ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
|
||||
// asyncUntransform is LA.Inverse() at recursion level for L,
|
||||
// and PA.Inverse() at recursion level for P.
|
||||
gfx3DMatrix asyncUntransform = gfx3DMatrix(aApzc->GetCurrentAsyncTransform()).Inverse();
|
||||
// untransformSinceLastApzc is OC.Inverse() * NC.Inverse() * MC.Inverse() * LA.Inverse() * LC.Inverse() at L,
|
||||
// and RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() at P.
|
||||
gfx3DMatrix untransformSinceLastApzc = ancestorUntransform * asyncUntransform * aApzc->GetCSSTransform().Inverse();
|
||||
// untransformed is the user input in L's layer space at L,
|
||||
// and in P's layer space at P.
|
||||
gfxPoint untransformed = untransformSinceLastApzc.ProjectPoint(aHitTestPoint);
|
||||
APZC_LOG("Untransformed %f %f to %f %f for APZC %p\n", aHitTestPoint.x, aHitTestPoint.y, untransformed.x, untransformed.y, aApzc);
|
||||
|
||||
// This walks the tree in depth-first, reverse order, so that it encounters
|
||||
// APZCs front-to-back on the screen.
|
||||
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed);
|
||||
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed, aTransformToApzcOut, aTransformToScreenOut);
|
||||
if (match) {
|
||||
// This code is not run in the recursion at layer L.
|
||||
// aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PA.Inverse() * PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
|
||||
// at recursion level for P
|
||||
aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut;
|
||||
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC * PC * QC * RC at recursion level for P
|
||||
aTransformToScreenOut = aTransformToScreenOut * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform();
|
||||
// The above values for aTransformToApzcOut and aTransformToScreenOut at recursion level for P match
|
||||
// the required output as explained in the comment above GetTargetAPZC. Note that any missing terms
|
||||
// are async transforms that are guaranteed to be identity transforms.
|
||||
return match;
|
||||
}
|
||||
}
|
||||
if (aApzc->VisibleRegionContains(LayerPoint(untransformed.x, untransformed.y))) {
|
||||
APZC_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n", untransformed.x, untransformed.y, aApzc);
|
||||
// This code is not run in the recursion at layer P.
|
||||
// aTransformToApzcOut is OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L.
|
||||
aTransformToApzcOut = ancestorUntransform;
|
||||
// aTransformToScreenOut is LA.Inverse() * MC * NC * OC at recursion level for L.
|
||||
aTransformToScreenOut = asyncUntransform * aApzc->GetAncestorTransform();
|
||||
return aApzc;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -236,11 +236,13 @@ public:
|
||||
used by other production code.
|
||||
*/
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
|
||||
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint, gfx3DMatrix& aTransformToApzcOut,
|
||||
gfx3DMatrix& aTransformToScreenOut);
|
||||
private:
|
||||
/* Recursive helpers */
|
||||
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint);
|
||||
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint,
|
||||
gfx3DMatrix& aTransformToApzcOut, gfx3DMatrix& aTransformToScreenOut);
|
||||
|
||||
/**
|
||||
* Recursive helper function to build the APZC tree. The tree of APZC instances has
|
||||
|
@ -247,64 +247,6 @@ WidgetSpaceToCompensatedViewportSpace(const ScreenPoint& aPoint,
|
||||
return aPoint / aCurrentZoom;
|
||||
}
|
||||
|
||||
nsEventStatus
|
||||
AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
nsInputEvent* aOutEvent)
|
||||
{
|
||||
CSSToScreenScale currentResolution;
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
currentResolution = mFrameMetrics.CalculateResolution();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
MultiTouchInput event(static_cast<const nsTouchEvent&>(aEvent));
|
||||
status = ReceiveInputEvent(event);
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_EVENT: {
|
||||
MultiTouchInput event(static_cast<const nsMouseEvent&>(aEvent));
|
||||
status = ReceiveInputEvent(event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
status = nsEventStatus_eIgnore;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (aEvent.eventStructType) {
|
||||
case NS_TOUCH_EVENT: {
|
||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aOutEvent);
|
||||
const nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches;
|
||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
||||
dom::Touch* touch = touches[i];
|
||||
if (touch) {
|
||||
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
touch->mRefPoint.x, touch->mRefPoint.y)),
|
||||
currentResolution);
|
||||
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
touch->mRefPoint = nsIntPoint(refPoint.x, refPoint.y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
CSSPoint refCSSPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
aOutEvent->refPoint.x, aOutEvent->refPoint.y)),
|
||||
currentResolution);
|
||||
LayoutDevicePoint refPoint = refCSSPoint * mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
aOutEvent->refPoint = LayoutDeviceIntPoint(refPoint.x, refPoint.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
|
||||
// If we may have touch listeners, we enable the machinery that allows touch
|
||||
// listeners to preventDefault any touch inputs. This should not happen unless
|
||||
|
@ -100,19 +100,6 @@ public:
|
||||
*/
|
||||
nsEventStatus ReceiveInputEvent(const InputData& aEvent);
|
||||
|
||||
/**
|
||||
* Special handler for nsInputEvents. Also sets |aOutEvent| (which is assumed
|
||||
* to be an already-existing instance of an nsInputEvent which may be an
|
||||
* nsTouchEvent) to have its touch points in DOM space. This is so that the
|
||||
* touches can be passed through the DOM and content can handle them.
|
||||
*
|
||||
* NOTE: Be careful of invoking the nsInputEvent variant. This can only be
|
||||
* called on the main thread. See widget/InputData.h for more information on
|
||||
* why we have InputData and nsInputEvent separated.
|
||||
*/
|
||||
nsEventStatus ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
nsInputEvent* aOutEvent);
|
||||
|
||||
/**
|
||||
* Updates the composition bounds, i.e. the dimensions of the final size of
|
||||
* the frame this is tied to during composition onto, in device pixels. In
|
||||
@ -642,9 +629,15 @@ private:
|
||||
* hit-testing to see which APZC instance should handle touch events.
|
||||
*/
|
||||
public:
|
||||
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransform) {
|
||||
void SetLayerHitTestData(const LayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
|
||||
const gfx3DMatrix& aTransformForLayer) {
|
||||
mVisibleRect = aRect;
|
||||
mCSSTransform = aTransform;
|
||||
mAncestorTransform = aTransformToLayer;
|
||||
mCSSTransform = aTransformForLayer;
|
||||
}
|
||||
|
||||
gfx3DMatrix GetAncestorTransform() const {
|
||||
return mAncestorTransform;
|
||||
}
|
||||
|
||||
gfx3DMatrix GetCSSTransform() const {
|
||||
@ -661,8 +654,10 @@ private:
|
||||
* applied to any layers, whether they are CSS transforms or async
|
||||
* transforms. */
|
||||
LayerRect mVisibleRect;
|
||||
/* This is the cumulative layer transform from the parent APZC down to this
|
||||
* one. */
|
||||
/* This is the cumulative CSS transform for all the layers between the parent
|
||||
* APZC and this one (not inclusive) */
|
||||
gfx3DMatrix mAncestorTransform;
|
||||
/* This is the CSS transform for this APZC's layer. */
|
||||
gfx3DMatrix mCSSTransform;
|
||||
};
|
||||
|
||||
|
@ -376,16 +376,17 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
||||
ScopedLayerTreeRegistration controller(0, root, mcc);
|
||||
|
||||
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
|
||||
gfx3DMatrix matrix;
|
||||
|
||||
// No APZC attached so hit testing will return no APZC at (20,20)
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20));
|
||||
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20), matrix, matrix);
|
||||
AsyncPanZoomController* nullAPZC = nullptr;
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// Now we have a root APZC that will match the page
|
||||
SetScrollableFrameMetrics(root, FrameMetrics::ROOT_SCROLL_ID, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
@ -393,28 +394,28 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
||||
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
// Now test hit testing when we have two scrollable layers
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1, mcc);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(15, 15), matrix, matrix);
|
||||
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(15, 15)
|
||||
|
||||
// Hit test ouside the reach of layer[3,4] but inside root
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(90, 90));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(90, 90), matrix, matrix);
|
||||
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerIntPoint(90, 90)
|
||||
|
||||
// Hit test ouside the reach of any layer
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10), matrix, matrix);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10), matrix, matrix);
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// Test layer transform
|
||||
@ -422,12 +423,12 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
||||
transform.ScalePost(0.1, 0.1, 1);
|
||||
root->SetBaseTransform(transform);
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(50, 50), matrix, matrix); // This point is now outside the root layer
|
||||
EXPECT_EQ(nullAPZC, hit.get());
|
||||
|
||||
// This hit test will hit both layers[3] and layers[4]; layers[4] is later in the tree so
|
||||
// it is a better match
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
|
||||
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 20)
|
||||
|
||||
@ -436,7 +437,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
||||
// layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2)
|
||||
// Does not contain (2, 2)
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(2, 2), matrix, matrix);
|
||||
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 20)
|
||||
|
||||
@ -457,7 +458,7 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
|
||||
|
||||
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
|
||||
// layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1, 45));
|
||||
hit = manager->GetTargetAPZC(ScreenPoint(1, 45), matrix, matrix);
|
||||
EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
|
||||
// expect hit point at LayerPoint(20, 29)
|
||||
|
||||
|
@ -222,8 +222,9 @@ if test "$CPU_ARCH" = "arm"; then
|
||||
dnl This matches media/webrtc/trunk/webrtc/build/common.gypi.
|
||||
if test -n "$ARM_ARCH"; then
|
||||
if test "$ARM_ARCH" -lt 7; then
|
||||
BUILD_ARM_NEON=0
|
||||
BUILD_ARM_NEON=
|
||||
else
|
||||
AC_DEFINE(BUILD_ARM_NEON)
|
||||
BUILD_ARM_NEON=1
|
||||
fi
|
||||
fi
|
||||
|
@ -35,6 +35,7 @@ simple_events = [
|
||||
'CFStateChangeEvent',
|
||||
'DataErrorEvent',
|
||||
'IccCardLockErrorEvent',
|
||||
'MozEmergencyCbModeEvent',
|
||||
'MozWifiStatusChangeEvent',
|
||||
'MozWifiConnectionInfoEvent',
|
||||
'MozCellBroadcastEvent',
|
||||
|
@ -163,7 +163,7 @@ public final class GeckoProfile {
|
||||
|
||||
private static File getGuestDir(Context context) {
|
||||
if (mGuestDir == null) {
|
||||
mGuestDir = context.getDir("guest", Context.MODE_PRIVATE);
|
||||
mGuestDir = context.getFileStreamPath("guest");
|
||||
}
|
||||
return mGuestDir;
|
||||
}
|
||||
@ -181,8 +181,12 @@ public final class GeckoProfile {
|
||||
public static boolean maybeCleanupGuestProfile(final Context context) {
|
||||
// Don't use profile.getDir() here, so that we don't accidently create the dir
|
||||
File guestDir = getGuestDir(context);
|
||||
if (!guestDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final GeckoProfile profile = getGuestProfile(context);
|
||||
if (guestDir.exists() && !profile.locked()) {
|
||||
if (!profile.locked()) {
|
||||
// if the guest dir exists, but its unlocked, delete it
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
|
@ -57,7 +57,7 @@ class MarionetteClient(object):
|
||||
"socket closed?",
|
||||
status=ErrorCodes.INVALID_RESPONSE)
|
||||
|
||||
def connect(self, timeout=180.0):
|
||||
def connect(self, timeout=240.0):
|
||||
""" Connect to the server and process the hello message we expect
|
||||
to receive in response.
|
||||
"""
|
||||
|
74
toolkit/devtools/server/tests/unit/test_sourcemaps-10.js
Normal file
74
toolkit/devtools/server/tests/unit/test_sourcemaps-10.js
Normal file
@ -0,0 +1,74 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check that we source map frame locations for the frame we are paused at.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
const promise = devtools.require("sdk/core/promise");
|
||||
Components.utils.import('resource:///modules/devtools/SourceMap.jsm');
|
||||
|
||||
function run_test() {
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-source-map");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-source-map", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
promise.resolve(define_code())
|
||||
.then(run_code)
|
||||
.then(test_frame_location)
|
||||
.then(null, error => {
|
||||
dump(error + "\n");
|
||||
dump(error.stack);
|
||||
do_check_true(false);
|
||||
})
|
||||
.then(() => {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function define_code() {
|
||||
let { code, map } = (new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "a.js", "function a() {\n"),
|
||||
new SourceNode(2, 0, "a.js", " b();\n"),
|
||||
new SourceNode(3, 0, "a.js", "}\n"),
|
||||
new SourceNode(1, 0, "b.js", "function b() {\n"),
|
||||
new SourceNode(2, 0, "b.js", " c();\n"),
|
||||
new SourceNode(3, 0, "b.js", "}\n"),
|
||||
new SourceNode(1, 0, "c.js", "function c() {\n"),
|
||||
new SourceNode(2, 0, "c.js", " debugger;\n"),
|
||||
new SourceNode(3, 0, "c.js", "}\n"),
|
||||
])).toStringWithSourceMap({
|
||||
file: "abc.js",
|
||||
sourceRoot: "http://example.com/www/js/"
|
||||
});
|
||||
|
||||
code += "//# sourceMappingURL=data:text/json," + map.toString();
|
||||
|
||||
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
|
||||
"http://example.com/www/js/abc.js", 1);
|
||||
}
|
||||
|
||||
function run_code() {
|
||||
const d = promise.defer();
|
||||
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
d.resolve(aPacket);
|
||||
gThreadClient.resume();
|
||||
});
|
||||
gDebuggee.a();
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
function test_frame_location({ frame: { where: { url, line, column } } }) {
|
||||
do_check_eq(url, "http://example.com/www/js/c.js");
|
||||
do_check_eq(line, 2);
|
||||
do_check_eq(column, 0);
|
||||
}
|
84
toolkit/devtools/server/tests/unit/test_sourcemaps-11.js
Normal file
84
toolkit/devtools/server/tests/unit/test_sourcemaps-11.js
Normal file
@ -0,0 +1,84 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check that we source map frame locations returned by "frames" requests.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
const promise = devtools.require("sdk/core/promise");
|
||||
Components.utils.import('resource:///modules/devtools/SourceMap.jsm');
|
||||
|
||||
function run_test() {
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-source-map");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestTabAndResume(gClient, "test-source-map", function(aResponse, aTabClient, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
promise.resolve(define_code())
|
||||
.then(run_code)
|
||||
.then(test_frames)
|
||||
.then(null, error => {
|
||||
dump(error + "\n");
|
||||
dump(error.stack);
|
||||
do_check_true(false);
|
||||
})
|
||||
.then(() => {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function define_code() {
|
||||
let { code, map } = (new SourceNode(null, null, null, [
|
||||
new SourceNode(1, 0, "a.js", "function a() {\n"),
|
||||
new SourceNode(2, 0, "a.js", " b();\n"),
|
||||
new SourceNode(3, 0, "a.js", "}\n"),
|
||||
new SourceNode(1, 0, "b.js", "function b() {\n"),
|
||||
new SourceNode(2, 0, "b.js", " c();\n"),
|
||||
new SourceNode(3, 0, "b.js", "}\n"),
|
||||
new SourceNode(1, 0, "c.js", "function c() {\n"),
|
||||
new SourceNode(2, 0, "c.js", " debugger;\n"),
|
||||
new SourceNode(3, 0, "c.js", "}\n"),
|
||||
])).toStringWithSourceMap({
|
||||
file: "abc.js",
|
||||
sourceRoot: "http://example.com/www/js/"
|
||||
});
|
||||
|
||||
code += "//# sourceMappingURL=data:text/json," + map.toString();
|
||||
|
||||
Components.utils.evalInSandbox(code, gDebuggee, "1.8",
|
||||
"http://example.com/www/js/abc.js", 1);
|
||||
}
|
||||
|
||||
function run_code() {
|
||||
const d = promise.defer();
|
||||
gClient.addOneTimeListener("paused", function () {
|
||||
gThreadClient.getFrames(0, 3, function (aResponse) {
|
||||
d.resolve(aResponse);
|
||||
gThreadClient.resume();
|
||||
})
|
||||
});
|
||||
gDebuggee.a();
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
function test_frames({ error, frames }) {
|
||||
do_check_true(!error);
|
||||
do_check_eq(frames.length, 3);
|
||||
check_frame(frames[0], "http://example.com/www/js/c.js");
|
||||
check_frame(frames[1], "http://example.com/www/js/b.js");
|
||||
check_frame(frames[2], "http://example.com/www/js/a.js");
|
||||
}
|
||||
|
||||
function check_frame({ where: { url, line, column } }, aExpectedUrl) {
|
||||
do_check_eq(url, aExpectedUrl);
|
||||
do_check_eq(line, 2);
|
||||
do_check_eq(column, 0);
|
||||
}
|
@ -113,6 +113,8 @@ skip-if = toolkit == "gonk"
|
||||
reason = bug 820380
|
||||
[test_sourcemaps-08.js]
|
||||
[test_sourcemaps-09.js]
|
||||
[test_sourcemaps-10.js]
|
||||
[test_sourcemaps-11.js]
|
||||
[test_objectgrips-01.js]
|
||||
[test_objectgrips-02.js]
|
||||
[test_objectgrips-03.js]
|
||||
|
Loading…
Reference in New Issue
Block a user