Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-07-30 18:08:18 -04:00
commit 02d1dbe0d8
46 changed files with 2084 additions and 736 deletions

View File

@ -30,7 +30,7 @@ LIBS += \
$(DEPTH)/widget/gonk/libdisplay/$(LIB_PREFIX)display.$(LIB_SUFFIX) \
$(MOZ_ZLIB_LIBS) \
$(NULL)
ifeq (17,$(ANDROID_VERSION))
ifeq (18,$(ANDROID_VERSION))
LIBS += \
-lgui \
-lsuspend \

View File

@ -1,4 +1,4 @@
{
"revision": "10f16f6a15f8a1c4b910548b4d0968baaac21c91",
"revision": "7e8284bea36c2d9307f919090922d3885f67eafc",
"repo_path": "/integration/gaia-central"
}

View File

@ -214,7 +214,7 @@ if test -n "$gonkdir" ; then
AC_DEFINE(MOZ_OMX_DECODER)
AC_SUBST(MOZ_OMX_DECODER)
;;
17)
18)
GONK_INCLUDES="-I$gonkdir/frameworks/native/include"
;;
*)

View File

@ -45,16 +45,21 @@ const ContentPanning = {
this.watchedEventsType = 'mouse';
}
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
// If we are using an AsyncPanZoomController for the parent frame,
// it will handle subframe scrolling too. We don't need to listen for
// these events.
if (!this._asyncPanZoomForViewportFrame) {
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
events.forEach(function(type) {
// Using the system group for mouse/touch events to avoid
// missing events if .stopPropagation() has been called.
els.addSystemEventListener(global, type,
this.handleEvent.bind(this),
/* useCapture = */ false);
}.bind(this));
events.forEach(function(type) {
// Using the system group for mouse/touch events to avoid
// missing events if .stopPropagation() has been called.
els.addSystemEventListener(global, type,
this.handleEvent.bind(this),
/* useCapture = */ false);
}.bind(this));
}
addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));

View File

@ -905,9 +905,6 @@ ContactDB.prototype = {
}
xIndex++;
}
if (!x) {
return sortOrder == "descending" ? 1 : -1;
}
while (yIndex < sortBy.length && !y) {
y = b.properties[sortBy[yIndex]];
if (y) {
@ -915,6 +912,18 @@ ContactDB.prototype = {
}
yIndex++;
}
if (!x) {
if (!y) {
let px, py;
px = JSON.stringify(a.published);
py = JSON.stringify(b.published);
if (px && py) {
return px.localeCompare(py);
}
} else {
return sortOrder == 'descending' ? 1 : -1;
}
}
if (!y) {
return sortOrder == "ascending" ? 1 : -1;
}

View File

@ -61,6 +61,24 @@ var c5 = {
nickname: "empty"
};
var c6 = {
name: "e",
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var c7 = {
name: "e",
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var c8 = {
name: "e",
familyName: ["e","e","e"],
givenName: ["e","e","e"],
};
var adr1 = {
type: "work",
streetAddress: "street 1",
@ -1338,6 +1356,64 @@ var steps = [
}
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact();
createResult1.init(c7);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c7, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact();
createResult1.init(c6);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c6, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact();
createResult1.init(c8);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c8, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting with published");
var options = {sortBy: "familyName",
sortOrder: "descending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 3, "3 results");
ok(req.result[0].published < req.result[1].published, "Right sorting order");
ok(req.result[1].published < req.result[2].published, "Right sorting order");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with properties2");
createResult2 = new mozContact();

View File

@ -1032,6 +1032,20 @@ TabChild::GetDOMWindowUtils()
return utils.forget();
}
already_AddRefed<nsIDOMWindowUtils>
TabChild::GetDOMWindowUtils(nsIContent* content)
{
nsCOMPtr<nsIDOMWindowUtils> utils;
nsIDocument* doc = content->GetCurrentDoc();
if (doc) {
nsCOMPtr<nsIDOMWindow> window = doc->GetDefaultView();
if (window) {
utils = do_GetInterface(window);
}
}
return utils.forget();
}
static nsInterfaceHashtable<nsPtrHashKey<PContentDialogChild>, nsIDialogParamBlock> gActiveDialogs;
NS_IMETHODIMP
@ -1459,32 +1473,34 @@ TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
aMessageName, false, &cloneData, nullptr, nullptr);
}
static void
ScrollWindowTo(nsIDOMWindow* aWindow, const CSSPoint& aPoint)
{
nsGlobalWindow* window = static_cast<nsGlobalWindow*>(aWindow);
nsIScrollableFrame* sf = window->GetScrollFrame();
if (sf) {
sf->ScrollToCSSPixelsApproximate(aPoint);
}
}
bool
TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
{
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
MOZ_ASSERT(aFrameMetrics.mScrollId != FrameMetrics::NULL_SCROLL_ID);
if (aFrameMetrics.mScrollId == FrameMetrics::ROOT_SCROLL_ID) {
uint32_t presShellId;
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
nsresult rv = utils->GetPresShellId(&presShellId);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (NS_SUCCEEDED(rv) && aFrameMetrics.mPresShellId != presShellId) {
// We've recieved a message that is out of date and we want to ignore.
// However we can't reply without painting so we reply by painting the
// exact same thing as we did before.
return ProcessUpdateFrame(mLastMetrics);
if (NS_SUCCEEDED(rv) && aFrameMetrics.mPresShellId == presShellId) {
return ProcessUpdateFrame(aFrameMetrics);
}
return ProcessUpdateFrame(aFrameMetrics);
} else {
// aFrameMetrics.mScrollId is not FrameMetrics::ROOT_SCROLL_ID,
// so we are trying to update a subframe. This requires special handling.
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(
aFrameMetrics.mScrollId);
if (content) {
return ProcessUpdateSubframe(content, aFrameMetrics);
}
}
// We've recieved a message that is out of date and we want to ignore.
// However we can't reply without painting so we reply by painting the
// exact same thing as we did before.
return ProcessUpdateFrame(mLastMetrics);
}
bool
@ -1533,51 +1549,60 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mWebNav);
// set the scroll port size, which determines the scroll range
utils->SetScrollPositionClampingScrollPortSize(
cssCompositedRect.width, cssCompositedRect.height);
ScrollWindowTo(window, aFrameMetrics.mScrollOffset);
LayoutDeviceToLayerScale resolution =
aFrameMetrics.CalculateResolution()
/ aFrameMetrics.mDevPixelsPerCSSPixel
* ScreenToLayerScale(1);
// scroll the window to the desired spot
nsIScrollableFrame* sf = static_cast<nsGlobalWindow*>(window.get())->GetScrollFrame();
if (sf) {
sf->ScrollToCSSPixelsApproximate(aFrameMetrics.mScrollOffset);
}
// set the resolution
LayoutDeviceToLayerScale resolution = aFrameMetrics.CalculateResolution()
/ aFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
utils->SetResolution(resolution.scale, resolution.scale);
if (aFrameMetrics.mScrollId != FrameMetrics::NULL_SCROLL_ID) {
SetDisplayPort(aFrameMetrics);
// and set the display port
nsCOMPtr<nsIDOMDocument> domDoc;
mWebNav->GetDocument(getter_AddRefs(domDoc));
if (domDoc) {
nsCOMPtr<nsIDOMElement> element;
domDoc->GetDocumentElement(getter_AddRefs(element));
if (element) {
utils->SetDisplayPortForElement(
aFrameMetrics.mDisplayPort.x, aFrameMetrics.mDisplayPort.y,
aFrameMetrics.mDisplayPort.width, aFrameMetrics.mDisplayPort.height,
element);
}
}
mLastMetrics = aFrameMetrics;
return true;
}
void
TabChild::SetDisplayPort(const FrameMetrics& aFrameMetrics)
bool
TabChild::ProcessUpdateSubframe(nsIContent* aContent,
const FrameMetrics& aMetrics)
{
nsCOMPtr<nsIDOMDocument> domDoc;
mWebNav->GetDocument(getter_AddRefs(domDoc));
if (!domDoc) {
return;
// scroll the frame to the desired spot
nsIScrollableFrame* scrollFrame = nsLayoutUtils::FindScrollableFrameFor(aMetrics.mScrollId);
if (scrollFrame) {
scrollFrame->ScrollToCSSPixelsApproximate(aMetrics.mScrollOffset);
}
// nsLayoutUtils::FindContentFor() doesn't provide a look-up for the root
// scroll idea. This is because the root scroll ID could refer to a different
// element in the DOM when navigating to a new document.
nsCOMPtr<nsIDOMElement> element;
if (aFrameMetrics.mScrollId == FrameMetrics::ROOT_SCROLL_ID) {
domDoc->GetDocumentElement(getter_AddRefs(element));
} else {
element = do_QueryInterface(nsLayoutUtils::FindContentFor(
aFrameMetrics.mScrollId));
}
if (element) {
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils(aContent));
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
if (utils && element) {
// and set the display port
utils->SetDisplayPortForElement(
aFrameMetrics.mDisplayPort.x, aFrameMetrics.mDisplayPort.y,
aFrameMetrics.mDisplayPort.width, aFrameMetrics.mDisplayPort.height,
aMetrics.mDisplayPort.x, aMetrics.mDisplayPort.y,
aMetrics.mDisplayPort.width, aMetrics.mDisplayPort.height,
element);
}
return true;
}
bool

View File

@ -378,10 +378,7 @@ private:
void DestroyWindow();
void SetProcessNameToAppName();
bool ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
// Update the DOM with the given display port. Finds the element based on
// the aFrameMetrics.mScrollId.
void SetDisplayPort(const FrameMetrics& aFrameMetrics);
bool ProcessUpdateSubframe(nsIContent* aContent, const FrameMetrics& aMetrics);
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
void DoFakeShow();
@ -426,7 +423,11 @@ private:
bool* aWindowIsNew,
nsIDOMWindow** aReturn);
// Get the DOMWindowUtils for the top-level window in this tab.
already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
// Get the DOMWindowUtils for the window corresponding to the givent content
// element. This might be an iframe inside the tab, for instance.
already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils(nsIContent* aContent);
class CachedFileDescriptorInfo;
class CachedFileDescriptorCallbackRunnable;

View File

@ -13,5 +13,6 @@ disabled = Bug 808783
[test_mobile_data_location.js]
[test_mobile_data_state.js]
[test_mobile_mmi.js]
[test_mobile_roaming_preference.js]
[test_call_barring_get_option.js]
[test_call_barring_set_error.js]

View File

@ -0,0 +1,98 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("mobileconnection", true, document);
let connection = navigator.mozMobileConnection;
ok(connection instanceof MozMobileConnection,
"connection is instanceof " + connection.constructor);
function failedToSetRoamingPreference(mode, expectedErrorMessage, callback) {
let request = connection.setRoamingPreference(mode);
ok(request instanceof DOMRequest,
"request instanceof " + request.constructor);
request.onsuccess = function onsuccess() {
ok(false, "Should not be here !!");
callback();
}
request.onerror = function onerror() {
is(request.error.name, expectedErrorMessage);
callback();
}
}
function testSetRoamingPreferenceWithNullValue() {
log("test setRoamingPreference(null)");
failedToSetRoamingPreference(null, "InvalidParameter", runNextTest);
}
function testSetRoamingPreferenceWithInvalidValue() {
log("test setRoamingPreference(\"InvalidValue\")");
failedToSetRoamingPreference("InvalidValue", "InvalidParameter", runNextTest);
}
function testSetRoamingPreferenceToHome() {
log("test setRoamingPreference(\"home\")");
// TODO: Bug 896394.
// Currently emulator run as GSM mode by default. So we expect to get a
// 'RequestNotSupported' error here.
failedToSetRoamingPreference("home", "RequestNotSupported", runNextTest);
}
function testGetRoamingPreference() {
log("test getRoamingPreference()");
// TODO: Bug 896394.
// Currently emulator run as GSM mode by default. So we expect to get a
// 'RequestNotSupported' error here.
let request = connection.getRoamingPreference();
ok(request instanceof DOMRequest,
"request instanceof " + request.constructor);
request.onsuccess = function onsuccess() {
ok(false, "Should not be here !!");
runNextTest();
}
request.onerror = function onerror() {
is(request.error.name, "RequestNotSupported");
runNextTest();
}
}
let tests = [
testSetRoamingPreferenceWithNullValue,
testSetRoamingPreferenceWithInvalidValue,
testSetRoamingPreferenceToHome,
testGetRoamingPreference
];
function runNextTest() {
let test = tests.shift();
if (!test) {
cleanUp();
return;
}
test();
}
function cleanUp() {
SpecialPowers.removePermission("mobileconnection", document);
finish();
}
runNextTest();

View File

@ -1616,7 +1616,7 @@ let RIL = {
if (roamingMode === -1) {
options.errorMsg = GECKO_ERROR_INVALID_PARAMETER;
this.sendDOMMessage(options);
this.sendChromeMessage(options);
return;
}
@ -5649,22 +5649,22 @@ RIL[REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE] = null;
RIL[REQUEST_CDMA_SET_ROAMING_PREFERENCE] = function REQUEST_CDMA_SET_ROAMING_PREFERENCE(length, options) {
if (options.rilRequestError) {
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendDOMMessage(options);
this.sendChromeMessage(options);
return;
}
this.sendDOMMessage(options);
this.sendChromeMessage(options);
};
RIL[REQUEST_CDMA_QUERY_ROAMING_PREFERENCE] = function REQUEST_CDMA_QUERY_ROAMING_PREFERENCE(length, options) {
if (options.rilRequestError) {
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendDOMMessage(options);
this.sendChromeMessage(options);
return;
}
let mode = Buf.readUint32List();
options.mode = CDMA_ROAMING_PREFERENCE_TO_GECKO[mode[0]];
this.sendDOMMessage(options);
this.sendChromeMessage(options);
};
RIL[REQUEST_SET_TTY_MODE] = null;
RIL[REQUEST_QUERY_TTY_MODE] = null;

View File

@ -86,21 +86,29 @@ this.PduHelper = {
/**
* Tag tokens
*
* @see WAP-183-ProvCont-20010724-A, clause 8.1
* @see WAP-183-ProvCont-20010724-A, clause 8.1 for code page 0
* @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.1 for code page 1
*/
const CP_TAG_FIELDS = (function () {
let names = {};
function add(name, number) {
function add(name, codepage, number) {
let entry = {
name: name,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("wap-provisioningdoc", 0x05);
add("characteristic", 0x06);
add("parm", 0x07);
// Code page 0
add("wap-provisioningdoc", 0, 0x05);
add("characteristic", 0, 0x06);
add("parm", 0, 0x07);
// Code page 1
add("characteristic", 1, 0x06);
add("parm", 1, 0x07);
return names;
})();
@ -108,155 +116,221 @@ const CP_TAG_FIELDS = (function () {
/**
* Attribute Tokens
*
* @see WAP-183-ProvCont-20010724-A, clause 8.2
* @see WAP-183-ProvCont-20010724-A, clause 8.2 for code page 0
* @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.2 for code page 1
*/
const CP_ATTRIBUTE_FIELDS = (function () {
let names = {};
function add(name, value, number) {
function add(name, value, codepage, number) {
let entry = {
name: name,
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("name", "", 0x05);
add("value", "", 0x06);
add("name", "NAME", 0x07);
add("name", "NAP-ADDRESS", 0x08);
add("name", "NAP-ADDRTYPE", 0x09);
add("name", "CALLTYPE", 0x0A);
add("name", "VALIDUNTIL", 0x0B);
add("name", "AUTHTYPE", 0x0C);
add("name", "AUTHNAME", 0x0D);
add("name", "AUTHSECRET", 0x0E);
add("name", "LINGER", 0x0F);
add("name", "BEARER", 0x10);
add("name", "NAPID", 0x11);
add("name", "COUNTRY", 0x12);
add("name", "NETWORK", 0x13);
add("name", "INTERNET", 0x14);
add("name", "PROXY-ID", 0x15);
add("name", "PROXY-PROVIDER-ID", 0x16);
add("name", "DOMAIN", 0x17);
add("name", "PROVURL", 0x18);
add("name", "PXAUTH-TYPE", 0x19);
add("name", "PXAUTH-ID", 0x1A);
add("name", "PXAUTH-PW", 0x1B);
add("name", "STARTPAGE", 0x1C);
add("name", "BASAUTH-ID", 0x1D);
add("name", "BASAUTH-PW", 0x1E);
add("name", "PUSHENABLED", 0x1F);
add("name", "PXADDR", 0x20);
add("name", "PXADDRTYPE", 0x21);
add("name", "TO-NAPID", 0x22);
add("name", "PORTNBR", 0x23);
add("name", "SERVICE", 0x24);
add("name", "LINKSPEED", 0x25);
add("name", "DNLINKSPEED", 0x26);
add("name", "LOCAL-ADDR", 0x27);
add("name", "LOCAL-ADDRTYPE", 0x28);
add("name", "CONTEXT-ALLOW", 0x29);
add("name", "TRUST", 0x2A);
add("name", "MASTER", 0x2B);
add("name", "SID", 0x2C);
add("name", "SOC", 0x2D);
add("name", "WSP-VERSION", 0x2E);
add("name", "PHYSICAL-PROXY-ID", 0x2F);
add("name", "CLIENT-ID", 0x30);
add("name", "DELIVERY-ERR-PDU", 0x31);
add("name", "DELIVERY-ORDER", 0x32);
add("name", "TRAFFIC-CLASS", 0x33);
add("name", "MAX-SDU-SIZE", 0x34);
add("name", "MAX-BITRATE-UPLINK", 0x35);
add("name", "MAX-BITRATE-DNLINK", 0x36);
add("name", "RESIDUAL-BER", 0x37);
add("name", "SDU-ERROR-RATIO", 0x38);
add("name", "TRAFFIC-HANDL-PRIO", 0x39);
add("name", "TRANSFER-DELAY", 0x3A);
add("name", "GUARANTEED-BITRATE-UPLINK", 0x3B);
add("name", "GUARANTEED-BITRATE-DNLINK", 0x3C);
add("version", "", 0x45);
add("version", "1.0", 0x46);
add("type", "", 0x50);
add("type", "PXLOGICAL", 0x51);
add("type", "PXPHYSICAL", 0x52);
add("type", "PORT", 0x53);
add("type", "VALIDITY", 0x54);
add("type", "NAPDEF", 0x55);
add("type", "BOOTSTRAP", 0x56);
// Code page 0
add("name", "", 0, 0x05);
add("value", "", 0, 0x06);
add("name", "NAME", 0, 0x07);
add("name", "NAP-ADDRESS", 0, 0x08);
add("name", "NAP-ADDRTYPE", 0, 0x09);
add("name", "CALLTYPE", 0, 0x0A);
add("name", "VALIDUNTIL", 0, 0x0B);
add("name", "AUTHTYPE", 0, 0x0C);
add("name", "AUTHNAME", 0, 0x0D);
add("name", "AUTHSECRET", 0, 0x0E);
add("name", "LINGER", 0, 0x0F);
add("name", "BEARER", 0, 0x10);
add("name", "NAPID", 0, 0x11);
add("name", "COUNTRY", 0, 0x12);
add("name", "NETWORK", 0, 0x13);
add("name", "INTERNET", 0, 0x14);
add("name", "PROXY-ID", 0, 0x15);
add("name", "PROXY-PROVIDER-ID", 0, 0x16);
add("name", "DOMAIN", 0, 0x17);
add("name", "PROVURL", 0, 0x18);
add("name", "PXAUTH-TYPE", 0, 0x19);
add("name", "PXAUTH-ID", 0, 0x1A);
add("name", "PXAUTH-PW", 0, 0x1B);
add("name", "STARTPAGE", 0, 0x1C);
add("name", "BASAUTH-ID", 0, 0x1D);
add("name", "BASAUTH-PW", 0, 0x1E);
add("name", "PUSHENABLED", 0, 0x1F);
add("name", "PXADDR", 0, 0x20);
add("name", "PXADDRTYPE", 0, 0x21);
add("name", "TO-NAPID", 0, 0x22);
add("name", "PORTNBR", 0, 0x23);
add("name", "SERVICE", 0, 0x24);
add("name", "LINKSPEED", 0, 0x25);
add("name", "DNLINKSPEED", 0, 0x26);
add("name", "LOCAL-ADDR", 0, 0x27);
add("name", "LOCAL-ADDRTYPE", 0, 0x28);
add("name", "CONTEXT-ALLOW", 0, 0x29);
add("name", "TRUST", 0, 0x2A);
add("name", "MASTER", 0, 0x2B);
add("name", "SID", 0, 0x2C);
add("name", "SOC", 0, 0x2D);
add("name", "WSP-VERSION", 0, 0x2E);
add("name", "PHYSICAL-PROXY-ID", 0, 0x2F);
add("name", "CLIENT-ID", 0, 0x30);
add("name", "DELIVERY-ERR-PDU", 0, 0x31);
add("name", "DELIVERY-ORDER", 0, 0x32);
add("name", "TRAFFIC-CLASS", 0, 0x33);
add("name", "MAX-SDU-SIZE", 0, 0x34);
add("name", "MAX-BITRATE-UPLINK", 0, 0x35);
add("name", "MAX-BITRATE-DNLINK", 0, 0x36);
add("name", "RESIDUAL-BER", 0, 0x37);
add("name", "SDU-ERROR-RATIO", 0, 0x38);
add("name", "TRAFFIC-HANDL-PRIO", 0, 0x39);
add("name", "TRANSFER-DELAY", 0, 0x3A);
add("name", "GUARANTEED-BITRATE-UPLINK", 0, 0x3B);
add("name", "GUARANTEED-BITRATE-DNLINK", 0, 0x3C);
add("version", "", 0, 0x45);
add("version", "1.0", 0, 0x46);
add("type", "", 0, 0x50);
add("type", "PXLOGICAL", 0, 0x51);
add("type", "PXPHYSICAL", 0, 0x52);
add("type", "PORT", 0, 0x53);
add("type", "VALIDITY", 0, 0x54);
add("type", "NAPDEF", 0, 0x55);
add("type", "BOOTSTRAP", 0, 0x56);
/*
* Mark out VENDORCONFIG so if it is contained in message, parse
* will failed and raw data is returned.
*/
// add("type", "VENDORCONFIG", 0x57);
add("type", "CLIENTIDENTITY", 0x58);
add("type", "PXAUTHINFO", 0x59);
add("type", "NAPAUTHINFO", 0x5A);
// add("type", "VENDORCONFIG", 0, 0x57);
add("type", "CLIENTIDENTITY", 0, 0x58);
add("type", "PXAUTHINFO", 0, 0x59);
add("type", "NAPAUTHINFO", 0, 0x5A);
// Code page 1
add("name", "", 1, 0x05);
add("value", "", 1, 0x06);
add("name", "NAME", 1, 0x07);
add("name", "INTERNET", 1, 0x14);
add("name", "STARTPAGE", 1, 0x1C);
add("name", "TO-NAPID", 1, 0x22);
add("name", "PORTNBR", 1, 0x23);
add("name", "SERVICE", 1, 0x24);
add("name", "AACCEPT", 1, 0x2E);
add("name", "AAUTHDATA", 1, 0x2F);
add("name", "AAUTHLEVEL", 1, 0x30);
add("name", "AAUTHNAME", 1, 0x31);
add("name", "AAUTHSECRET", 1, 0x32);
add("name", "AAUTHTYPE", 1, 0x33);
add("name", "ADDR", 1, 0x34);
add("name", "ADDRTYPE", 1, 0x35);
add("name", "APPID", 1, 0x36);
add("name", "APROTOCOL", 1, 0x37);
add("name", "PROVIDER-ID", 1, 0x38);
add("name", "TO-PROXY", 1, 0x39);
add("name", "URI", 1, 0x3A);
add("name", "RULE", 1, 0x3B);
add("type", "", 1, 0x50);
add("type", "PORT", 1, 0x53);
add("type", "APPLICATION", 1, 0x55);
add("type", "APPADDR", 1, 0x56);
add("type", "APPAUTH", 1, 0x57);
add("type", "CLIENTIDENTITY", 1, 0x58);
add("type", "RESOURCE", 1, 0x59);
return names;
})();
/**
* Value Tokens
*
* @see WAP-183-ProvCont-20010724-A, clause 8.3 for code page 0
* @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.3 for code page 1
*/
const CP_VALUE_FIELDS = (function () {
let names = {};
function add(value, number) {
function add(value, codepage, number) {
let entry = {
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("IPV4", 0x85);
add("IPV6", 0x86);
add("E164", 0x87);
add("ALPHA", 0x88);
add("APN", 0x89);
add("SCODE", 0x8A);
add("TETRA-ITSI", 0x8B);
add("MAN", 0x8C);
add("ANALOG-MODEM", 0x90);
add("V.120", 0x91);
add("V.110", 0x92);
add("X.31", 0x93);
add("BIT-TRANSPARENT", 0x94);
add("DIRECT-ASYNCHRONOUS-DATA-SERVICE", 0x95);
add("PAP", 0x9A);
add("CHAP", 0x9B);
add("HTTP-BASIC", 0x9C);
add("HTTP-DIGEST", 0x9D);
add("WTLS-SS", 0x9E);
add("GSM-USSD", 0xA2);
add("GSM-SMS", 0xA3);
add("ANSI-136-GUTS", 0xA4);
add("IS-95-CDMA-SMS", 0xA5);
add("IS-95-CDMA-CSD", 0xA6);
add("IS-95-CDMA-PAC", 0xA7);
add("ANSI-136-CSD", 0xA8);
add("ANSI-136-GPRS", 0xA9);
add("GSM-CSD", 0xAA);
add("GSM-GPRS", 0xAB);
add("AMPS-CDPD", 0xAC);
add("PDC-CSD", 0xAD);
add("PDC-PACKET", 0xAE);
add("IDEN-SMS", 0xAF);
add("IDEN-CSD", 0xB0);
add("IDEN-PACKET", 0xB1);
add("FLEX/REFLEX", 0xB2);
add("PHS-SMS", 0xB3);
add("PHS-CSD", 0xB4);
add("TETRA-SDS", 0xB5);
add("TETRA-PACKET", 0xB6);
add("ANSI-136-GHOST", 0xB7);
add("MOBITEX-MPAK", 0xB8);
add("AUTOBOUDING", 0xC5);
add("CL-WSP", 0xCA);
add("CO-WSP", 0xCB);
add("CL-SEC-WSP", 0xCC);
add("CO-SEC-WSP", 0xCD);
add("CL-SEC-WTA", 0xCE);
add("CO-SEC-WTA", 0xCF);
// Code page 0
add("IPV4", 0, 0x85);
add("IPV6", 0, 0x86);
add("E164", 0, 0x87);
add("ALPHA", 0, 0x88);
add("APN", 0, 0x89);
add("SCODE", 0, 0x8A);
add("TETRA-ITSI", 0, 0x8B);
add("MAN", 0, 0x8C);
add("ANALOG-MODEM", 0, 0x90);
add("V.120", 0, 0x91);
add("V.110", 0, 0x92);
add("X.31", 0, 0x93);
add("BIT-TRANSPARENT", 0, 0x94);
add("DIRECT-ASYNCHRONOUS-DATA-SERVICE", 0, 0x95);
add("PAP", 0, 0x9A);
add("CHAP", 0, 0x9B);
add("HTTP-BASIC", 0, 0x9C);
add("HTTP-DIGEST", 0, 0x9D);
add("WTLS-SS", 0, 0x9E);
add("MD5", 0, 0x9F); // Added in OMA, 7.3.3
add("GSM-USSD", 0, 0xA2);
add("GSM-SMS", 0, 0xA3);
add("ANSI-136-GUTS", 0, 0xA4);
add("IS-95-CDMA-SMS", 0, 0xA5);
add("IS-95-CDMA-CSD", 0, 0xA6);
add("IS-95-CDMA-PAC", 0, 0xA7);
add("ANSI-136-CSD", 0, 0xA8);
add("ANSI-136-GPRS", 0, 0xA9);
add("GSM-CSD", 0, 0xAA);
add("GSM-GPRS", 0, 0xAB);
add("AMPS-CDPD", 0, 0xAC);
add("PDC-CSD", 0, 0xAD);
add("PDC-PACKET", 0, 0xAE);
add("IDEN-SMS", 0, 0xAF);
add("IDEN-CSD", 0, 0xB0);
add("IDEN-PACKET", 0, 0xB1);
add("FLEX/REFLEX", 0, 0xB2);
add("PHS-SMS", 0, 0xB3);
add("PHS-CSD", 0, 0xB4);
add("TETRA-SDS", 0, 0xB5);
add("TETRA-PACKET", 0, 0xB6);
add("ANSI-136-GHOST", 0, 0xB7);
add("MOBITEX-MPAK", 0, 0xB8);
add("CDMA2000-1X-SIMPLE-IP", 0, 0xB9); // Added in OMA, 7.3.4
add("CDMA2000-1X-MOBILE-IP", 0, 0xBA); // Added in OMA, 7.3.4
add("AUTOBOUDING", 0, 0xC5);
add("CL-WSP", 0, 0xCA);
add("CO-WSP", 0, 0xCB);
add("CL-SEC-WSP", 0, 0xCC);
add("CO-SEC-WSP", 0, 0xCD);
add("CL-SEC-WTA", 0, 0xCE);
add("CO-SEC-WTA", 0, 0xCF);
add("OTA-HTTP-TO", 0, 0xD0); // Added in OMA, 7.3.6
add("OTA-HTTP-TLS-TO", 0, 0xD1); // Added in OMA, 7.3.6
add("OTA-HTTP-PO", 0, 0xD2); // Added in OMA, 7.3.6
add("OTA-HTTP-TLS-PO", 0, 0xD3); // Added in OMA, 7.3.6
add("AAA", 0, 0xE0); // Added in OMA, 7.3.8
add("HA", 0, 0xE1); // Added in OMA, 7.3.8
// Code page 1
add("IPV6", 1, 0x86);
add("E164", 1, 0x87);
add("ALPHA", 1, 0x88);
add("APPSRV", 1, 0x8D);
add("OBEX", 1, 0x8E);
add(",", 1, 0x90);
add("HTTP-", 1, 0x91);
add("BASIC", 1, 0x92);
add("DIGEST", 1, 0x93);
return names;
})();

View File

@ -134,18 +134,21 @@ this.PduHelper = {
*/
const SI_TAG_FIELDS = (function () {
let names = {};
function add(name, number) {
function add(name, codepage, number) {
let entry = {
name: name,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("si", 0x05);
add("indication", 0x06);
add("info", 0x07);
add("item", 0x08);
add("si", 0, 0x05);
add("indication", 0, 0x06);
add("info", 0, 0x07);
add("item", 0, 0x08);
return names;
})();
@ -157,47 +160,53 @@ const SI_TAG_FIELDS = (function () {
*/
const SI_ATTRIBUTE_FIELDS = (function () {
let names = {};
function add(name, value, number) {
function add(name, value, codepage, number) {
let entry = {
name: name,
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("action", "signal-none", 0x05);
add("action", "signal-low", 0x06);
add("action", "signal-medium", 0x07);
add("action", "signal-high", 0x08);
add("action", "delete", 0x09);
add("created", "", 0x0A);
add("href", "", 0x0B);
add("href", "http://", 0x0C);
add("href", "http://www.", 0x0D);
add("href", "https://", 0x0E);
add("href", "https://www.", 0x0F);
add("si-expires", "", 0x10);
add("si-id", "", 0x11);
add("class", "", 0x12);
add("action", "signal-none", 0, 0x05);
add("action", "signal-low", 0, 0x06);
add("action", "signal-medium", 0, 0x07);
add("action", "signal-high", 0, 0x08);
add("action", "delete", 0, 0x09);
add("created", "", 0, 0x0A);
add("href", "", 0, 0x0B);
add("href", "http://", 0, 0x0C);
add("href", "http://www.", 0, 0x0D);
add("href", "https://", 0, 0x0E);
add("href", "https://www.", 0, 0x0F);
add("si-expires", "", 0, 0x10);
add("si-id", "", 0, 0x11);
add("class", "", 0, 0x12);
return names;
})();
const SI_VALUE_FIELDS = (function () {
let names = {};
function add(value, number) {
function add(value, codepage, number) {
let entry = {
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add(".com/", 0x85);
add(".edu/", 0x86);
add(".net/", 0x87);
add(".org/", 0x88);
add(".com/", 0, 0x85);
add(".edu/", 0, 0x86);
add(".net/", 0, 0x87);
add(".org/", 0, 0x88);
return names;
})();

View File

@ -90,15 +90,18 @@ this.PduHelper = {
*/
const SL_TAG_FIELDS = (function () {
let names = {};
function add(name, number) {
function add(name, codepage, number) {
let entry = {
name: name,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("sl", 0x05);
add("sl", 0, 0x05);
return names;
})();
@ -110,41 +113,47 @@ const SL_TAG_FIELDS = (function () {
*/
const SL_ATTRIBUTE_FIELDS = (function () {
let names = {};
function add(name, value, number) {
function add(name, value, codepage, number) {
let entry = {
name: name,
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add("action", "execute-low", 0x05);
add("action", "execute-high", 0x06);
add("action", "cache", 0x07);
add("href", "", 0x08);
add("href", "http://", 0x09);
add("href", "http://www.", 0x0A);
add("href", "https://", 0x0B);
add("href", "https://www.", 0x0C);
add("action", "execute-low", 0, 0x05);
add("action", "execute-high", 0, 0x06);
add("action", "cache", 0, 0x07);
add("href", "", 0, 0x08);
add("href", "http://", 0, 0x09);
add("href", "http://www.", 0, 0x0A);
add("href", "https://", 0, 0x0B);
add("href", "https://www.", 0, 0x0C);
return names;
})();
const SL_VALUE_FIELDS = (function () {
let names = {};
function add(value, number) {
function add(value, codepage, number) {
let entry = {
value: value,
number: number,
};
names[number] = entry;
if (!names[codepage]) {
names[codepage] = {};
}
names[codepage][number] = entry;
}
add(".com/", 0x85);
add(".edu/", 0x86);
add(".net/", 0x87);
add(".org/", 0x88);
add(".com/", 0, 0x85);
add(".edu/", 0, 0x86);
add(".net/", 0, 0x87);
add(".org/", 0, 0x88);
return names;
})();

View File

@ -62,8 +62,8 @@ this.WapPushManager = {
let appid = options.headers["x-wap-application-id"];
if (!appid) {
// Assume message without applicatioin ID is WAP Push
debug("Push message doesn't contains X-Wap-Application-Id.");
return;
}
// MMS

View File

@ -23,6 +23,7 @@ const TAG_TOKEN_VALUE_MASK = 0x3F;
*
* @see WAP-192-WBXML-20010725-A, clause 7.1
*/
const CODE_PAGE_SWITCH_TOKEN = 0x00;
const TAG_END_TOKEN = 0x01;
const INLINE_STRING_TOKEN = 0x03;
const STRING_TABLE_TOKEN = 0x83;
@ -34,11 +35,53 @@ this.DEBUG_ALL = false;
// Enable debug message for WBXML decoder core.
this.DEBUG = DEBUG_ALL | false;
/**
* Handle WBXML code page switch.
*
* @param data
* A wrapped object containing raw PDU data.
* @param decodeInfo
* Internal information for decode process.
*
* @see WAP-192-WBXML-20010725-A, clause 5.8.4.7.2 and 5.8.1
*/
this.WbxmlCodePageSwitch = {
decode: function decode_wbxml_code_page_switch(data, decodeInfo) {
let codePage = WSP.Octet.decode(data);
if (decodeInfo.currentState === "tag") {
decodeInfo.currentTokenList.tag = decodeInfo.tokenList.tag[codePage];
if (!decodeInfo.currentTokenList.tag) {
throw new Error("Invalid tag code page: " + codePage + ".");
}
return "";
}
if (decodeInfo.currentState === "attr") {
decodeInfo.currentTokenList.attr = decodeInfo.tokenList.attr[codePage];
decodeInfo.currentTokenList.value = decodeInfo.tokenList.value[codePage];
if (!decodeInfo.currentTokenList.attr ||
!decodeInfo.currentTokenList.value) {
throw new Error("Invalid attr code page: " + codePage + ".");
}
return "";
}
throw new Error("Invalid decoder state: " + decodeInfo.currentState + ".");
},
};
/**
* Parse end WBXML encoded message.
*
* @param data
* A wrapped object containing raw PDU data.
* @param decodeInfo
* Internal information for decode process.
*
* @see WAP-192-WBXML-20010725-A, clause 5.8.4.7.1
*
@ -84,6 +127,8 @@ this.WbxmlStringTable = {
*
* @param data
* A wrapped object containing raw PDU data.
* @param decodeInfo
* Internal information for decode process.
*
* @see WAP-192-WBXML-20010725-A, clause 5.8.4.1
*
@ -106,6 +151,8 @@ this.WbxmlInlineString = {
*
* @param data
* A wrapped object containing raw PDU data.
* @param decodeInfo
* Internal information for decode process.
*
* @see WAP-192-WBXML-20010725-A, clause 5.8.4.6
*
@ -135,11 +182,20 @@ this.PduHelper = {
parseWbxml: function parseWbxml_wbxml(data, decodeInfo, appToken) {
// Parse token definition to my structure.
let tagTokenList = appToken.tagTokenList;
let attrTokenList = appToken.attrTokenList;
let valueTokenList = appToken.valueTokenList;
decodeInfo.tagStack = []; // tag decode stack
decodeInfo.tokenList = {
tag: appToken.tagTokenList,
attr: appToken.attrTokenList,
value: appToken.valueTokenList
};
decodeInfo.tagStack = []; // tag decode stack
decodeInfo.currentTokenList = {
tag: decodeInfo.tokenList.tag[0],
attr: decodeInfo.tokenList.attr[0],
value: decodeInfo.tokenList.value[0]
};
decodeInfo.currentState = "tag"; // Current decoding state, "tag" or "attr"
// Used to read corresponding code page
// initial state : "tag"
// Merge global tag tokens into single list, so we don't have
// to search two lists every time.
@ -156,6 +212,9 @@ this.PduHelper = {
// Decode content, might be a new tag token, an end of tag token, or an
// inline string.
// Switch to tag domain
decodeInfo.currentState = "tag";
let tagToken = WSP.Octet.decode(data);
let tagTokenValue = tagToken & TAG_TOKEN_VALUE_MASK;
@ -170,7 +229,7 @@ this.PduHelper = {
}
// Check if application tag token is valid
tagInfo = tagTokenList[tagTokenValue];
tagInfo = decodeInfo.currentTokenList.tag[tagTokenValue];
if (!tagInfo) {
throw new Error("Unsupported WBXML token: " + tagTokenValue + ".");
}
@ -181,6 +240,9 @@ this.PduHelper = {
// Decode attributes, might be a new attribute token, a value token,
// or an inline string
// Switch to attr/value domain
decodeInfo.currentState = "attr";
let attrSeperator = "";
while (data.offset < data.array.length) {
let attrToken = WSP.Octet.decode(data);
@ -195,14 +257,14 @@ this.PduHelper = {
}
// Check if attribute token is valid
attrInfo = attrTokenList[attrToken];
attrInfo = decodeInfo.currentTokenList.attr[attrToken];
if (attrInfo) {
content += attrSeperator + " " + attrInfo.name + "=\"" + attrInfo.value;
attrSeperator = "\"";
continue;
}
attrInfo = valueTokenList[attrToken];
attrInfo = decodeInfo.currentTokenList.value[attrToken];
if (attrInfo) {
content += attrInfo.value;
continue;
@ -325,10 +387,11 @@ const WBXML_GLOBAL_TOKENS = (function () {
names[number] = entry;
}
add(TAG_END_TOKEN, WbxmlEnd);
add(INLINE_STRING_TOKEN, WbxmlInlineString);
add(STRING_TABLE_TOKEN, WbxmlStringTable);
add(OPAQUE_TOKEN, WbxmlOpaque);
add(CODE_PAGE_SWITCH_TOKEN, WbxmlCodePageSwitch);
add(TAG_END_TOKEN, WbxmlEnd);
add(INLINE_STRING_TOKEN, WbxmlInlineString);
add(STRING_TABLE_TOKEN, WbxmlStringTable);
add(OPAQUE_TOKEN, WbxmlOpaque);
return names;
})();

View File

@ -357,3 +357,143 @@ add_test(function test_cp_parse_wbxml() {
run_next_test();
});
/**
* CP compressed by WBXML with code page switch
*/
add_test(function test_cp_parse_wbxml_code_page() {
let wbxml_code_page_data_array = new Uint8Array([
0x03, 0x0B, 0x6A, 0x00, 0x45, 0xC6, 0x56, 0x01,
0x87, 0x07, 0x06, 0x03, 0x43, 0x48, 0x54, 0x5F,
0x65, 0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0x01,
0xC6, 0x00, 0x01, 0x55, 0x01, 0x87, 0x36, 0x00,
0x00, 0x06, 0x03, 0x77, 0x32, 0x00, 0x01, 0x87,
0x00, 0x01, 0x39, 0x00, 0x00, 0x06, 0x03, 0x57,
0x50, 0x52, 0x4F, 0x58, 0x59, 0x00, 0x01, 0x87,
0x07, 0x06, 0x03, 0x43, 0x48, 0x54, 0x5F, 0x65,
0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0xC6, 0x00,
0x01, 0x59, 0x01, 0x87, 0x3A, 0x00, 0x00, 0x06,
0x03, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
0x77, 0x61, 0x70, 0x2E, 0x65, 0x6D, 0x6F, 0x6D,
0x65, 0x2E, 0x6E, 0x65, 0x74, 0x2F, 0x00, 0x01,
0x87, 0x07, 0x06, 0x03, 0x43, 0x48, 0x54, 0x5F,
0x65, 0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0x87,
0x1C, 0x01, 0x01, 0x01, 0xC6, 0x00, 0x01, 0x55,
0x01, 0x87, 0x36, 0x00, 0x00, 0x06, 0x03, 0x77,
0x34, 0x00, 0x01, 0x87, 0x00, 0x01, 0x39, 0x00,
0x00, 0x06, 0x03, 0x4D, 0x50, 0x52, 0x4F, 0x58,
0x59, 0x00, 0x01, 0x87, 0x00, 0x01, 0x34, 0x00,
0x00, 0x06, 0x03, 0x68, 0x74, 0x74, 0x70, 0x3A,
0x2F, 0x2F, 0x6D, 0x6D, 0x73, 0x3A, 0x38, 0x30,
0x30, 0x32, 0x00, 0x01, 0x01, 0xC6, 0x51, 0x01,
0x87, 0x15, 0x06, 0x03, 0x57, 0x50, 0x52, 0x4F,
0x58, 0x59, 0x00, 0x01, 0x87, 0x07, 0x06, 0x03,
0x43, 0x48, 0x54, 0x5F, 0x65, 0x6D, 0x6F, 0x6D,
0x65, 0x00, 0x01, 0x87, 0x1C, 0x06, 0x03, 0x68,
0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x61,
0x70, 0x2E, 0x65, 0x6D, 0x6F, 0x6D, 0x65, 0x2E,
0x6E, 0x65, 0x74, 0x2F, 0x00, 0x01, 0xC6, 0x52,
0x01, 0x87, 0x2F, 0x06, 0x03, 0x50, 0x52, 0x4F,
0x58, 0x59, 0x31, 0x00, 0x01, 0x87, 0x20, 0x06,
0x03, 0x31, 0x30, 0x2E, 0x31, 0x2E, 0x31, 0x2E,
0x31, 0x00, 0x01, 0x87, 0x21, 0x06, 0x85, 0x01,
0x87, 0x22, 0x06, 0x03, 0x43, 0x48, 0x54, 0x5F,
0x65, 0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0xC6,
0x53, 0x01, 0x87, 0x23, 0x06, 0x03, 0x38, 0x30,
0x38, 0x30, 0x00, 0x01, 0x01, 0x01, 0x01, 0xC6,
0x51, 0x01, 0x87, 0x15, 0x06, 0x03, 0x4D, 0x50,
0x52, 0x4F, 0x58, 0x59, 0x00, 0x01, 0x87, 0x07,
0x06, 0x03, 0x43, 0x48, 0x54, 0x5F, 0x4D, 0x4D,
0x53, 0x00, 0x01, 0xC6, 0x52, 0x01, 0x87, 0x2F,
0x06, 0x03, 0x50, 0x52, 0x4F, 0x58, 0x59, 0x32,
0x00, 0x01, 0x87, 0x20, 0x06, 0x03, 0x31, 0x30,
0x2E, 0x31, 0x2E, 0x31, 0x2E, 0x31, 0x00, 0x01,
0x87, 0x21, 0x06, 0x85, 0x01, 0x87, 0x22, 0x06,
0x03, 0x43, 0x48, 0x54, 0x5F, 0x4D, 0x4D, 0x53,
0x00, 0x01, 0xC6, 0x53, 0x01, 0x87, 0x23, 0x06,
0x03, 0x38, 0x30, 0x38, 0x30, 0x00, 0x01, 0x01,
0x01, 0x01, 0xC6, 0x55, 0x01, 0x87, 0x11, 0x06,
0x03, 0x43, 0x48, 0x54, 0x5F, 0x65, 0x6D, 0x6F,
0x6D, 0x65, 0x00, 0x01, 0x87, 0x07, 0x06, 0x03,
0x43, 0x48, 0x54, 0x5F, 0x65, 0x6D, 0x6F, 0x6D,
0x65, 0x00, 0x01, 0x87, 0x10, 0x06, 0xAB, 0x01,
0x87, 0x08, 0x06, 0x03, 0x65, 0x6D, 0x6F, 0x6D,
0x65, 0x00, 0x01, 0x87, 0x09, 0x06, 0x89, 0x01,
0x01, 0xC6, 0x55, 0x01, 0x87, 0x11, 0x06, 0x03,
0x43, 0x48, 0x54, 0x5F, 0x4D, 0x4D, 0x53, 0x00,
0x01, 0x87, 0x07, 0x06, 0x03, 0x43, 0x48, 0x54,
0x5F, 0x4D, 0x4D, 0x53, 0x00, 0x01, 0x87, 0x10,
0x06, 0xAB, 0x01, 0x87, 0x08, 0x06, 0x03, 0x65,
0x6D, 0x6F, 0x6D, 0x65, 0x00, 0x01, 0x87, 0x09,
0x06, 0x89, 0x01, 0x01, 0x01
]);
let wbxml_content =
"<wap-provisioningdoc>" +
"<characteristic type=\"BOOTSTRAP\">" +
"<parm name=\"NAME\" value=\"CHT_emome\"/>" +
"</characteristic>" +
"<characteristic type=\"APPLICATION\">" +
"<parm name=\"APPID\" value=\"w2\"/>" +
"<parm name=\"TO-PROXY\" value=\"WPROXY\"/>" +
"<parm name=\"NAME\" value=\"CHT_emome\"/>" +
"<characteristic type=\"RESOURCE\">" +
"<parm name=\"URI\" value=\"http://wap.emome.net/\"/>" +
"<parm name=\"NAME\" value=\"CHT_emome\"/>" +
"<parm name=\"STARTPAGE\"/>" +
"</characteristic>" +
"</characteristic>" +
"<characteristic type=\"APPLICATION\">" +
"<parm name=\"APPID\" value=\"w4\"/>" +
"<parm name=\"TO-PROXY\" value=\"MPROXY\"/>" +
"<parm name=\"ADDR\" value=\"http://mms:8002\"/>" +
"</characteristic>" +
"<characteristic type=\"PXLOGICAL\">" +
"<parm name=\"PROXY-ID\" value=\"WPROXY\"/>" +
"<parm name=\"NAME\" value=\"CHT_emome\"/>" +
"<parm name=\"STARTPAGE\" value=\"http://wap.emome.net/\"/>" +
"<characteristic type=\"PXPHYSICAL\">" +
"<parm name=\"PHYSICAL-PROXY-ID\" value=\"PROXY1\"/>" +
"<parm name=\"PXADDR\" value=\"10.1.1.1\"/>" +
"<parm name=\"PXADDRTYPE\" value=\"IPV4\"/>" +
"<parm name=\"TO-NAPID\" value=\"CHT_emome\"/>" +
"<characteristic type=\"PORT\">" +
"<parm name=\"PORTNBR\" value=\"8080\"/>" +
"</characteristic>" +
"</characteristic>" +
"</characteristic>" +
"<characteristic type=\"PXLOGICAL\">" +
"<parm name=\"PROXY-ID\" value=\"MPROXY\"/>" +
"<parm name=\"NAME\" value=\"CHT_MMS\"/>" +
"<characteristic type=\"PXPHYSICAL\">" +
"<parm name=\"PHYSICAL-PROXY-ID\" value=\"PROXY2\"/>" +
"<parm name=\"PXADDR\" value=\"10.1.1.1\"/>" +
"<parm name=\"PXADDRTYPE\" value=\"IPV4\"/>" +
"<parm name=\"TO-NAPID\" value=\"CHT_MMS\"/>" +
"<characteristic type=\"PORT\">" +
"<parm name=\"PORTNBR\" value=\"8080\"/>" +
"</characteristic>" +
"</characteristic>" +
"</characteristic>" +
"<characteristic type=\"NAPDEF\">" +
"<parm name=\"NAPID\" value=\"CHT_emome\"/>" +
"<parm name=\"NAME\" value=\"CHT_emome\"/>" +
"<parm name=\"BEARER\" value=\"GSM-GPRS\"/>" +
"<parm name=\"NAP-ADDRESS\" value=\"emome\"/>" +
"<parm name=\"NAP-ADDRTYPE\" value=\"APN\"/>" +
"</characteristic>" +
"<characteristic type=\"NAPDEF\">" +
"<parm name=\"NAPID\" value=\"CHT_MMS\"/>" +
"<parm name=\"NAME\" value=\"CHT_MMS\"/>" +
"<parm name=\"BEARER\" value=\"GSM-GPRS\"/>" +
"<parm name=\"NAP-ADDRESS\" value=\"emome\"/>" +
"<parm name=\"NAP-ADDRTYPE\" value=\"APN\"/>" +
"</characteristic>" +
"</wap-provisioningdoc>";
test_parser(wbxml_code_page_data_array, "application/vnd.wap.connectivity-wbxml", {
contentType: "text/vnd.wap.connectivity-xml",
content: wbxml_content
});
run_next_test();
});

View File

@ -13,11 +13,17 @@ namespace layers {
/* static */ LayersBackend Compositor::sBackend = LAYERS_NONE;
/* static */ LayersBackend
Compositor::GetBackend()
{
AssertOnCompositorThread();
return sBackend;
}
/* static */ void
Compositor::AssertOnCompositorThread()
{
MOZ_ASSERT(CompositorParent::CompositorLoop() ==
MessageLoop::current(),
"Can only call this from the compositor thread!");
return sBackend;
}
void

View File

@ -398,6 +398,12 @@ public:
virtual nsIWidget* GetWidget() const { return nullptr; }
virtual const nsIntSize& GetWidgetSize() = 0;
/**
* Debug-build assertion that can be called to ensure code is running on the
* compositor thread.
*/
static void AssertOnCompositorThread();
/**
* We enforce that there can only be one Compositor backend type off the main
* thread at the same time. The backend type in use can be checked with this

View File

@ -0,0 +1,386 @@
/* -*- Mode: C++; tab-width: 8; 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 "APZCTreeManager.h"
#include "AsyncCompositionManager.h" // for ViewTransform
#include "LayerManagerComposite.h" // for AsyncCompositionManager.h
#include "Compositor.h"
#define APZC_LOG(...)
// #define APZC_LOG(args...) printf_stderr(args)
namespace mozilla {
namespace layers {
APZCTreeManager::APZCTreeManager()
: mTreeLock("APZCTreeLock")
{
MOZ_ASSERT(NS_IsMainThread());
AsyncPanZoomController::InitializeGlobalState();
}
void
APZCTreeManager::AssertOnCompositorThread()
{
Compositor::AssertOnCompositorThread();
}
/* Flatten the tree of APZC instances into the given nsTArray */
static void
Collect(AsyncPanZoomController* aApzc, nsTArray< nsRefPtr<AsyncPanZoomController> >* aCollection)
{
if (aApzc) {
aCollection->AppendElement(aApzc);
Collect(aApzc->GetLastChild(), aCollection);
Collect(aApzc->GetPrevSibling(), aCollection);
}
}
void
APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId)
{
AssertOnCompositorThread();
MonitorAutoLock lock(mTreeLock);
// We do this business with collecting the entire tree into an array because otherwise
// it's very hard to determine which APZC instances need to be destroyed. In the worst
// case, there are two scenarios: (a) a layer with an APZC is removed from the layer
// tree and (b) a layer with an APZC is moved in the layer tree from one place to a
// completely different place. In scenario (a) we would want to destroy the APZC while
// walking the layer tree and noticing that the layer/APZC is no longer there. But if
// we do that then we run into a problem in scenario (b) because we might encounter that
// layer later during the walk. To handle both of these we have to 'remember' that the
// layer was not found, and then do the destroy only at the end of the tree walk after
// we are sure that the layer was removed and not just transplanted elsewhere. Doing that
// as part of a recursive tree walk is hard and so maintaining a list and removing
// APZCs that are still alive is much simpler.
nsTArray< nsRefPtr<AsyncPanZoomController> > apzcsToDestroy;
Collect(mRootApzc, &apzcsToDestroy);
mRootApzc = nullptr;
if (aRoot) {
UpdatePanZoomControllerTree(aCompositor,
aRoot,
// aCompositor is null in gtest scenarios
aCompositor ? aCompositor->RootLayerTreeId() : 0,
nullptr, nullptr,
aIsFirstPaint, aFirstPaintLayersId,
&apzcsToDestroy);
}
for (int i = apzcsToDestroy.Length() - 1; i >= 0; i--) {
APZC_LOG("Destroying APZC at %p\n", apzcsToDestroy[i].get());
apzcsToDestroy[i]->Destroy();
}
}
AsyncPanZoomController*
APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
Layer* aLayer, uint64_t aLayersId,
AsyncPanZoomController* aParent,
AsyncPanZoomController* aNextSibling,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy)
{
ContainerLayer* container = aLayer->AsContainerLayer();
AsyncPanZoomController* controller = nullptr;
if (container) {
if (container->GetFrameMetrics().IsScrollable()) {
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
if (state && state->mController.get()) {
// If we get here, aLayer is a scrollable container layer and somebody
// has registered a GeckoContentController for it, so we need to ensure
// it has an APZC instance to manage its scrolling.
controller = container->GetAsyncPanZoomController();
if (!controller) {
controller = new AsyncPanZoomController(aLayersId, state->mController,
AsyncPanZoomController::USE_GESTURE_DETECTOR);
controller->SetCompositorParent(aCompositor);
} else {
// If there was already an APZC for the layer clear the tree pointers
// so that it doesn't continue pointing to APZCs that should no longer
// be in the tree. These pointers will get reset properly as we continue
// building the tree. Also remove it from the set of APZCs that are going
// to be destroyed, because it's going to remain active.
aApzcsToDestroy->RemoveElement(controller);
controller->SetPrevSibling(nullptr);
controller->SetLastChild(nullptr);
}
APZC_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", controller, aLayer, aLayersId, container->GetFrameMetrics().mScrollId);
controller->NotifyLayersUpdated(container->GetFrameMetrics(),
aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
gfx3DMatrix transform = container->GetEffectiveTransform();
LayerRect visible = container->GetFrameMetrics().mViewport * container->GetFrameMetrics().LayersPixelsPerCSSPixel();
gfxRect transformed = transform.TransformBounds(gfxRect(visible.x, visible.y, visible.width, visible.height));
controller->SetVisibleRegion(transformed);
APZC_LOG("Setting rect(%f %f %f %f) as visible region for %p\n", transformed.x, transformed.y,
transformed.width, transformed.height,
controller);
// Bind the APZC instance into the tree of APZCs
if (aNextSibling) {
aNextSibling->SetPrevSibling(controller);
} else if (aParent) {
aParent->SetLastChild(controller);
} else {
mRootApzc = controller;
}
// Let this controller be the parent of other controllers when we recurse downwards
aParent = controller;
}
}
container->SetAsyncPanZoomController(controller);
}
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
AsyncPanZoomController* next = nullptr;
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
next = UpdatePanZoomControllerTree(aCompositor, child, childLayersId, aParent, next,
aIsFirstPaint, aFirstPaintLayersId, aApzcsToDestroy);
}
// Return the APZC that should be the sibling of other APZCs as we continue
// moving towards the first child at this depth in the layer tree.
// If this layer doesn't have a controller, we promote any APZCs in the subtree
// upwards. Otherwise we fall back to the aNextSibling that was passed in.
if (controller) {
return controller;
}
if (next) {
return next;
}
return aNextSibling;
}
nsEventStatus
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
{
nsRefPtr<AsyncPanZoomController> apzc;
switch (aEvent.mInputType) {
case MULTITOUCH_INPUT: {
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
apzc = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
break;
} case PINCHGESTURE_INPUT: {
const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
apzc = GetTargetAPZC(pinchInput.mFocusPoint);
break;
} case TAPGESTURE_INPUT: {
const TapGestureInput& tapInput = aEvent.AsTapGestureInput();
apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint));
break;
} default: {
// leave apzc as nullptr
break;
}
}
if (apzc) {
return apzc->ReceiveInputEvent(aEvent);
}
return nsEventStatus_eIgnore;
}
nsEventStatus
APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent,
nsInputEvent* aOutEvent)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<AsyncPanZoomController> apzc;
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)));
}
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)));
break;
} default: {
// leave apzc as nullptr
break;
}
}
if (apzc) {
return apzc->ReceiveInputEvent(aEvent, aOutEvent);
}
return nsEventStatus_eIgnore;
}
void
APZCTreeManager::UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
const ScreenIntRect& aCompositionBounds)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->UpdateCompositionBounds(aCompositionBounds);
}
}
void
APZCTreeManager::CancelDefaultPanZoom(const ScrollableLayerGuid& aGuid)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->CancelDefaultPanZoom();
}
}
void
APZCTreeManager::DetectScrollableSubframe(const ScrollableLayerGuid& aGuid)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->DetectScrollableSubframe();
}
}
void
APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
const CSSRect& aRect)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->ZoomToRect(aRect);
}
}
void
APZCTreeManager::ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
bool aPreventDefault)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->ContentReceivedTouch(aPreventDefault);
}
}
void
APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
bool aAllowZoom,
float aMinScale,
float aMaxScale)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->UpdateZoomConstraints(aAllowZoom, aMinScale, aMaxScale);
}
}
void
APZCTreeManager::UpdateScrollOffset(const ScrollableLayerGuid& aGuid,
const CSSPoint& aScrollOffset)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->UpdateScrollOffset(aScrollOffset);
}
}
void
APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (apzc) {
apzc->CancelAnimation();
}
}
void
APZCTreeManager::ClearTree()
{
MonitorAutoLock lock(mTreeLock);
// This can be done as part of a tree walk but it's easier to
// just re-use the Collect method that we need in other places.
// If this is too slow feel free to change it to a recursive walk.
nsTArray< nsRefPtr<AsyncPanZoomController> > apzcsToDestroy;
Collect(mRootApzc, &apzcsToDestroy);
for (int i = apzcsToDestroy.Length() - 1; i >= 0; i--) {
apzcsToDestroy[i]->Destroy();
}
mRootApzc = nullptr;
}
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
{
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> target;
// The root may have siblings, check those too
for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
target = FindTargetAPZC(apzc, aGuid);
if (target) {
break;
}
}
return target.forget();
}
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
{
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);
if (target) {
break;
}
}
return target.forget();
}
AsyncPanZoomController*
APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) {
// 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 = FindTargetAPZC(child, aGuid);
if (match) {
return match;
}
}
if (aApzc->Matches(aGuid)) {
return aApzc;
}
return nullptr;
}
AsyncPanZoomController*
APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint)
{
// This walks the tree in depth-first, reverse order, so that it encounters
// APZCs front-to-back on the screen.
ViewTransform apzcTransform = aApzc->GetCurrentAsyncTransform();
gfxPoint untransformed = gfx3DMatrix(apzcTransform).Inverse().ProjectPoint(aHitTestPoint);
for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
AsyncPanZoomController* match = GetAPZCAtPoint(child, untransformed);
if (match) {
return match;
}
}
if (aApzc->VisibleRegionContains(untransformed)) {
return aApzc;
}
return nullptr;
}
}
}

View File

@ -0,0 +1,275 @@
/* -*- Mode: C++; tab-width: 8; 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_layers_APZCTreeManager_h
#define mozilla_layers_APZCTreeManager_h
#include "mozilla/layers/AsyncPanZoomController.h"
#include "Layers.h"
#include "CompositorParent.h"
namespace mozilla {
namespace layers {
class AsyncPanZoomController;
class CompositorParent;
/**
* This class allows us to uniquely identify a scrollable layer. The
* mLayersId identifies the layer tree (corresponding to a child process
* and/or tab) that the scrollable layer belongs to. The mPresShellId
* is a temporal identifier (corresponding to the document loaded that
* contains the scrollable layer, which may change over time). The
* mScrollId corresponds to the actual frame that is scrollable.
*/
struct ScrollableLayerGuid {
uint64_t mLayersId;
uint32_t mPresShellId;
FrameMetrics::ViewID mScrollId;
ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
FrameMetrics::ViewID aScrollId)
: mLayersId(aLayersId)
, mPresShellId(aPresShellId)
, mScrollId(aScrollId)
{
MOZ_COUNT_CTOR(ScrollableLayerGuid);
}
ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics)
: mLayersId(aLayersId)
, mPresShellId(aMetrics.mPresShellId)
, mScrollId(aMetrics.mScrollId)
{
MOZ_COUNT_CTOR(ScrollableLayerGuid);
}
ScrollableLayerGuid(uint64_t aLayersId)
: mLayersId(aLayersId)
, mPresShellId(0)
, mScrollId(FrameMetrics::ROOT_SCROLL_ID)
{
MOZ_COUNT_CTOR(ScrollableLayerGuid);
// TODO: get rid of this constructor once all callers know their
// presShellId and scrollId
}
~ScrollableLayerGuid()
{
MOZ_COUNT_DTOR(ScrollableLayerGuid);
}
bool operator==(const ScrollableLayerGuid& other) const
{
return mLayersId == other.mLayersId
&& mPresShellId == other.mPresShellId
&& mScrollId == other.mScrollId;
}
bool operator!=(const ScrollableLayerGuid& other) const
{
return !(*this == other);
}
};
/**
* This class manages the tree of AsyncPanZoomController instances. There is one
* instance of this class owned by each CompositorParent, and it contains as
* many AsyncPanZoomController instances as there are scrollable container layers.
* This class generally lives on the compositor thread, although some functions
* may be called from other threads as noted; thread safety is ensured internally.
*
* The bulk of the work of this class happens as part of the UpdatePanZoomControllerTree
* function, which is when a layer tree update is received by the compositor.
* This function walks through the layer tree and creates a tree of APZC instances
* to match the scrollable container layers. APZC instances may be preserved across
* calls to this function if the corresponding layers are still present in the layer
* tree.
*
* The other functions on this class are used by various pieces of client code to
* notify the APZC instances of events relevant to them. This includes, for example,
* user input events that drive panning and zooming, changes to the scroll viewport
* area, and changes to pan/zoom constraints.
*
* Note that the ClearTree function MUST be called when this class is no longer needed;
* see the method documentation for details.
*/
class APZCTreeManager {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager)
public:
APZCTreeManager();
virtual ~APZCTreeManager() {}
/**
* Rebuild the APZC tree based on the layer update that just came up. Preserve
* APZC instances where possible, but retire those whose layers are no longer
* in the layer tree.
*
* This must be called on the compositor thread as it walks the layer tree.
*
* @param aCompositor A pointer to the compositor parent instance that owns
* this APZCTreeManager
* @param aRoot The root of the (full) layer tree
* @param aFirstPaintLayersId The layers id of the subtree to which aIsFirstPaint
* applies.
* @param aIsFirstPaint True if the layers update that this is called in response
* to included a first-paint. If this is true, the part of
* the tree that is affected by the first-paint flag is
* indicated by the aFirstPaintLayersId parameter.
*/
void UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot,
bool aIsFirstPaint, uint64_t aFirstPaintLayersId);
/**
* General handler for incoming input events. Manipulates the frame metrics
* based on what type of input it is. For example, a PinchGestureEvent will
* cause scaling. This should only be called externally to this class.
* HandleInputEvent() should be used internally.
*/
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
* general, this will just be:
* { x = 0, y = 0, width = surface.width, height = surface.height }, however
* there is no hard requirement for this.
*/
void UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
const ScreenIntRect& aCompositionBounds);
/**
* We are scrolling a subframe, so disable our machinery until we hit
* a touch end or a new touch start. This prevents us from accidentally
* panning both the subframe and the parent frame.
*
* XXX/bug 775452: We should eventually be supporting async scrollable
* subframes.
*/
void CancelDefaultPanZoom(const ScrollableLayerGuid& aGuid);
/**
* We have found a scrollable subframe, so we need to delay the scrolling
* gesture executed and let subframe do the scrolling first.
*/
void DetectScrollableSubframe(const ScrollableLayerGuid& aGuid);
/**
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
* in. The actual animation is done on the compositor thread after being set
* up. |aRect| must be given in CSS pixels, relative to the document.
*/
void ZoomToRect(const ScrollableLayerGuid& aGuid,
const CSSRect& aRect);
/**
* If we have touch listeners, this should always be called when we know
* definitively whether or not content has preventDefaulted any touch events
* that have come in. If |aPreventDefault| is true, any touch events in the
* queue will be discarded.
*/
void ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
bool aPreventDefault);
/**
* Updates any zoom constraints contained in the <meta name="viewport"> tag.
* We try to obey everything it asks us elsewhere, but here we only handle
* minimum-scale, maximum-scale, and user-scalable.
*/
void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
bool aAllowZoom,
float aMinScale,
float aMaxScale);
/**
* Update mFrameMetrics.mScrollOffset to the given offset.
* This is necessary in cases where a scroll is not caused by user
* input (for example, a content scrollTo()).
*/
void UpdateScrollOffset(const ScrollableLayerGuid& aGuid,
const CSSPoint& aScrollOffset);
/**
* Cancels any currently running animation. Note that all this does is set the
* state of the AsyncPanZoomController back to NOTHING, but it is the
* animation's responsibility to check this before advancing.
*/
void CancelAnimation(const ScrollableLayerGuid &aGuid);
/**
* Calls Destroy() on all APZC instances attached to the tree, and resets the
* tree back to empty. This function may be called multiple times during the
* lifetime of this APZCTreeManager, but it must always be called at least once
* when this APZCTreeManager is no longer needed. Failing to call this function
* may prevent objects from being freed properly.
*/
void ClearTree();
protected:
/**
* Debug-build assertion that can be called to ensure code is running on the
* compositor thread.
*/
virtual void AssertOnCompositorThread();
public:
/* Some helper functions to find an APZC given some identifying input. These functions
lock the tree of APZCs while they find the right one, and then return an addref'd
pointer to it. This allows caller code to just use the target APZC without worrying
about it going away. These are public for testing code and generally should not be
used by other production code.
*/
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
private:
/* Recursive helpers */
AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, gfxPoint aHitTestPoint);
/**
* Recursive helper function to build the APZC tree. The tree of APZC instances has
* the same shape as the layer tree, but excludes all the layers that are not scrollable.
* Note that this means APZCs corresponding to layers at different depths in the tree
* may end up becoming siblings. It also means that the "root" APZC may have siblings.
* This function walks the layer tree backwards through siblings and constructs the APZC
* tree also as a last-child-prev-sibling tree because that simplifies the hit detection
* code.
*/
AsyncPanZoomController* UpdatePanZoomControllerTree(CompositorParent* aCompositor,
Layer* aLayer, uint64_t aLayersId,
AsyncPanZoomController* aParent,
AsyncPanZoomController* aNextSibling,
bool aIsFirstPaint,
uint64_t aFirstPaintLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy);
private:
/* Whenever walking or mutating the tree rooted at mRootApzc, mTreeLock must be held.
* This lock does not need to be held while manipulating a single APZC instance in
* isolation (that is, if its tree pointers are not being accessed or mutated). The
* lock also needs to be held when accessing the mRootApzc instance variable, as that
* is considered part of the APZC tree management state. */
mozilla::Monitor mTreeLock;
nsRefPtr<AsyncPanZoomController> mRootApzc;
};
}
}
#endif // mozilla_layers_PanZoomController_h

View File

@ -51,7 +51,6 @@ WalkTheTree(Layer* aLayer,
if (RefLayer* ref = aLayer->AsRefLayer()) {
if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(ref->GetReferentId())) {
if (Layer* referent = state->mRoot) {
ContainerLayer *referentAsContainer = referent->AsContainerLayer();
if (!ref->GetVisibleRegion().IsEmpty()) {
ScreenOrientation chromeOrientation = aTargetConfig.orientation();
ScreenOrientation contentOrientation = state->mTargetConfig.orientation();
@ -63,16 +62,8 @@ WalkTheTree(Layer* aLayer,
if (OP == Resolve) {
ref->ConnectReferentLayer(referent);
if (referentAsContainer) {
if (AsyncPanZoomController* apzc = state->mController) {
referentAsContainer->SetAsyncPanZoomController(apzc);
}
}
} else {
ref->DetachReferentLayer(referent);
if (referentAsContainer) {
referentAsContainer->SetAsyncPanZoomController(nullptr);
}
}
}
}
@ -437,7 +428,6 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
ScreenPoint scrollOffset;
*aWantNextFrame |=
controller->SampleContentTransformForFrame(aCurrentFrame,
container,
&treeTransform,
scrollOffset);

View File

@ -106,6 +106,18 @@ static float gYSkateSizeMultiplier = 3.5f;
static float gXStationarySizeMultiplier = 1.5f;
static float gYStationarySizeMultiplier = 2.5f;
/**
* The time period in ms that throttles mozbrowserasyncscroll event.
* Default is 100ms if there is no "apzc.asyncscroll.throttle" in preference.
*/
static int gAsyncScrollThrottleTime = 100;
/**
* The timeout in ms for mAsyncScrollTimeoutTask delay task.
* Default is 300ms if there is no "apzc.asyncscroll.timeout" in preference.
*/
static int gAsyncScrollTimeout = 300;
static TimeStamp sFrameTime;
static TimeStamp
@ -121,8 +133,16 @@ AsyncPanZoomController::SetFrameTime(const TimeStamp& aTime) {
sFrameTime = aTime;
}
static void ReadAZPCPrefs()
/*static*/ void
AsyncPanZoomController::InitializeGlobalState()
{
MOZ_ASSERT(NS_IsMainThread());
static bool sInitialized = false;
if (sInitialized)
return;
sInitialized = true;
Preferences::AddIntVarCache(&gPanRepaintInterval, "gfx.azpc.pan_repaint_interval", gPanRepaintInterval);
Preferences::AddIntVarCache(&gFlingRepaintInterval, "gfx.azpc.fling_repaint_interval", gFlingRepaintInterval);
Preferences::AddFloatVarCache(&gMinSkateSpeed, "gfx.azpc.min_skate_speed", gMinSkateSpeed);
@ -133,36 +153,22 @@ static void ReadAZPCPrefs()
Preferences::AddFloatVarCache(&gYSkateSizeMultiplier, "gfx.azpc.y_skate_size_multiplier", gYSkateSizeMultiplier);
Preferences::AddFloatVarCache(&gXStationarySizeMultiplier, "gfx.azpc.x_stationary_size_multiplier", gXStationarySizeMultiplier);
Preferences::AddFloatVarCache(&gYStationarySizeMultiplier, "gfx.azpc.y_stationary_size_multiplier", gYStationarySizeMultiplier);
Preferences::AddIntVarCache(&gAsyncScrollThrottleTime, "apzc.asyncscroll.throttle", gAsyncScrollThrottleTime);
Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apzc.asyncscroll.timeout", gAsyncScrollTimeout);
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
ClearOnShutdown(&gComputedTimingFunction);
}
class ReadAZPCPref MOZ_FINAL : public nsRunnable {
public:
NS_IMETHOD Run()
{
ReadAZPCPrefs();
return NS_OK;
}
};
static void InitAZPCPrefs()
{
static bool sInitialized = false;
if (sInitialized)
return;
sInitialized = true;
if (NS_IsMainThread()) {
ReadAZPCPrefs();
} else {
// We have to dispatch an event to the main thread to read the pref.
NS_DispatchToMainThread(new ReadAZPCPref());
}
}
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
GeckoContentController* aGeckoContentController,
GestureBehavior aGestures)
: mPaintThrottler(GetFrameTime()),
: mLayersId(aLayersId),
mPaintThrottler(GetFrameTime()),
mGeckoContentController(aGeckoContentController),
mRefPtrMonitor("RefPtrMonitor"),
mTouchListenerTimeoutTask(nullptr),
mX(this),
mY(this),
@ -176,45 +182,48 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon
mLastAsyncScrollOffset(0, 0),
mCurrentAsyncScrollOffset(0, 0),
mAsyncScrollTimeoutTask(nullptr),
mAsyncScrollThrottleTime(100),
mAsyncScrollTimeout(300),
mDPI(72),
mDisableNextTouchBatch(false),
mHandlingTouchQueue(false),
mDelayPanning(false)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(AsyncPanZoomController);
InitAZPCPrefs();
if (aGestures == USE_GESTURE_DETECTOR) {
mGestureEventListener = new GestureEventListener(this);
}
SetDPI(mDPI);
if (!gComputedTimingFunction) {
gComputedTimingFunction = new ComputedTimingFunction();
gComputedTimingFunction->Init(
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
ClearOnShutdown(&gComputedTimingFunction);
}
Preferences::GetUint("apzc.asyncscroll.throttle", &mAsyncScrollThrottleTime);
Preferences::GetUint("apzc.asyncscroll.timeout", &mAsyncScrollTimeout);
}
AsyncPanZoomController::~AsyncPanZoomController() {
MOZ_COUNT_DTOR(AsyncPanZoomController);
}
already_AddRefed<GeckoContentController>
AsyncPanZoomController::GetGeckoContentController() {
MonitorAutoLock lock(mRefPtrMonitor);
nsRefPtr<GeckoContentController> controller = mGeckoContentController;
return controller.forget();
}
already_AddRefed<GestureEventListener>
AsyncPanZoomController::GetGestureEventListener() {
MonitorAutoLock lock(mRefPtrMonitor);
nsRefPtr<GestureEventListener> listener = mGestureEventListener;
return listener.forget();
}
void
AsyncPanZoomController::Destroy()
{
// These memebrs can only be used on the controller/UI thread.
mGeckoContentController = nullptr;
mGestureEventListener = nullptr;
{ // scope the lock
MonitorAutoLock lock(mRefPtrMonitor);
mGeckoContentController = nullptr;
mGestureEventListener = nullptr;
}
mPrevSibling = nullptr;
mLastChild = nullptr;
}
/* static */float
@ -332,8 +341,9 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent) {
nsEventStatus rv = nsEventStatus_eIgnore;
if (mGestureEventListener && !mDisableNextTouchBatch) {
rv = mGestureEventListener->HandleInputEvent(aEvent);
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
if (listener && !mDisableNextTouchBatch) {
rv = listener->HandleInputEvent(aEvent);
if (rv == nsEventStatus_eConsumeNoDefault)
return rv;
}
@ -659,12 +669,13 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
}
nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
if (mGeckoContentController) {
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
MonitorAutoLock monitor(mMonitor);
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
mGeckoContentController->HandleLongTap(gfx::RoundedToInt(point));
controller->HandleLongTap(gfx::RoundedToInt(point));
return nsEventStatus_eConsumeNoDefault;
}
return nsEventStatus_eIgnore;
@ -675,25 +686,27 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
}
nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
if (mGeckoContentController) {
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
MonitorAutoLock monitor(mMonitor);
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
mGeckoContentController->HandleSingleTap(gfx::RoundedToInt(point));
controller->HandleSingleTap(gfx::RoundedToInt(point));
return nsEventStatus_eConsumeNoDefault;
}
return nsEventStatus_eIgnore;
}
nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
if (mGeckoContentController) {
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
MonitorAutoLock monitor(mMonitor);
if (mAllowZoom) {
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(aEvent.mPoint, resolution);
mGeckoContentController->HandleDoubleTap(gfx::RoundedToInt(point));
controller->HandleDoubleTap(gfx::RoundedToInt(point));
}
return nsEventStatus_eConsumeNoDefault;
@ -1019,12 +1032,15 @@ void AsyncPanZoomController::RequestContentRepaint() {
// This message is compressed, so fire whether or not we already have a paint
// queued up. We need to know whether or not a paint was requested anyways,
// for the purposes of content calling window.scrollTo().
mPaintThrottler.PostTask(
FROM_HERE,
NewRunnableMethod(mGeckoContentController.get(),
&GeckoContentController::RequestContentRepaint,
mFrameMetrics),
GetFrameTime());
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
mPaintThrottler.PostTask(
FROM_HERE,
NewRunnableMethod(controller.get(),
&GeckoContentController::RequestContentRepaint,
mFrameMetrics),
GetFrameTime());
}
mFrameMetrics.mPresShellId = mLastContentPaintMetrics.mPresShellId;
mLastPaintRequestMetrics = mFrameMetrics;
@ -1043,7 +1059,6 @@ AsyncPanZoomController::FireAsyncScrollOnTimeout()
}
bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
ContainerLayer* aLayer,
ViewTransform* aNewTransform,
ScreenPoint& aScrollOffset) {
// The eventual return value of this function. The compositor needs to know
@ -1053,10 +1068,6 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
// responsibility to schedule a composite.
bool requestAnimationFrame = false;
LayerPoint metricsScrollOffset;
CSSPoint scrollOffset;
CSSToScreenScale localScale;
const FrameMetrics& frame = aLayer->GetFrameMetrics();
{
MonitorAutoLock mon(mMonitor);
@ -1103,17 +1114,9 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
break;
}
// Current local transform; this is not what's painted but rather
// what PZC has transformed due to touches like panning or
// pinching. Eventually, the root layer transform will become this
// during runtime, but we must wait for Gecko to repaint.
localScale = mFrameMetrics.CalculateResolution();
aScrollOffset = mFrameMetrics.mScrollOffset * mFrameMetrics.CalculateResolution();
*aNewTransform = GetCurrentAsyncTransformInternal();
if (frame.IsScrollable()) {
metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
}
scrollOffset = mFrameMetrics.mScrollOffset;
mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset;
}
@ -1129,7 +1132,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
// with the last event.
// Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
if (delta.ToMilliseconds() > mAsyncScrollThrottleTime &&
if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
MonitorAutoLock monitor(mMonitor);
mLastAsyncScrollTime = aSampleTime;
@ -1141,25 +1144,35 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
mAsyncScrollTimeoutTask,
mAsyncScrollTimeout);
gAsyncScrollTimeout);
}
CSSToLayerScale paintedScale = frame.mDevPixelsPerCSSPixel * frame.mResolution;
LayerPoint translation = (scrollOffset * paintedScale) - metricsScrollOffset;
*aNewTransform = ViewTransform(-translation, localScale / frame.mDevPixelsPerCSSPixel);
aScrollOffset = scrollOffset * localScale;
mLastSampleTime = aSampleTime;
return requestAnimationFrame;
}
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
MonitorAutoLock mon(mMonitor);
return GetCurrentAsyncTransformInternal();
}
ViewTransform AsyncPanZoomController::GetCurrentAsyncTransformInternal() {
LayerPoint metricsScrollOffset;
if (mLastContentPaintMetrics.IsScrollable()) {
metricsScrollOffset = mLastContentPaintMetrics.GetScrollOffsetInLayerPixels();
}
CSSToScreenScale localScale = mFrameMetrics.CalculateResolution();
LayerPoint translation = mFrameMetrics.GetScrollOffsetInLayerPixels() - metricsScrollOffset;
return ViewTransform(-translation, localScale / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
}
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
MonitorAutoLock monitor(mMonitor);
mLastContentPaintMetrics = aViewportFrame;
mLastContentPaintMetrics = aLayerMetrics;
mFrameMetrics.mMayHaveTouchListeners = aViewportFrame.mMayHaveTouchListeners;
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
// TODO: Once a mechanism for calling UpdateScrollOffset() when content does
// a scrollTo() is implemented for B2G (bug 895905), this block can be removed.
@ -1176,7 +1189,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
case FLING:
case TOUCHING:
case WAITING_LISTENERS:
mFrameMetrics.mScrollOffset = aViewportFrame.mScrollOffset;
mFrameMetrics.mScrollOffset = aLayerMetrics.mScrollOffset;
break;
// Don't clobber if we're in other states.
default:
@ -1187,12 +1200,12 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
mPaintThrottler.TaskComplete(GetFrameTime());
bool needContentRepaint = false;
if (aViewportFrame.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
aViewportFrame.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
if (aLayerMetrics.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
aLayerMetrics.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
// Remote content has sync'd up to the composition geometry
// change, so we can accept the viewport it's calculated.
CSSToScreenScale previousResolution = mFrameMetrics.CalculateResolution();
mFrameMetrics.mViewport = aViewportFrame.mViewport;
mFrameMetrics.mViewport = aLayerMetrics.mViewport;
CSSToScreenScale newResolution = mFrameMetrics.CalculateResolution();
needContentRepaint |= (previousResolution != newResolution);
}
@ -1204,11 +1217,15 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
mX.CancelTouch();
mY.CancelTouch();
mFrameMetrics = aViewportFrame;
// XXX If this is the very first time we're getting a layers update we need to
// trigger another repaint, or the B2G browser shows stale content. This needs
// to be investigated and fixed.
needContentRepaint |= (mFrameMetrics.IsDefault() && !aLayerMetrics.IsDefault());
mFrameMetrics = aLayerMetrics;
mState = NOTHING;
} else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aViewportFrame.mScrollableRect)) {
mFrameMetrics.mScrollableRect = aViewportFrame.mScrollableRect;
} else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aLayerMetrics.mScrollableRect)) {
mFrameMetrics.mScrollableRect = aLayerMetrics.mScrollableRect;
}
if (needContentRepaint) {
@ -1242,8 +1259,9 @@ void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompo
void AsyncPanZoomController::CancelDefaultPanZoom() {
mDisableNextTouchBatch = true;
if (mGestureEventListener) {
mGestureEventListener->CancelGesture();
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
if (listener) {
listener->CancelGesture();
}
}
@ -1424,83 +1442,44 @@ void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
}
void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
if (!mGeckoContentController) {
return;
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
controller->PostDelayedTask(aTask, aDelayMs);
}
mGeckoContentController->PostDelayedTask(aTask, aDelayMs);
}
void AsyncPanZoomController::SendAsyncScrollEvent() {
if (!mGeckoContentController) {
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (!controller) {
return;
}
FrameMetrics::ViewID scrollId;
CSSRect contentRect;
CSSSize scrollableSize;
{
// XXX bug 890932 - there should be a lock here. but it causes a deadlock.
scrollId = mFrameMetrics.mScrollId;
scrollableSize = mFrameMetrics.mScrollableRect.Size();
contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
contentRect.MoveTo(mCurrentAsyncScrollOffset);
}
mGeckoContentController->SendAsyncScrollDOMEvent(contentRect, scrollableSize);
controller->SendAsyncScrollDOMEvent(scrollId, contentRect, scrollableSize);
}
static void GetAPZCAtPointOnSubtree(const ContainerLayer& aLayerIn,
const gfxPoint& aPoint,
AsyncPanZoomController** aApzcOut,
LayerIntPoint* aRelativePointOut)
{
// Making layers const correct is very slow because it requires
// a near clobber of the tree. Once const correct is further along
// remove this cast.
ContainerLayer& aLayer = const_cast<ContainerLayer&>(aLayerIn);
gfx3DMatrix transform = aLayer.GetLocalTransform().Inverse();
gfxPoint layerPoint = transform.Transform(aPoint);
// iterate over the children first. They are better match then the parent
Layer* currLayer = aLayer.GetLastChild();
while (currLayer) {
if (currLayer->AsContainerLayer()) {
GetAPZCAtPointOnSubtree(*currLayer->AsContainerLayer(), layerPoint, aApzcOut, aRelativePointOut);
}
if (*aApzcOut) {
return;
}
currLayer = currLayer->GetPrevSibling();
}
if (aLayer.GetFrameMetrics().IsScrollable()) {
const FrameMetrics& frame = aLayer.GetFrameMetrics();
LayerRect layerViewport = frame.mViewport * frame.LayersPixelsPerCSSPixel();
bool intersect = layerViewport.Contains(layerPoint.x, layerPoint.y);
if (intersect) {
*aApzcOut = aLayer.GetAsyncPanZoomController();
*aRelativePointOut = LayerIntPoint(NS_lround(layerPoint.x), NS_lround(layerPoint.y));
}
}
}
void AsyncPanZoomController::GetAPZCAtPoint(const ContainerLayer& aLayerTree,
const ScreenIntPoint& aPoint,
AsyncPanZoomController** aApzcOut,
LayerIntPoint* aRelativePointOut)
{
*aApzcOut = nullptr;
gfxPoint point(aPoint.x, aPoint.y);
GetAPZCAtPointOnSubtree(aLayerTree, point, aApzcOut, aRelativePointOut);
}
void AsyncPanZoomController::UpdateScrollOffset(CSSPoint aScrollOffset)
void AsyncPanZoomController::UpdateScrollOffset(const CSSPoint& aScrollOffset)
{
MonitorAutoLock monitor(mMonitor);
mFrameMetrics.mScrollOffset = aScrollOffset;
}
bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
{
// TODO: also check the presShellId and mScrollId, once those are
// fully propagated everywhere in RenderFrameParent and AndroidJNI.
return aGuid.mLayersId == mLayersId;
}
}
}

View File

@ -14,12 +14,14 @@
#include "InputData.h"
#include "Axis.h"
#include "TaskThrottler.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "base/message_loop.h"
namespace mozilla {
namespace layers {
struct ScrollableLayerGuid;
class CompositorParent;
class GestureEventListener;
class ContainerLayer;
@ -45,7 +47,7 @@ class ViewTransform;
* asynchronously scrolled subframes, we want to have one AsyncPanZoomController
* per frame.
*/
class AsyncPanZoomController MOZ_FINAL {
class AsyncPanZoomController {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController)
typedef mozilla::MonitorAutoLock MonitorAutoLock;
@ -68,19 +70,25 @@ public:
*/
static float GetTouchStartTolerance();
AsyncPanZoomController(GeckoContentController* aController,
AsyncPanZoomController(uint64_t aLayersId,
GeckoContentController* aController,
GestureBehavior aGestures = DEFAULT_GESTURES);
~AsyncPanZoomController();
// --------------------------------------------------------------------------
// These methods must only be called on the controller/UI thread.
// These methods must only be called on the gecko thread.
//
/**
* Shut down the controller/UI thread state and prepare to be
* deleted (which may happen from any thread).
* Read the various prefs and do any global initialization for all APZC instances.
* This must be run on the gecko thread before any APZC instances are actually
* used for anything meaningful.
*/
void Destroy();
static void InitializeGlobalState();
// --------------------------------------------------------------------------
// These methods must only be called on the controller/UI thread.
//
/**
* General handler for incoming input events. Manipulates the frame metrics
@ -166,26 +174,25 @@ public:
* idempotent. For example, a fling transform can be applied each time this is
* called (though not necessarily). |aSampleTime| is the time that this is
* sampled at; this is used for interpolating animations. Calling this sets a
* new transform in |aNewTransform| which should be applied directly to the
* shadow layer of the frame (do not multiply it in as the code already does
* this internally with |aLayer|'s transform).
* new transform in |aNewTransform| which should be multiplied to the transform
* in the shadow layer corresponding to this APZC.
*
* Return value indicates whether or not any currently running animation
* should continue. That is, if true, the compositor should schedule another
* composite.
*/
bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
ContainerLayer* aLayer,
ViewTransform* aNewTransform,
ScreenPoint& aScrollOffset);
/**
* A shadow layer update has arrived. |aViewportFrame| is the new FrameMetrics
* for the top-level frame. |aIsFirstPaint| is a flag passed from the shadow
* A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics
* for the container layer corresponding to this APZC.
* |aIsFirstPaint| is a flag passed from the shadow
* layers code indicating that the frame metrics being sent with this call are
* the initial metrics and the initial paint of the frame has just happened.
*/
void NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint);
void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint);
/**
* The platform implementation must set the compositor parent so that we can
@ -197,6 +204,24 @@ public:
// These methods can be called from any thread.
//
/**
* Shut down the controller/UI thread state and prepare to be
* deleted (which may happen from any thread).
*/
void Destroy();
/**
* Returns the incremental transformation corresponding to the async pan/zoom
* in progress. That is, when this transform is multiplied with the layer's
* existing transform, it will make the layer appear with the desired pan/zoom
* amount.
*/
ViewTransform GetCurrentAsyncTransform();
private:
/* Internal method of above. Callers to this MUST hold the monitor. */
ViewTransform GetCurrentAsyncTransformInternal();
public:
/**
* Sets the DPI of the device for use within panning and zooming logic. It is
* a platform responsibility to set this on initialization of this class and
@ -234,6 +259,11 @@ public:
*/
nsEventStatus HandleInputEvent(const InputData& aEvent);
/**
* Returns true if this APZC instance is for the layer identified by the guid.
*/
bool Matches(const ScrollableLayerGuid& aGuid);
/**
* Sync panning and zooming animation using a fixed frame time.
* This will ensure that we animate the APZC correctly with other external
@ -241,23 +271,12 @@ public:
*/
static void SetFrameTime(const TimeStamp& aMilliseconds);
/**
* Transform and intersect aPoint with the layer tree returning the appropriate
* AsyncPanZoomController for this point.
* aRelativePointOut Return the point transformed into the layer coordinates
* relative to the scroll origin for this layer.
*/
static void GetAPZCAtPoint(const ContainerLayer& aLayerTree,
const ScreenIntPoint& aPoint,
AsyncPanZoomController** aApzcOut,
LayerIntPoint* aRelativePointOut);
/**
* Update mFrameMetrics.mScrollOffset to the given offset.
* This is necessary in cases where a scroll is not caused by user
* input (for example, a content scrollTo()).
*/
void UpdateScrollOffset(CSSPoint aScrollOffset);
void UpdateScrollOffset(const CSSPoint& aScrollOffset);
/**
* Cancels any currently running animation. Note that all this does is set the
@ -492,16 +511,39 @@ private:
*/
void SetState(PanZoomState aState);
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
TaskThrottler mPaintThrottler;
/* Access to the following two fields is protected by the mRefPtrMonitor,
since they are accessed on the UI thread but can be cleared on the
compositor thread. */
nsRefPtr<GeckoContentController> mGeckoContentController;
nsRefPtr<GestureEventListener> mGestureEventListener;
Monitor mRefPtrMonitor;
/* Utility functions that return a addrefed pointer to the corresponding fields. */
already_AddRefed<GeckoContentController> GetGeckoContentController();
already_AddRefed<GestureEventListener> GetGestureEventListener();
protected:
// Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
// monitor. Do not read from or modify either of them without locking.
FrameMetrics mFrameMetrics;
// Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|.
// Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the
// monitor should be held. When setting |mState|, either the SetState()
// function can be used, or the monitor can be held and then |mState| updated.
Monitor mMonitor;
private:
// Metrics of the container layer corresponding to this APZC. This is
// stored here so that it is accessible from the UI/controller thread.
// These are the metrics at last content paint, the most recent
// values we were notified of in NotifyLayersUpdate().
// values we were notified of in NotifyLayersUpdate(). Since it represents
// the Gecko state, it should be used as a basis for untransformation when
// sending messages back to Gecko.
FrameMetrics mLastContentPaintMetrics;
// The last metrics that we requested a paint for. These are used to make sure
// that we're not requesting a paint of the same thing that's already drawn.
@ -532,14 +574,6 @@ private:
float mMinZoom;
float mMaxZoom;
// Protects |mFrameMetrics|, |mLastContentPaintMetrics|, |mState| and
// |mMetaViewportInfo|. Before manipulating |mFrameMetrics| or
// |mLastContentPaintMetrics|, the monitor should be held. When setting
// |mState|, either the SetState() function can be used, or the monitor can be
// held and then |mState| updated. |mMetaViewportInfo| should be updated
// using UpdateMetaViewport().
Monitor mMonitor;
// The last time the compositor has sampled the content transform for this
// frame.
TimeStamp mLastSampleTime;
@ -571,14 +605,6 @@ private:
// ensures the last mozbrowserasyncscroll event is always been fired.
CancelableTask* mAsyncScrollTimeoutTask;
// The time period in ms that throttles mozbrowserasyncscroll event.
// Default is 100ms if there is no "apzc.asyncscroll.throttle" in preference.
uint32_t mAsyncScrollThrottleTime;
// The timeout in ms for mAsyncScrollTimeoutTask delay task.
// Default is 300ms if there is no "apzc.asyncscroll.timeout" in preference.
uint32_t mAsyncScrollTimeout;
int mDPI;
// Flag used to determine whether or not we should disable handling of the
@ -598,6 +624,37 @@ private:
bool mDelayPanning;
friend class Axis;
/* The functions and members in this section are used to build a tree
* structure out of APZC instances. This tree can only be walked or
* manipulated while holding the lock in the associated APZCTreeManager
* instance.
*/
public:
void SetLastChild(AsyncPanZoomController* child) { mLastChild = child; }
void SetPrevSibling(AsyncPanZoomController* sibling) { mPrevSibling = sibling; }
AsyncPanZoomController* GetLastChild() const { return mLastChild; }
AsyncPanZoomController* GetPrevSibling() const { return mPrevSibling; }
private:
nsRefPtr<AsyncPanZoomController> mLastChild;
nsRefPtr<AsyncPanZoomController> mPrevSibling;
/* The functions and members in this section are used to maintain the
* area that this APZC instance is responsible for. This is used when
* hit-testing to see which APZC instance should handle touch events.
*/
public:
void SetVisibleRegion(gfxRect rect) { mVisibleRegion = rect; }
bool VisibleRegionContains(const gfxPoint& aPoint) const {
return mVisibleRegion.Contains(aPoint.x, aPoint.y);
}
private:
/* This is the viewport of the layer that this APZC corresponds to, but
* post-transform. In other words, it is in the coordinate space of its
* parent layer. */
gfxRect mVisibleRegion;
};
}

View File

@ -8,7 +8,6 @@
#include "mozilla/DebugOnly.h"
#include "AsyncPanZoomController.h"
#include "AutoOpenSurface.h"
#include "CompositorParent.h"
#include "mozilla/layers/CompositorOGL.h"
@ -155,6 +154,10 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor,
this, &mCompositorID));
mRootLayerTreeID = AllocateLayerTreeId();
sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
mApzcTreeManager = new APZCTreeManager();
++sCompositorThreadRefCount;
}
@ -170,6 +173,12 @@ CompositorParent::IsInCompositorThread()
return CompositorThreadID() == PlatformThread::CurrentId();
}
uint64_t
CompositorParent::RootLayerTreeId()
{
return mRootLayerTreeID;
}
CompositorParent::~CompositorParent()
{
MOZ_COUNT_DTOR(CompositorParent);
@ -186,6 +195,9 @@ CompositorParent::Destroy()
// Ensure that the layer manager is destructed on the compositor thread.
mLayerManager = nullptr;
mCompositionManager = nullptr;
mApzcTreeManager->ClearTree();
mApzcTreeManager = nullptr;
sIndirectLayerTrees.erase(mRootLayerTreeID);
}
void
@ -404,8 +416,13 @@ CompositorParent::ScheduleTask(CancelableTask* task, int time)
}
void
CompositorParent::NotifyShadowTreeTransaction()
CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint)
{
if (mApzcTreeManager) {
AutoResolveRefLayers resolve(mCompositionManager);
mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId);
}
if (mLayerManager) {
LayerManagerComposite* managerComposite = mLayerManager->AsLayerManagerComposite();
if (managerComposite) {
@ -559,6 +576,12 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
mCompositionManager->Updated(isFirstPaint, aTargetConfig);
Layer* root = aLayerTree->GetRoot();
mLayerManager->SetRoot(root);
if (mApzcTreeManager) {
AutoResolveRefLayers resolve(mCompositionManager);
mApzcTreeManager->UpdatePanZoomControllerTree(this, root, isFirstPaint, mRootLayerTreeID);
}
if (root) {
SetShadowProperties(root);
if (mIsTesting) {
@ -704,7 +727,7 @@ CompositorParent::AllocateLayerTreeId()
{
MOZ_ASSERT(CompositorLoop());
MOZ_ASSERT(NS_IsMainThread());
static uint64_t ids;
static uint64_t ids = 0;
return ++ids;
}
@ -724,20 +747,30 @@ CompositorParent::DeallocateLayerTreeId(uint64_t aId)
static void
UpdateControllerForLayersId(uint64_t aLayersId,
AsyncPanZoomController* aController)
GeckoContentController* aController)
{
// Adopt ref given to us by SetPanZoomControllerForLayerTree()
// Adopt ref given to us by SetControllerForLayerTree()
sIndirectLayerTrees[aLayersId].mController =
already_AddRefed<AsyncPanZoomController>(aController);
already_AddRefed<GeckoContentController>(aController);
}
// Notify the AsyncPanZoomController about the current compositor so that it
// can request composites off the compositor thread.
aController->SetCompositorParent(sIndirectLayerTrees[aLayersId].mParent);
ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(uint64_t aLayersId,
Layer* aRoot,
GeckoContentController* aController)
: mLayersId(aLayersId)
{
sIndirectLayerTrees[aLayersId].mRoot = aRoot;
sIndirectLayerTrees[aLayersId].mController = aController;
}
ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration()
{
sIndirectLayerTrees.erase(mLayersId);
}
/*static*/ void
CompositorParent::SetPanZoomControllerForLayerTree(uint64_t aLayersId,
AsyncPanZoomController* aController)
CompositorParent::SetControllerForLayerTree(uint64_t aLayersId,
GeckoContentController* aController)
{
// This ref is adopted by UpdateControllerForLayersId().
aController->AddRef();
@ -747,6 +780,16 @@ CompositorParent::SetPanZoomControllerForLayerTree(uint64_t aLayersId,
aController));
}
/*static*/ APZCTreeManager*
CompositorParent::GetAPZCTreeManager(uint64_t aLayersId)
{
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
if (state && state->mParent) {
return state->mParent->mApzcTreeManager;
}
return nullptr;
}
/**
* This class handles layer updates pushed directly from child
* processes to the compositor thread. It's associated with a
@ -831,16 +874,10 @@ CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess)
}
static void
UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig, bool isFirstPaint)
UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig)
{
sIndirectLayerTrees[aId].mRoot = aRoot;
sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
ContainerLayer* rootContainer = aRoot->AsContainerLayer();
if (rootContainer) {
if (AsyncPanZoomController* apzc = sIndirectLayerTrees[aId].mController) {
apzc->NotifyLayersUpdated(rootContainer->GetFrameMetrics(), isFirstPaint);
}
}
}
/* static */ const CompositorParent::LayerTreeState*
@ -912,9 +949,9 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
if (shadowRoot) {
SetShadowProperties(shadowRoot);
}
UpdateIndirectTree(id, shadowRoot, aTargetConfig, isFirstPaint);
UpdateIndirectTree(id, shadowRoot, aTargetConfig);
sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction();
sIndirectLayerTrees[id].mParent->NotifyShadowTreeTransaction(id, isFirstPaint);
}
void

View File

@ -17,6 +17,7 @@
#include "mozilla/layers/PCompositorParent.h"
#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "base/thread.h"
#include "mozilla/Monitor.h"
#include "mozilla/TimeStamp.h"
@ -31,12 +32,23 @@ class Thread;
namespace mozilla {
namespace layers {
class AsyncPanZoomController;
class APZCTreeManager;
class Layer;
class LayerManagerComposite;
class AsyncCompositionManager;
struct TextureFactoryIdentifier;
struct ScopedLayerTreeRegistration
{
ScopedLayerTreeRegistration(uint64_t aLayersId,
Layer* aRoot,
GeckoContentController* aController);
~ScopedLayerTreeRegistration();
private:
uint64_t mLayersId;
};
class CompositorParent : public PCompositorParent,
public ShadowLayersManager
{
@ -89,7 +101,13 @@ public:
bool ScheduleResumeOnCompositorThread(int width, int height);
virtual void ScheduleComposition();
void NotifyShadowTreeTransaction();
void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint);
/**
* Returns the unique layer tree identifier that corresponds to the root
* tree of this compositor.
*/
uint64_t RootLayerTreeId();
/**
* Returns a pointer to the compositor corresponding to the given ID.
@ -128,13 +146,19 @@ public:
static void DeallocateLayerTreeId(uint64_t aId);
/**
* Set aController as the pan/zoom controller for the tree referred
* Set aController as the pan/zoom callback for the subtree referred
* to by aLayersId.
*
* Must run on content main thread.
*/
static void SetPanZoomControllerForLayerTree(uint64_t aLayersId,
AsyncPanZoomController* aController);
static void SetControllerForLayerTree(uint64_t aLayersId,
GeckoContentController* aController);
/**
* This returns a reference to the APZCTreeManager to which
* pan/zoom-related events can be sent.
*/
static APZCTreeManager* GetAPZCTreeManager(uint64_t aLayersId);
/**
* A new child process has been configured to push transactions
@ -154,7 +178,7 @@ public:
struct LayerTreeState {
nsRefPtr<Layer> mRoot;
nsRefPtr<AsyncPanZoomController> mController;
nsRefPtr<GeckoContentController> mController;
CompositorParent *mParent;
TargetConfig mTargetConfig;
};
@ -264,10 +288,13 @@ private:
mozilla::Monitor mResumeCompositionMonitor;
uint64_t mCompositorID;
uint64_t mRootLayerTreeID;
bool mOverrideComposeReadiness;
CancelableTask* mForceCompositionTask;
nsRefPtr<APZCTreeManager> mApzcTreeManager;
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};

View File

@ -51,7 +51,8 @@ public:
* |aContentRect| is in CSS pixels, relative to the current cssPage.
* |aScrollableSize| is the current content width/height in CSS pixels.
*/
virtual void SendAsyncScrollDOMEvent(const CSSRect &aContentRect,
virtual void SendAsyncScrollDOMEvent(FrameMetrics::ViewID aScrollId,
const CSSRect &aContentRect,
const CSSSize &aScrollableSize) = 0;
/**

View File

@ -105,6 +105,7 @@ EXPORTS.mozilla.layers += [
'client/ImageClient.h',
'client/TextureClient.h',
'client/TiledContentClient.h',
'composite/APZCTreeManager.h',
'composite/AsyncCompositionManager.h',
'composite/CanvasLayerComposite.h',
'composite/ColorLayerComposite.h',
@ -170,6 +171,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
]
CPP_SOURCES += [
'APZCTreeManager.cpp',
'AsyncCompositionManager.cpp',
'AsyncPanZoomController.cpp',
'Axis.cpp',

View File

@ -10,6 +10,8 @@
#include "mozilla/layers/AsyncPanZoomController.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "Layers.h"
#include "TestLayers.h"
@ -24,7 +26,7 @@ public:
MOCK_METHOD1(HandleDoubleTap, void(const CSSIntPoint&));
MOCK_METHOD1(HandleSingleTap, void(const CSSIntPoint&));
MOCK_METHOD1(HandleLongTap, void(const CSSIntPoint&));
MOCK_METHOD2(SendAsyncScrollDOMEvent, void(const CSSRect &aContentRect, const CSSSize &aScrollableSize));
MOCK_METHOD3(SendAsyncScrollDOMEvent, void(FrameMetrics::ViewID aScrollId, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
};
@ -39,6 +41,23 @@ class TestAPZCContainerLayer : public ContainerLayer {
void RepositionChild(Layer* aChild, Layer* aAfter) {}
};
class TestAsyncPanZoomController : public AsyncPanZoomController {
public:
TestAsyncPanZoomController(uint64_t aLayersId, MockContentController* mcc)
: AsyncPanZoomController(aLayersId, mcc)
{}
void SetFrameMetrics(const FrameMetrics& metrics) {
MonitorAutoLock lock(mMonitor);
mFrameMetrics = metrics;
}
};
class TestAPZCTreeManager : public APZCTreeManager {
protected:
void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
};
static
FrameMetrics TestFrameMetrics() {
FrameMetrics fm;
@ -90,21 +109,20 @@ void ApzcPan(AsyncPanZoomController* apzc, int& aTime, int aTouchStartY, int aTo
TEST(AsyncPanZoomController, Constructor) {
// RefCounted class can't live in the stack
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
}
TEST(AsyncPanZoomController, SimpleTransform) {
TimeStamp testStartTime = TimeStamp::Now();
// RefCounted class can't live in the stack
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
TestAPZCContainerLayer layer;
ScreenPoint pointOut;
ViewTransform viewTransformOut;
apzc->SampleContentTransformForFrame(testStartTime, &layer, &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(pointOut, ScreenPoint());
EXPECT_EQ(viewTransformOut, ViewTransform());
@ -131,7 +149,8 @@ TEST(AsyncPanZoomController, ComplexTransform) {
// sides.
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
nsRefPtr<TestAsyncPanZoomController> childApzc = new TestAsyncPanZoomController(0, mcc);
const char* layerTreeSyntax = "c(c)";
// LayerID 0 1
@ -174,39 +193,41 @@ TEST(AsyncPanZoomController, ComplexTransform) {
// the CSS transform on the child layer does not affect the SampleContentTransformForFrame code
// initial transform
apzc->SetFrameMetrics(metrics);
apzc->NotifyLayersUpdated(metrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[0]->AsContainerLayer(), &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(60, 60), pointOut);
apzc->NotifyLayersUpdated(childMetrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[1]->AsContainerLayer(), &viewTransformOut, pointOut);
childApzc->SetFrameMetrics(childMetrics);
childApzc->NotifyLayersUpdated(childMetrics, true);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(60, 60), pointOut);
// do an async scroll by 5 pixels and check the transform
metrics.mScrollOffset += CSSPoint(5, 0);
apzc->NotifyLayersUpdated(metrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[0]->AsContainerLayer(), &viewTransformOut, pointOut);
apzc->SetFrameMetrics(metrics);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(90, 60), pointOut);
childMetrics.mScrollOffset += CSSPoint(5, 0);
apzc->NotifyLayersUpdated(childMetrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[1]->AsContainerLayer(), &viewTransformOut, pointOut);
childApzc->SetFrameMetrics(childMetrics);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(90, 60), pointOut);
// do an async zoom of 1.5x and check the transform
metrics.mZoom.scale *= 1.5f;
apzc->NotifyLayersUpdated(metrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[0]->AsContainerLayer(), &viewTransformOut, pointOut);
apzc->SetFrameMetrics(metrics);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ScreenPoint(135, 90), pointOut);
childMetrics.mZoom.scale *= 1.5f;
apzc->NotifyLayersUpdated(childMetrics, true);
apzc->SampleContentTransformForFrame(testStartTime, layers[0]->AsContainerLayer(), &viewTransformOut, pointOut);
childApzc->SetFrameMetrics(childMetrics);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ScreenPoint(135, 90), pointOut);
}
@ -216,28 +237,29 @@ TEST(AsyncPanZoomController, Pan) {
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_)).Times(4);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(4);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
int time = 0;
int touchStart = 50;
int touchEnd = 10;
TestAPZCContainerLayer layer;
ScreenPoint pointOut;
ViewTransform viewTransformOut;
// Pan down
ApzcPan(apzc, time, touchStart, touchEnd);
apzc->SampleContentTransformForFrame(testStartTime, &layer, &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(pointOut, ScreenPoint(0, -(touchEnd-touchStart)));
EXPECT_NE(viewTransformOut, ViewTransform());
// Pan back
ApzcPan(apzc, time, touchEnd, touchStart);
apzc->SampleContentTransformForFrame(testStartTime, &layer, &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(pointOut, ScreenPoint());
EXPECT_EQ(viewTransformOut, ViewTransform());
}
@ -247,16 +269,17 @@ TEST(AsyncPanZoomController, Fling) {
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_)).Times(2);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
int time = 0;
int touchStart = 50;
int touchEnd = 10;
TestAPZCContainerLayer layer;
ScreenPoint pointOut;
ViewTransform viewTransformOut;
@ -264,7 +287,7 @@ TEST(AsyncPanZoomController, Fling) {
ApzcPan(apzc, time, touchStart, touchEnd);
ScreenPoint lastPoint;
for (int i = 1; i < 50; i+=1) {
apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &layer, &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &viewTransformOut, pointOut);
EXPECT_GT(pointOut.y, lastPoint.y);
lastPoint = pointOut;
}
@ -275,23 +298,24 @@ TEST(AsyncPanZoomController, OverScrollPanning) {
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzc = new AsyncPanZoomController(mcc);
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
apzc->SetFrameMetrics(TestFrameMetrics());
apzc->NotifyLayersUpdated(TestFrameMetrics(), true);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_)).Times(3);
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(3);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
// Pan sufficiently to hit overscroll behavior
int time = 0;
int touchStart = 500;
int touchEnd = 10;
TestAPZCContainerLayer layer;
ScreenPoint pointOut;
ViewTransform viewTransformOut;
// Pan down
ApzcPan(apzc, time, touchStart, touchEnd);
apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &layer, &viewTransformOut, pointOut);
apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
EXPECT_EQ(pointOut, ScreenPoint(0, 90));
}
@ -322,124 +346,102 @@ CreateTestLayerTree(nsRefPtr<LayerManager>& aLayerManager, nsTArray<nsRefPtr<Lay
return CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, aLayerManager, aLayers);
}
TEST(AsyncPanZoomController, GetAPZCAtPoint) {
static void
SetScrollableFrameMetrics(Layer* aLayer, FrameMetrics::ViewID aScrollId, MockContentController* mcc)
{
ContainerLayer* container = aLayer->AsContainerLayer();
FrameMetrics metrics;
metrics.mScrollId = aScrollId;
nsIntRect layerBound = aLayer->GetVisibleRegion().GetBounds();
metrics.mCompositionBounds = ScreenIntRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
metrics.mViewport = CSSRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
container->SetFrameMetrics(metrics);
// when we do the next tree update, a new APZC will be created for this layer,
// and that will invoke these functions once.
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(1);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
}
TEST(APZCTreeManager, GetAPZCAtPoint) {
nsTArray<nsRefPtr<Layer> > layers;
nsRefPtr<LayerManager> lm;
nsRefPtr<Layer> root = CreateTestLayerTree(lm, layers);
TimeStamp testStartTime = TimeStamp::Now();
AsyncPanZoomController::SetFrameTime(testStartTime);
nsRefPtr<MockContentController> mcc = new MockContentController();
nsRefPtr<AsyncPanZoomController> apzcMain = new AsyncPanZoomController(mcc);
nsRefPtr<AsyncPanZoomController> apzcSub3 = new AsyncPanZoomController(mcc);
nsRefPtr<AsyncPanZoomController> apzcSub4 = new AsyncPanZoomController(mcc);
nsRefPtr<AsyncPanZoomController> apzcSub7 = new AsyncPanZoomController(mcc);
apzcMain->NotifyLayersUpdated(TestFrameMetrics(), true);
ScopedLayerTreeRegistration controller(0, root, mcc);
nsIntRect layerBound;
ScreenIntPoint touchPoint(20, 20);
AsyncPanZoomController* apzcOut;
LayerIntPoint relativePointOut;
FrameMetrics scrollable;
nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
// No APZC attached so hit testing will return no APZC at (20,20)
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20));
AsyncPanZoomController* nullAPZC = nullptr;
EXPECT_EQ(apzcOut, nullAPZC);
EXPECT_EQ(nullAPZC, hit.get());
// Now we have a root APZC that will match the page
scrollable.mScrollId = FrameMetrics::ROOT_SCROLL_ID;
layerBound = root->GetVisibleRegion().GetBounds();
scrollable.mViewport = CSSRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
root->AsContainerLayer()->SetFrameMetrics(scrollable);
root->AsContainerLayer()->SetAsyncPanZoomController(apzcMain);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcMain.get());
EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut);
SetScrollableFrameMetrics(root, FrameMetrics::ROOT_SCROLL_ID, mcc);
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerIntPoint(15, 15)
// Now we have a sub APZC with a better fit
scrollable.mScrollId = FrameMetrics::START_SCROLL_ID;
layerBound = layers[3]->GetVisibleRegion().GetBounds();
scrollable.mViewport = CSSRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
layers[3]->AsContainerLayer()->SetFrameMetrics(scrollable);
layers[3]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub3);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub3.get());
EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut);
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));
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
touchPoint = ScreenIntPoint(15,15);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub3.get()); // We haven't bound apzcSub4 yet
scrollable.mScrollId++;
layerBound = layers[4]->GetVisibleRegion().GetBounds();
scrollable.mViewport = CSSRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
layers[4]->AsContainerLayer()->SetFrameMetrics(scrollable);
layers[4]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub4);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub4.get());
EXPECT_EQ(LayerIntPoint(15, 15), relativePointOut);
hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
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));
EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerIntPoint(15, 15)
// Hit test ouside the reach of apzc3/4 but inside apzcMain
touchPoint = ScreenIntPoint(90,90);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcMain.get());
EXPECT_EQ(LayerIntPoint(90, 90), relativePointOut);
// Hit test ouside the reach of layer[3,4] but inside root
hit = manager->GetTargetAPZC(ScreenPoint(90, 90));
EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerIntPoint(90, 90)
// Hit test ouside the reach of any layer
touchPoint = ScreenIntPoint(1000,10);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, nullAPZC);
touchPoint = ScreenIntPoint(-1000,10);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, nullAPZC);
hit = manager->GetTargetAPZC(ScreenPoint(1000, 10));
EXPECT_EQ(nullAPZC, hit.get());
hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10));
EXPECT_EQ(nullAPZC, hit.get());
// Test layer transform
gfx3DMatrix transform;
transform.ScalePost(0.1, 0.1, 1);
root->SetBaseTransform(transform);
root->ComputeEffectiveTransforms(gfx3DMatrix());
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer
EXPECT_EQ(nullAPZC, hit.get());
touchPoint = ScreenIntPoint(50,50); // This point is now outside the root layer
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, nullAPZC);
touchPoint = ScreenIntPoint(2,2);
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub4.get());
EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut);
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 20)
// Scale layer[4] outside the range
layers[4]->SetBaseTransform(transform);
// layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2)
// Does not contain (2, 2)
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub3.get());
EXPECT_EQ(LayerIntPoint(20, 20), relativePointOut);
root->ComputeEffectiveTransforms(gfx3DMatrix());
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 20)
// Transformation chain to layer 7
scrollable.mScrollId++;
layerBound = layers[7]->GetVisibleRegion().GetBounds();
scrollable.mViewport = CSSRect(layerBound.x, layerBound.y,
layerBound.width, layerBound.height);
layers[7]->AsContainerLayer()->SetFrameMetrics(scrollable);
layers[7]->AsContainerLayer()->SetAsyncPanZoomController(apzcSub7);
SetScrollableFrameMetrics(layers[7], FrameMetrics::START_SCROLL_ID + 2, mcc);
gfx3DMatrix translateTransform;
translateTransform.Translate(gfxPoint3D(10, 10, 0));
@ -453,12 +455,14 @@ TEST(AsyncPanZoomController, GetAPZCAtPoint) {
translateTransform3.ScalePost(1,15,1);
layers[7]->SetBaseTransform(translateTransform3);
touchPoint = ScreenIntPoint(1,45);
root->ComputeEffectiveTransforms(gfx3DMatrix());
manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
// layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers
AsyncPanZoomController::GetAPZCAtPoint(*root->AsContainerLayer(), touchPoint,
&apzcOut, &relativePointOut);
EXPECT_EQ(apzcOut, apzcSub7.get());
EXPECT_EQ(LayerIntPoint(20, 29), relativePointOut);
hit = manager->GetTargetAPZC(ScreenPoint(1, 45));
EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
// expect hit point at LayerPoint(20, 29)
manager->ClearTree();
}

View File

@ -48,6 +48,7 @@ public:
}
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
virtual void RepositionChild(Layer* aChild, Layer* aAfter) {
@ -92,10 +93,6 @@ public:
return TYPE_THEBES;
}
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) {
MOZ_CRASH();
}
virtual void InvalidateRegion(const nsIntRegion& aRegion) {
MOZ_CRASH();
}
@ -236,6 +233,9 @@ already_AddRefed<Layer> CreateLayerTree(
lastLayer = layer;
}
}
if (rootLayer) {
rootLayer->ComputeEffectiveTransforms(gfx3DMatrix());
}
return rootLayer.forget();
}

View File

@ -469,6 +469,23 @@ nsLayoutUtils::FindContentFor(ViewID aId)
}
}
nsIScrollableFrame*
nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
{
nsIContent* content = FindContentFor(aId);
if (!content) {
return nullptr;
}
nsIFrame* scrolledFrame = content->GetPrimaryFrame();
if (scrolledFrame && content->OwnerDoc()->GetRootElement() == content) {
// The content is the root element of a subdocument, so return the root scrollable
// for the subdocument.
scrolledFrame = scrolledFrame->PresContext()->PresShell()->GetRootScrollFrame();
}
return scrolledFrame ? scrolledFrame->GetScrollTargetFrame() : nullptr;
}
bool
nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
{

View File

@ -76,6 +76,11 @@ public:
*/
static nsIContent* FindContentFor(ViewID aId);
/**
* Find the scrollable frame for a given ID.
*/
static nsIScrollableFrame* FindScrollableFrameFor(ViewID aId);
/**
* Get display port for the given element.
*/

View File

@ -15,7 +15,7 @@
#endif //MOZ_ENABLE_D3D9_LAYER
#include "mozilla/BrowserElementParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/layers/AsyncPanZoomController.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/LayerTransactionParent.h"
#include "nsContentUtils.h"
@ -552,7 +552,8 @@ public:
void ClearRenderFrame() { mRenderFrame = nullptr; }
virtual void SendAsyncScrollDOMEvent(const CSSRect& aContentRect,
virtual void SendAsyncScrollDOMEvent(FrameMetrics::ViewID aScrollId,
const CSSRect& aContentRect,
const CSSSize& aContentSize) MOZ_OVERRIDE
{
if (MessageLoop::current() != mUILoop) {
@ -560,10 +561,10 @@ public:
FROM_HERE,
NewRunnableMethod(this,
&RemoteContentController::SendAsyncScrollDOMEvent,
aContentRect, aContentSize));
aScrollId, aContentRect, aContentSize));
return;
}
if (mRenderFrame) {
if (mRenderFrame && aScrollId == FrameMetrics::ROOT_SCROLL_ID) {
TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect,
aContentSize);
@ -620,14 +621,24 @@ RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader,
}
if (aScrollingBehavior == ASYNC_PAN_ZOOM) {
mContentController = new RemoteContentController(this);
mPanZoomController = new AsyncPanZoomController(
mContentController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
CompositorParent::SetPanZoomControllerForLayerTree(mLayersId,
mPanZoomController);
CompositorParent::SetControllerForLayerTree(mLayersId, mContentController);
}
}
}
APZCTreeManager*
RenderFrameParent::GetApzcTreeManager()
{
// We can't get a ref to the APZCTreeManager until after the child is
// created and the static getter knows which CompositorParent is
// instantiated with this layers ID. That's why try to fetch it when
// we first need it and cache the result.
if (!mApzcTreeManager) {
mApzcTreeManager = CompositorParent::GetAPZCTreeManager(mLayersId);
}
return mApzcTreeManager.get();
}
RenderFrameParent::~RenderFrameParent()
{}
@ -787,17 +798,17 @@ void
RenderFrameParent::NotifyInputEvent(const nsInputEvent& aEvent,
nsInputEvent* aOutEvent)
{
if (mPanZoomController) {
mPanZoomController->ReceiveInputEvent(aEvent, aOutEvent);
if (GetApzcTreeManager()) {
GetApzcTreeManager()->ReceiveInputEvent(aEvent, aOutEvent);
}
}
void
RenderFrameParent::NotifyDimensionsChanged(ScreenIntSize size)
{
if (mPanZoomController) {
mPanZoomController->UpdateCompositionBounds(
ScreenIntRect(ScreenIntPoint(), size));
if (GetApzcTreeManager()) {
GetApzcTreeManager()->UpdateCompositionBounds(ScrollableLayerGuid(mLayersId),
ScreenIntRect(ScreenIntPoint(), size));
}
}
@ -810,7 +821,7 @@ RenderFrameParent::ActorDestroy(ActorDestroyReason why)
// Stop our content controller from requesting repaints of our
// content.
mContentController->ClearRenderFrame();
mPanZoomController->Destroy();
// TODO: notify the compositor?
}
}
@ -836,8 +847,8 @@ RenderFrameParent::RecvNotifyCompositorTransaction()
bool
RenderFrameParent::RecvCancelDefaultPanZoom()
{
if (mPanZoomController) {
mPanZoomController->CancelDefaultPanZoom();
if (GetApzcTreeManager()) {
GetApzcTreeManager()->CancelDefaultPanZoom(ScrollableLayerGuid(mLayersId));
}
return true;
}
@ -845,8 +856,8 @@ RenderFrameParent::RecvCancelDefaultPanZoom()
bool
RenderFrameParent::RecvDetectScrollableSubframe()
{
if (mPanZoomController) {
mPanZoomController->DetectScrollableSubframe();
if (GetApzcTreeManager()) {
GetApzcTreeManager()->DetectScrollableSubframe(ScrollableLayerGuid(mLayersId));
}
return true;
}
@ -972,24 +983,27 @@ RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
void
RenderFrameParent::ZoomToRect(const CSSRect& aRect)
{
if (mPanZoomController) {
mPanZoomController->ZoomToRect(aRect);
if (GetApzcTreeManager()) {
GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId),
aRect);
}
}
void
RenderFrameParent::ContentReceivedTouch(bool aPreventDefault)
{
if (mPanZoomController) {
mPanZoomController->ContentReceivedTouch(aPreventDefault);
if (GetApzcTreeManager()) {
GetApzcTreeManager()->ContentReceivedTouch(ScrollableLayerGuid(mLayersId),
aPreventDefault);
}
}
void
RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom)
{
if (mPanZoomController) {
mPanZoomController->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
if (GetApzcTreeManager()) {
GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId),
aAllowZoom, aMinZoom, aMaxZoom);
}
}

View File

@ -25,7 +25,7 @@ namespace mozilla {
class InputEvent;
namespace layers {
class AsyncPanZoomController;
class APZCTreeManager;
class GestureEventListener;
class TargetConfig;
class LayerTransactionParent;
@ -132,11 +132,13 @@ private:
nsRefPtr<nsFrameLoader> mFrameLoader;
nsRefPtr<ContainerLayer> mContainer;
// When our scrolling behavior is ASYNC_PAN_ZOOM, we have a nonnull
// AsyncPanZoomController. It's associated with the shadow layer
// tree on the compositor thread.
nsRefPtr<layers::AsyncPanZoomController> mPanZoomController;
// APZCTreeManager. It's used to manipulate the shadow layer tree
// on the compositor thread.
nsRefPtr<layers::APZCTreeManager> mApzcTreeManager;
nsRefPtr<RemoteContentController> mContentController;
layers::APZCTreeManager* GetApzcTreeManager();
// This contains the views for all the scrollable frames currently in the
// painted region of our remote content.
ViewMap mContentViews;

View File

@ -96,6 +96,9 @@ endif #}
ifdef MOZ_B2G_BT #{
STATIC_LIBS += mozdbus_s
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
OS_LIBS += -ldbus
endif
endif #}
ifneq ($(strip $(MOZ_B2G_RIL)$(MOZ_B2G_BT)),) #{
@ -446,7 +449,6 @@ OS_LIBS += \
-lsysutils \
-lcamera_client \
-lsensorservice \
-ldbus \
-lstagefright \
-lstagefright_foundation \
-lstagefright_omx \

View File

@ -2850,7 +2850,9 @@ AndroidBridge::HandleLongTap(const CSSIntPoint& aPoint)
}
void
AndroidBridge::SendAsyncScrollDOMEvent(const CSSRect& aContentRect, const CSSSize& aScrollableSize)
AndroidBridge::SendAsyncScrollDOMEvent(mozilla::layers::FrameMetrics::ViewID aScrollId,
const CSSRect& aContentRect,
const CSSSize& aScrollableSize)
{
// FIXME implement this
}

View File

@ -601,7 +601,9 @@ public:
void HandleDoubleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
void HandleSingleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
void HandleLongTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE;
void SendAsyncScrollDOMEvent(const CSSRect& aContentRect, const CSSSize& aScrollableSize) MOZ_OVERRIDE;
void SendAsyncScrollDOMEvent(mozilla::layers::FrameMetrics::ViewID aScrollId,
const CSSRect& aContentRect,
const CSSSize& aScrollableSize) MOZ_OVERRIDE;
void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE;
int64_t RunDelayedTasks();
};

View File

@ -35,7 +35,7 @@
#include "mozilla/dom/mobilemessage/Types.h"
#include "mozilla/dom/mobilemessage/PSms.h"
#include "mozilla/dom/mobilemessage/SmsParent.h"
#include "mozilla/layers/AsyncPanZoomController.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "nsIMobileMessageDatabaseService.h"
#include "nsPluginInstanceOwner.h"
#include "nsSurfaceTexture.h"
@ -847,10 +847,10 @@ Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_gfx_NativePanZoomController_abortAnimation(JNIEnv* env, jobject instance)
{
AsyncPanZoomController* controller = nsWindow::GetPanZoomController();
if (controller) {
controller->CancelAnimation();
}
APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
if (controller) {
controller->CancelAnimation(ScrollableLayerGuid(nsWindow::RootLayerTreeId()));
}
}
NS_EXPORT void JNICALL
@ -865,13 +865,12 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject ins
MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
env->DeleteGlobalRef(oldRef);
}
nsWindow::SetPanZoomController(new AsyncPanZoomController(AndroidBridge::Bridge(), AsyncPanZoomController::USE_GESTURE_DETECTOR));
}
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
{
AsyncPanZoomController *controller = nsWindow::GetPanZoomController();
APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
if (controller) {
AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event);
const MultiTouchInput& input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow());
@ -905,7 +904,6 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject
return;
}
nsWindow::SetPanZoomController(nullptr);
jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(NULL);
if (!oldRef) {
MOZ_ASSERT(false, "Clearing a non-existent NPZC");
@ -917,9 +915,9 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
{
AsyncPanZoomController *controller = nsWindow::GetPanZoomController();
APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
if (controller) {
controller->ContentReceivedTouch(prevented);
controller->ContentReceivedTouch(ScrollableLayerGuid(nsWindow::RootLayerTreeId()), prevented);
}
}
@ -946,9 +944,9 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_gfx_NativePanZoomController_updateScrollOffset(JNIEnv* env, jobject instance, jfloat cssX, jfloat cssY)
{
AsyncPanZoomController* controller = nsWindow::GetPanZoomController();
APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
if (controller) {
controller->UpdateScrollOffset(CSSPoint(cssX, cssY));
controller->UpdateScrollOffset(ScrollableLayerGuid(nsWindow::RootLayerTreeId()), CSSPoint(cssX, cssY));
}
}

View File

@ -2417,11 +2417,11 @@ nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect)
// off-main-thread compositor fields and functions
nsRefPtr<mozilla::layers::APZCTreeManager> nsWindow::sApzcTreeManager = 0;
nsRefPtr<mozilla::layers::LayerManager> nsWindow::sLayerManager = 0;
nsRefPtr<mozilla::layers::CompositorParent> nsWindow::sCompositorParent = 0;
nsRefPtr<mozilla::layers::CompositorChild> nsWindow::sCompositorChild = 0;
bool nsWindow::sCompositorPaused = true;
nsRefPtr<mozilla::layers::AsyncPanZoomController> nsWindow::sApzc = 0;
void
nsWindow::SetCompositor(mozilla::layers::LayerManager* aLayerManager,
@ -2496,52 +2496,30 @@ nsWindow::NeedsPaint()
return nsIWidget::NeedsPaint();
}
class AndroidCompositorParent : public CompositorParent {
public:
AndroidCompositorParent(nsIWidget* aWidget, bool aRenderToEGLSurface,
int aSurfaceWidth, int aSurfaceHeight)
: CompositorParent(aWidget, aRenderToEGLSurface, aSurfaceWidth, aSurfaceHeight)
{
if (nsWindow::GetPanZoomController()) {
nsWindow::GetPanZoomController()->SetCompositorParent(this);
}
}
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, const TargetConfig& aTargetConfig,
bool isFirstPaint) MOZ_OVERRIDE
{
CompositorParent::ShadowLayersUpdated(aLayerTree, aTargetConfig, isFirstPaint);
Layer* targetLayer = GetLayerManager()->GetPrimaryScrollableLayer();
AsyncPanZoomController* controller = nsWindow::GetPanZoomController();
if (targetLayer && targetLayer->AsContainerLayer() && controller) {
targetLayer->AsContainerLayer()->SetAsyncPanZoomController(controller);
controller->NotifyLayersUpdated(targetLayer->AsContainerLayer()->GetFrameMetrics(), isFirstPaint);
}
}
};
CompositorParent*
nsWindow::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight)
{
return new AndroidCompositorParent(this, true, aSurfaceWidth, aSurfaceHeight);
return new CompositorParent(this, true, aSurfaceWidth, aSurfaceHeight);
}
void
nsWindow::SetPanZoomController(AsyncPanZoomController* apzc)
mozilla::layers::APZCTreeManager*
nsWindow::GetAPZCTreeManager()
{
if (sApzc) {
sApzc->SetCompositorParent(nullptr);
sApzc = nullptr;
}
if (apzc) {
sApzc = apzc;
sApzc->SetCompositorParent(sCompositorParent);
if (!sApzcTreeManager) {
CompositorParent* compositor = sCompositorParent;
if (!compositor) {
return nullptr;
}
uint64_t rootLayerTreeId = compositor->RootLayerTreeId();
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, AndroidBridge::Bridge());
sApzcTreeManager = CompositorParent::GetAPZCTreeManager(rootLayerTreeId);
}
return sApzcTreeManager;
}
AsyncPanZoomController*
nsWindow::GetPanZoomController()
uint64_t
nsWindow::RootLayerTreeId()
{
return sApzc;
MOZ_ASSERT(sCompositorParent);
return sCompositorParent->RootLayerTreeId();
}

View File

@ -23,7 +23,7 @@ namespace mozilla {
class CompositorParent;
class CompositorChild;
class LayerManager;
class AsyncPanZoomController;
class APZCTreeManager;
}
}
@ -155,8 +155,9 @@ public:
static void ScheduleResumeComposition(int width, int height);
static void ForceIsFirstPaint();
static float ComputeRenderIntegrity();
static void SetPanZoomController(mozilla::layers::AsyncPanZoomController* apzc);
static mozilla::layers::AsyncPanZoomController* GetPanZoomController();
static mozilla::layers::APZCTreeManager* GetAPZCTreeManager();
/* RootLayerTreeId() can only be called when GetAPZCTreeManager() returns non-null */
static uint64_t RootLayerTreeId();
virtual bool WidgetPaintsBackground();
@ -231,11 +232,11 @@ private:
mozilla::AndroidLayerRendererFrame mLayerRendererFrame;
static nsRefPtr<mozilla::layers::APZCTreeManager> sApzcTreeManager;
static nsRefPtr<mozilla::layers::LayerManager> sLayerManager;
static nsRefPtr<mozilla::layers::CompositorParent> sCompositorParent;
static nsRefPtr<mozilla::layers::CompositorChild> sCompositorChild;
static bool sCompositorPaused;
static nsRefPtr<mozilla::layers::AsyncPanZoomController> sApzc;
};
#endif /* NSWINDOW_H_ */

View File

@ -29,7 +29,6 @@
#include <EGL/egl.h>
#include <hardware/hardware.h>
#include <gui/SurfaceTextureClient.h>
#include <ui/GraphicBuffer.h>
#include "FramebufferSurface.h"

View File

@ -14,7 +14,7 @@
*/
#include "GonkDisplayJB.h"
#include <gui/SurfaceTextureClient.h>
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@ -99,7 +99,7 @@ GonkDisplayJB::GonkDisplayJB()
mAlloc = new GraphicBufferAlloc();
mFBSurface = new FramebufferSurface(0, mWidth, mHeight, surfaceformat, mAlloc);
sp<SurfaceTextureClient> stc = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(mFBSurface->getBufferQueue()));
sp<Surface> stc = new Surface(static_cast<sp<IGraphicBufferProducer> >(mFBSurface->getBufferQueue()));
mSTClient = stc;
mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
@ -166,8 +166,8 @@ GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
StopBootAnimation();
mBootAnimBuffer = nullptr;
mList->dpy = dpy;
mList->sur = sur;
mList->outbuf = nullptr;
mList->outbufAcquireFenceFd = -1;
eglSwapBuffers(dpy, sur);
return Post(mFBSurface->lastHandle, mFBSurface->lastFenceFD);
}
@ -189,8 +189,11 @@ GonkDisplayJB::Post(buffer_handle_t buf, int fence)
mList->flags = HWC_GEOMETRY_CHANGED;
mList->hwLayers[0].compositionType = HWC_BACKGROUND;
mList->hwLayers[0].hints = 0;
mList->hwLayers[0].flags = 0;
/* Skip this layer so the hwc module doesn't complain about null handles */
mList->hwLayers[0].flags = HWC_SKIP_LAYER;
mList->hwLayers[0].backgroundColor = {0};
/* hwc module checks displayFrame even though it shouldn't */
mList->hwLayers[0].displayFrame = r;
mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET;
mList->hwLayers[1].hints = 0;
mList->hwLayers[1].flags = 0;
@ -200,9 +203,10 @@ GonkDisplayJB::Post(buffer_handle_t buf, int fence)
mList->hwLayers[1].sourceCrop = r;
mList->hwLayers[1].displayFrame = r;
mList->hwLayers[1].visibleRegionScreen.numRects = 1;
mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[0].sourceCrop;
mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].sourceCrop;
mList->hwLayers[1].acquireFenceFd = fence;
mList->hwLayers[1].releaseFenceFd = -1;
mList->hwLayers[1].planeAlpha = 0xFF;
mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
mFBSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd);

View File

@ -20,7 +20,7 @@ CPP_SOURCES += [
'BootAnimation.cpp',
]
if CONFIG['ANDROID_VERSION'] == '17':
if CONFIG['ANDROID_VERSION'] == '18':
CPP_SOURCES += [
'FramebufferSurface.cpp',
'GraphicBufferAlloc.cpp',

View File

@ -52,6 +52,7 @@
#include "libui/EventHub.h"
#include "libui/InputReader.h"
#include "libui/InputDispatcher.h"
#include "cutils/properties.h"
#include "GeckoProfiler.h"
@ -78,6 +79,9 @@ bool gDrawRequest = false;
static nsAppShell *gAppShell = NULL;
static int epollfd = 0;
static int signalfds[2] = {0};
static bool sDevInputAudioJack;
static int32_t sHeadphoneState;
static int32_t sMicrophoneState;
NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
@ -245,6 +249,41 @@ maybeSendKeyEvent(int keyCode, bool pressed, uint64_t timeMs)
}
}
class SwitchEventRunnable : public nsRunnable {
public:
SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
{}
NS_IMETHOD Run()
{
hal::NotifySwitchChange(mEvent);
return NS_OK;
}
private:
hal::SwitchEvent mEvent;
};
static void
updateHeadphoneSwitch()
{
hal::SwitchEvent event;
switch (sHeadphoneState) {
case AKEY_STATE_UP:
event.status() = hal::SWITCH_STATE_OFF;
break;
case AKEY_STATE_DOWN:
event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
hal::SWITCH_STATE_HEADPHONE : hal::SWITCH_STATE_HEADSET;
break;
default:
return;
}
event.device() = hal::SWITCH_HEADPHONES;
NS_DispatchToMainThread(new SwitchEventRunnable(event));
}
class GeckoPointerController : public PointerControllerInterface {
float mX;
float mY;
@ -553,6 +592,19 @@ GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
{
if (!sDevInputAudioJack)
return;
switch (args->switchCode) {
case SW_HEADPHONE_INSERT:
sHeadphoneState = args->switchValue;
updateHeadphoneSwitch();
break;
case SW_MICROPHONE_INSERT:
sMicrophoneState = args->switchValue;
updateHeadphoneSwitch();
break;
}
}
void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
@ -661,6 +713,12 @@ nsAppShell::Observe(nsISupports* aSubject,
return nsBaseAppShell::Observe(aSubject, aTopic, aData);
}
if (sDevInputAudioJack) {
sHeadphoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT);
sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT);
updateHeadphoneSwitch();
}
mEnableDraw = true;
NotifyEvent();
return NS_OK;
@ -680,6 +738,12 @@ nsAppShell::Exit()
void
nsAppShell::InitInputDevices()
{
char value[PROPERTY_VALUE_MAX];
property_get("ro.moz.devinputjack", value, "0");
sDevInputAudioJack = !strcmp(value, "1");
sHeadphoneState = AKEY_STATE_UNKNOWN;
sMicrophoneState = AKEY_STATE_UNKNOWN;
mEventHub = new EventHub();
mReaderPolicy = new GeckoInputReaderPolicy();
mReaderPolicy->setDisplayInfo();

View File

@ -140,7 +140,7 @@ namespace {
NS_IMPL_ISUPPORTS_INHERITED0(MetroWidget, nsBaseWidget)
nsRefPtr<mozilla::layers::AsyncPanZoomController> MetroWidget::sAPZC;
nsRefPtr<mozilla::layers::APZCTreeManager> MetroWidget::sAPZC;
MetroWidget::MetroWidget() :
mTransparencyMode(eTransparencyOpaque),
@ -166,7 +166,6 @@ MetroWidget::~MetroWidget()
// Global shutdown
if (!gInstanceCount) {
MetroWidget::sAPZC->Destroy();
MetroWidget::sAPZC = nullptr;
nsTextStore::Terminate();
} // !gInstanceCount
@ -813,22 +812,8 @@ public:
observerService->AddObserver(this, "viewport-needs-updating", false);
}
if (MetroWidget::sAPZC) {
MetroWidget::sAPZC->SetCompositorParent(this);
}
}
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree, const TargetConfig& aTargetConfig,
bool isFirstPaint) MOZ_OVERRIDE
{
CompositorParent::ShadowLayersUpdated(aLayerTree, aTargetConfig, isFirstPaint);
Layer* targetLayer = GetLayerManager()->GetPrimaryScrollableLayer();
if (targetLayer && targetLayer->AsContainerLayer() && MetroWidget::sAPZC &&
targetLayer->AsContainerLayer()->GetFrameMetrics().IsScrollable()) {
targetLayer->AsContainerLayer()->SetAsyncPanZoomController(MetroWidget::sAPZC);
MetroWidget::sAPZC->NotifyLayersUpdated(targetLayer->AsContainerLayer()->GetFrameMetrics(),
isFirstPaint);
}
CompositorParent::SetControllerForLayerTree(RootLayerTreeId(), aMetroWidget);
MetroWidget::sAPZC = CompositorParent::GetAPZCTreeManager(RootLayerTreeId());
}
NS_IMETHODIMP Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
@ -846,7 +831,6 @@ public:
mozilla::gfx::Point(0.0f, 0.0f),
mozilla::gfx::Point(0.0f, 0.0f),
0.0);
MetroWidget::sAPZC->NotifyLayersUpdated(frameMetrics, true);
mMetroWidget->RequestContentRepaint(frameMetrics);
}
}
@ -910,10 +894,6 @@ MetroWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
if (ShouldUseOffMainThreadCompositing()) {
NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
CreateCompositor();
if (ShouldUseAPZC()) {
sAPZC = new AsyncPanZoomController(this, AsyncPanZoomController::USE_GESTURE_DETECTOR);
sAPZC->SetCompositorParent(mCompositorParent);
}
} else if (ShouldUseMainThreadD3D10Manager()) {
nsRefPtr<mozilla::layers::LayerManagerD3D10> layerManager =
new mozilla::layers::LayerManagerD3D10(this);
@ -1457,7 +1437,7 @@ MetroWidget::HandleLongTap(const CSSIntPoint& aPoint)
}
void
MetroWidget::SendAsyncScrollDOMEvent(const CSSRect &aContentRect, const CSSSize &aScrollableSize)
MetroWidget::SendAsyncScrollDOMEvent(FrameMetrics::ViewID aScrollId, const CSSRect &aContentRect, const CSSSize &aScrollableSize)
{
LogFunction();
}

View File

@ -23,7 +23,7 @@
#endif
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/AsyncPanZoomController.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "Units.h"
#include "MetroInput.h"
@ -191,7 +191,7 @@ public:
virtual void HandleDoubleTap(const mozilla::CSSIntPoint& aPoint);
virtual void HandleSingleTap(const mozilla::CSSIntPoint& aPoint);
virtual void HandleLongTap(const mozilla::CSSIntPoint& aPoint);
virtual void SendAsyncScrollDOMEvent(const mozilla::CSSRect &aContentRect, const mozilla::CSSSize &aScrollableSize);
virtual void SendAsyncScrollDOMEvent(mozilla::layers::FrameMetrics::ViewID aScrollId, const mozilla::CSSRect &aContentRect, const mozilla::CSSSize &aScrollableSize);
virtual void PostDelayedTask(Task* aTask, int aDelayMs);
virtual void HandlePanBegin();
virtual void HandlePanEnd();
@ -237,5 +237,5 @@ protected:
mozilla::layers::FrameMetrics mFrameMetrics;
public:
static nsRefPtr<mozilla::layers::AsyncPanZoomController> sAPZC;
static nsRefPtr<mozilla::layers::APZCTreeManager> sAPZC;
};