merge fx-team to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2013-11-26 12:38:36 +01:00
commit 10cb29314e
38 changed files with 928 additions and 639 deletions

View File

@ -779,4 +779,11 @@ const CustomizableWidgets = [{
};
CustomizableUI.addListener(listener);
}
}, {
id: "email-link-button",
removable: true,
onCommand: function(aEvent) {
let win = aEvent.view;
win.MailIntegration.sendLinkForWindow(win.content);
}
}];

View File

@ -15,6 +15,7 @@ const kAboutURI = "about:customizing";
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
const kPlaceholderClass = "panel-customization-placeholder";
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
const kMaxTransitionDurationMs = 2000;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/CustomizableUI.jsm");
@ -322,9 +323,11 @@ CustomizeMode.prototype = {
let deck = this.document.getElementById("tab-view-deck");
let customizeTransitionEnd = function(aEvent) {
if (aEvent.originalTarget != deck || aEvent.propertyName != "padding-bottom") {
if (aEvent != "timedout" &&
(aEvent.originalTarget != deck || aEvent.propertyName != "padding-bottom")) {
return;
}
this.window.clearTimeout(catchAllTimeout);
deck.removeEventListener("transitionend", customizeTransitionEnd);
if (!aEntering) {
@ -350,6 +353,9 @@ CustomizeMode.prototype = {
this.document.documentElement.setAttribute("customize-exiting", true);
this.document.documentElement.removeAttribute("customize-entered");
}
let catchAll = () => customizeTransitionEnd("timedout");
let catchAllTimeout = this.window.setTimeout(catchAll, kMaxTransitionDurationMs);
return deferred.promise;
},
@ -359,7 +365,17 @@ CustomizeMode.prototype = {
let result = this.window.gNavToolbox.dispatchEvent(evt);
},
_getCustomizableChildForNode: function(aNode) {
let area = this._getCustomizableParent(aNode);
area = area.customizationTarget || area;
while (aNode && aNode.parentNode != area) {
aNode = aNode.parentNode;
}
return aNode;
},
addToToolbar: function(aNode) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
aNode = aNode.firstChild;
}
@ -367,6 +383,7 @@ CustomizeMode.prototype = {
},
addToPanel: function(aNode) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
aNode = aNode.firstChild;
}
@ -374,6 +391,7 @@ CustomizeMode.prototype = {
},
removeFromArea: function(aNode) {
aNode = this._getCustomizableChildForNode(aNode);
if (aNode.localName == "toolbarpaletteitem" && aNode.firstChild) {
aNode = aNode.firstChild;
}
@ -539,7 +557,13 @@ CustomizeMode.prototype = {
deferredUnwrapToolbarItem: function(aWrapper) {
let deferred = Promise.defer();
dispatchFunction(function() {
deferred.resolve(this.unwrapToolbarItem(aWrapper));
let item = null;
try {
item = this.unwrapToolbarItem(aWrapper);
} catch (ex) {
Cu.reportError(ex);
}
deferred.resolve(item);
}.bind(this));
return deferred.promise;
},

View File

@ -71,6 +71,32 @@ let gTests = [
},
teardown: null
},
{
desc: "Right-click on the searchbar and moving it to the menu and back should move the search-container instead.",
run: function() {
let searchbar = document.getElementById("searchbar");
gCustomizeMode.addToPanel(searchbar);
let placement = CustomizableUI.getPlacementOfWidget("search-container");
is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
let shownPanelPromise = promisePanelShown(window);
PanelUI.toggle({type: "command"});
yield shownPanelPromise;
let hiddenPanelPromise = promisePanelHidden(window);
PanelUI.toggle({type: "command"});
yield hiddenPanelPromise;
gCustomizeMode.addToToolbar(searchbar);
placement = CustomizableUI.getPlacementOfWidget("search-container");
is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in navbar");
gCustomizeMode.removeFromArea(searchbar);
placement = CustomizableUI.getPlacementOfWidget("search-container");
is(placement, null, "Should be in palette");
CustomizableUI.reset();
placement = CustomizableUI.getPlacementOfWidget("search-container");
is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in navbar");
}
},
{
desc: "Right-click on an item within the menu panel should show a context menu with options to move it.",
setup: null,

View File

@ -39,6 +39,14 @@
background: rgba(255,0,0,0.2);
}
.CodeMirror {
cursor: text;
}
.CodeMirror-gutters {
cursor: default;
}
/* This is to avoid the fake horizontal scrollbar div of codemirror to go 0
height when floating scrollbars are active. Make sure that this value is equal
to the maximum of `min-height` specific to the `scrollbar[orient="horizontal"]`

View File

@ -122,20 +122,23 @@ function Editor(config) {
this.version = null;
this.config = {
value: "",
mode: Editor.modes.text,
indentUnit: tabSize,
tabSize: tabSize,
contextMenu: null,
matchBrackets: true,
extraKeys: {},
indentWithTabs: useTabs,
styleActiveLine: true,
theme: "mozilla"
value: "",
mode: Editor.modes.text,
indentUnit: tabSize,
tabSize: tabSize,
contextMenu: null,
matchBrackets: true,
extraKeys: {},
indentWithTabs: useTabs,
styleActiveLine: true,
autoCloseBrackets: true,
theme: "mozilla"
};
// Additional shortcuts.
this.config.extraKeys[Editor.keyFor("jumpToLine")] = (cm) => this.jumpToLine(cm);
this.config.extraKeys[Editor.keyFor("moveLineUp")] = (cm) => this.moveLineUp();
this.config.extraKeys[Editor.keyFor("moveLineDown")] = (cm) => this.moveLineDown();
this.config.extraKeys[Editor.keyFor("toggleComment")] = "toggleComment";
// Disable ctrl-[ and ctrl-] because toolbox uses those shortcuts.
@ -636,6 +639,65 @@ Editor.prototype = {
this.openDialog(div, (line) => this.setCursor({ line: line - 1, ch: 0 }));
},
/**
* Moves the content of the current line or the lines selected up a line.
*/
moveLineUp: function () {
let cm = editors.get(this);
let start = cm.getCursor("start");
let end = cm.getCursor("end");
if (start.line === 0)
return;
// Get the text in the lines selected or the current line of the cursor
// and append the text of the previous line.
let value;
if (start.line !== end.line) {
value = cm.getRange({ line: start.line, ch: 0 },
{ line: end.line, ch: cm.getLine(end.line).length }) + "\n";
} else {
value = cm.getLine(start.line) + "\n";
}
value += cm.getLine(start.line - 1);
// Replace the previous line and the currently selected lines with the new
// value and maintain the selection of the text.
cm.replaceRange(value, { line: start.line - 1, ch: 0 },
{ line: end.line, ch: cm.getLine(end.line).length });
cm.setSelection({ line: start.line - 1, ch: start.ch },
{ line: end.line - 1, ch: end.ch });
},
/**
* Moves the content of the current line or the lines selected down a line.
*/
moveLineDown: function () {
let cm = editors.get(this);
let start = cm.getCursor("start");
let end = cm.getCursor("end");
if (end.line + 1 === cm.lineCount())
return;
// Get the text of next line and append the text in the lines selected
// or the current line of the cursor.
let value = cm.getLine(end.line + 1) + "\n";
if (start.line !== end.line) {
value += cm.getRange({ line: start.line, ch: 0 },
{ line: end.line, ch: cm.getLine(end.line).length });
} else {
value += cm.getLine(start.line);
}
// Replace the currently selected lines and the next line with the new
// value and maintain the selection of the text.
cm.replaceRange(value, { line: start.line, ch: 0 },
{ line: end.line + 1, ch: cm.getLine(end.line + 1).length});
cm.setSelection({ line: start.line + 1, ch: start.ch },
{ line: end.line + 1, ch: end.ch });
},
/**
* Extends an instance of the Editor object with additional
* functions. Each function will be called with context as

View File

@ -13,5 +13,6 @@ support-files =
[browser_editor_cursor.js]
[browser_editor_history.js]
[browser_editor_markers.js]
[browser_editor_movelines.js]
[browser_codemirror.js]
[browser_sourceeditor_initialization.js]

View File

@ -0,0 +1,62 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function test() {
waitForExplicitFinish();
setup((ed, win) => {
var simpleProg = "function foo() {\n let i = 1;\n let j = 2;\n return bar;\n}";
ed.setText(simpleProg);
// Move first line up
ed.setCursor({ line: 0, ch: 0 });
ed.moveLineUp();
is(ed.getText(0), "function foo() {", "getText(num)");
ch(ed.getCursor(), { line: 0, ch: 0 }, "getCursor");
// Move last line down
ed.setCursor({ line: 4, ch: 0 });
ed.moveLineDown();
is(ed.getText(4), "}", "getText(num)");
ch(ed.getCursor(), { line: 4, ch: 0 }, "getCursor");
// Move line 2 up
ed.setCursor({ line: 1, ch: 5});
ed.moveLineUp();
is(ed.getText(0), " let i = 1;", "getText(num)");
is(ed.getText(1), "function foo() {", "getText(num)");
ch(ed.getCursor(), { line: 0, ch: 5 }, "getCursor");
// Undo previous move by moving line 1 down
ed.moveLineDown();
is(ed.getText(0), "function foo() {", "getText(num)");
is(ed.getText(1), " let i = 1;", "getText(num)");
ch(ed.getCursor(), { line: 1, ch: 5 }, "getCursor");
// Move line 2 and 3 up
ed.setSelection({ line: 1, ch: 0 }, { line: 2, ch: 0 });
ed.moveLineUp();
is(ed.getText(0), " let i = 1;", "getText(num)");
is(ed.getText(1), " let j = 2;", "getText(num)");
is(ed.getText(2), "function foo() {", "getText(num)");
ch(ed.getCursor("start"), { line: 0, ch: 0 }, "getCursor(string)");
ch(ed.getCursor("end"), { line: 1, ch: 0 }, "getCursor(string)");
// Move line 1 to 3 down twice
ed.dropSelection();
ed.setSelection({ line: 0, ch: 7 }, { line: 2, ch: 5 });
ed.moveLineDown();
ed.moveLineDown();
is(ed.getText(0), " return bar;", "getText(num)");
is(ed.getText(1), "}", "getText(num)");
is(ed.getText(2), " let i = 1;", "getText(num)");
is(ed.getText(3), " let j = 2;", "getText(num)");
is(ed.getText(4), "function foo() {", "getText(num)");
ch(ed.getCursor("start"), { line: 2, ch: 7 }, "getCursor(string)");
ch(ed.getCursor("end"), { line: 4, ch: 5 }, "getCursor(string)");
teardown(ed, win);
});
}

View File

@ -74,3 +74,6 @@ feed-button.tooltiptext = Subscribe to this page…
characterencoding-button.label = Character Encoding
characterencoding-button.tooltiptext = Character encoding
email-link-button.label = Email Link
email-link-button.tooltiptext = Email Link

View File

@ -73,4 +73,14 @@ indentLess.commandkey=[
# the Toolbox to switch between tools
#
# DO NOT translate this key without proper synchronization with toolbox.dtd.
indentMore.commandkey=]
indentMore.commandkey=]
# LOCALIZATION NOTE (moveLineUp.commandkey): This the key to use in
# conjunction with accel (Command on Mac or Ctrl on other platforms) to move
# the selected lines up.
moveLineUp.commandkey=Alt-Up
# LOCALIZATION NOTE (moveLineDown.commandkey): This the key to use in
# conjunction with accel (Command on Mac or Ctrl on other platforms) to move
# the selected lines down.
moveLineDown.commandkey=Alt-Down

View File

@ -15,7 +15,7 @@
<content>
<xul:stack>
<xul:toolbarbutton anonid="progressButton" class="circularprogressindicator-progressButton appbar-secondary"/>
<xul:toolbarbutton anonid="progressButton" class="circularprogressindicator-progressButton"/>
<html:div anonid="progressTrack" xbl:inherits="progress" class="circularprogressindicator-progressTrack"></html:div>
<html:canvas anonid="progressRing" xbl:inherits="progress" class="circularprogressindicator-progressRing" width="40" height="40"></html:canvas>
</xul:stack>

View File

@ -432,7 +432,7 @@ let Content = {
aRect.height,
presShellId.value,
viewId].join(",");
Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
Services.obs.notifyObservers(null, "apzc-zoom-to-rect", zoomData);
},
_shouldZoomToElement: function(aElement) {

View File

@ -35,6 +35,9 @@ var StartUI = {
this.chromeWin.addEventListener("MozPrecisePointer", this, true);
this.chromeWin.addEventListener("MozImprecisePointer", this, true);
this.chromeWin.addEventListener("MozAfterPaint", this, true);
this.chromeWin.Elements.panelUI.addEventListener("ToolPanelHidden", this, false);
Services.obs.addObserver(this, "metro_viewstate_changed", false);
},
@ -107,6 +110,15 @@ var StartUI = {
aEvent.preventDefault();
aEvent.stopPropagation();
break;
case "ToolPanelHidden":
// After opening panel UI (console) set disableZoom again.
this.chromeWin.addEventListener("MozAfterPaint", this, true);
break;
case "MozAfterPaint":
this._disableZoom();
this.chromeWin.removeEventListener("MozAfterPaint", this, true);
break;
}
},
@ -116,5 +128,24 @@ var StartUI = {
this._adjustDOMforViewState(aData);
break;
}
},
_disableZoom: function() {
let utils = Util.getWindowUtils(window);
let viewId;
try {
viewId = utils.getViewId(document.documentElement);
} catch(e) {
return;
}
let presShellId = {};
utils.getPresShellId(presShellId);
let notificationData = [
presShellId.value,
viewId].join(",");
Services.obs.notifyObservers(null, "apzc-disable-zoom", notificationData);
}
};

View File

@ -746,13 +746,16 @@ documenttab[selected] .documenttab-selection {
}
#download-progress {
-moz-image-region: rect(0px, 40px, 40px, 0px) !important;
width: 40px;
height: 40px;
list-style-image: url(chrome://browser/skin/images/navbar-download.png);
-moz-image-region: rect(0px, 40px, 40px, 0px);
}
#download-progress:hover {
-moz-image-region: rect(40px, 40px, 80px, 0px) !important;
-moz-image-region: rect(0px, 80px, 40px, 40px);
}
#download-progress:active {
-moz-image-region: rect(80px, 40px, 120px, 0px) !important;
-moz-image-region: rect(0px, 120px, 40px, 80px);
}
#pin-button {
@ -768,6 +771,10 @@ documenttab[selected] .documenttab-selection {
}
@media (min-resolution: @min_res_140pc@) {
#download-progress {
list-style-image: url(chrome://browser/skin/images/navbar-download@1.4x.png);
}
#pin-button {
list-style-image: url(chrome://browser/skin/images/navbar-pin@1.4x.png);
}
@ -782,6 +789,10 @@ documenttab[selected] .documenttab-selection {
}
@media (min-resolution: @min_res_180pc@) {
#download-progress {
list-style-image: url(chrome://browser/skin/images/navbar-download@1.8x.png);
}
#pin-button {
list-style-image: url(chrome://browser/skin/images/navbar-pin@1.8x.png);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -27,6 +27,9 @@ chrome.jar:
skin/images/navbar-back.png (images/navbar-back.png)
skin/images/navbar-back@1.4x.png (images/navbar-back@1.4x.png)
skin/images/navbar-back@1.8x.png (images/navbar-back@1.8x.png)
skin/images/navbar-download.png (images/navbar-download.png)
skin/images/navbar-download@1.4x.png (images/navbar-download@1.4x.png)
skin/images/navbar-download@1.8x.png (images/navbar-download@1.8x.png)
skin/images/navbar-forward.png (images/navbar-forward.png)
skin/images/navbar-forward@1.4x.png (images/navbar-forward@1.4x.png)
skin/images/navbar-forward@1.8x.png (images/navbar-forward@1.8x.png)

View File

@ -588,6 +588,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(36px, 612px, 54px, 594px);
}
#email-link-button@toolbarButtonPressed@ {
-moz-image-region: rect(18px, 306px, 36px, 288px);
}
/**
* OSX has a unique set of icons when fullscreen is in the checked state.
*/
@ -737,6 +741,14 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(36px, 612px, 72px, 576px);
}
#email-link-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 612px, 36px, 576px);
}
#email-link-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
-moz-image-region: rect(36px, 612px, 72px, 576px);
}
#characterencoding-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 648px, 36px, 612px);
}
@ -1009,6 +1021,16 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
-moz-image-region: rect(0px, 1536px, 64px, 1472px);
}
#email-link-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #email-link-button {
-moz-image-region: rect(0px, 896px, 64px, 832px);
}
/* This is temporary until we have an email-link icon (Bug 932235) */
#email-link-button > image {
transform: scale(-1, -1);
}
/* Footer and wide panel control icons */
#edit-controls@inAnyPanel@ > toolbarbutton,
#zoom-controls@inAnyPanel@ > toolbarbutton,

View File

@ -1,4 +1,4 @@
%filter substitution
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]),.overflowedItem)

View File

@ -60,6 +60,17 @@ toolbarpaletteitem[place="palette"] > #social-share-button {
-moz-image-region: rect(0px, 448px, 32px, 416px);
}
#email-link-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #email-link-button {
-moz-image-region: rect(0, 448px, 32px, 416px);
}
/* This is temporary until we have an email-link icon (Bug 932235) */
#email-link-button[cui-areatype="menu-panel"] > image,
toolbarpaletteitem[place="palette"] > #email-link-button > image {
transform: scale(-1, -1);
}
#characterencoding-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #characterencoding-button {
-moz-image-region: rect(0px, 480px, 32px, 448px);

View File

@ -69,6 +69,12 @@
-moz-image-region: rect(0px, 306px, 18px, 288px);
}
#email-link-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 306px, 18px, 288px);
/* This is temporary until we have an email-link icon (Bug 932235) */
transform: scale(-1, -1);
}
#characterencoding-button[cui-areatype="toolbar"]{
-moz-image-region: rect(0, 324px, 18px, 306px);
}

View File

@ -95,6 +95,11 @@ public class GeckoNetworkManager extends BroadcastReceiver {
NETWORK_UNKNOWN
}
private enum InfoType {
MCC,
MNC
}
private Context mApplicationContext;
private NetworkType mNetworkType = NetworkType.NETWORK_NONE;
private IntentFilter mNetworkFilter = new IntentFilter();
@ -322,4 +327,32 @@ public class GeckoNetworkManager extends BroadcastReceiver {
return false;
}
}
private static int getNetworkOperator(InfoType type) {
TelephonyManager tel = (TelephonyManager)sInstance.mApplicationContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tel == null) {
Log.e(LOGTAG, "Telephony service does not exist");
return -1;
}
String networkOperator = tel.getNetworkOperator();
if (networkOperator == null || networkOperator.length() <= 3) {
return -1;
}
if (type == InfoType.MNC) {
return Integer.parseInt(networkOperator.substring(3));
} else if (type == InfoType.MCC) {
return Integer.parseInt(networkOperator.substring(0, 3));
}
return -1;
}
public static int getMCC() {
return getNetworkOperator(InfoType.MCC);
}
public static int getMNC() {
return getNetworkOperator(InfoType.MNC);
}
}

View File

@ -58,6 +58,7 @@ skip-if = processor == "x86"
[testSessionOOMSave]
[testSessionOOMRestore]
[testSettingsMenuItems]
[testMozPay]
[testSharedPreferences]
# [testShareLink] # see bug 915897
[testSystemPages]

View File

@ -0,0 +1,25 @@
<html>
<head>
<script type="text/javascript">
function start() {
if (!mozPaymentProvider)
window.close();
// We don't have a way to mock these values yet. This check just makes sure the world
// doesn't crash if we ask for them.
var mcc = mozPaymentProvider.mcc;
var mnc = mozPaymentProvider.mnc;
// We use the jwt passed in here to test calling paymentFailed/Success
if (window.location.hash == "#pass")
mozPaymentProvider.paymentSuccess("PAID CORRECTLY");
else if (window.location.hash == "#fail")
mozPaymentProvider.paymentFailed("FAILED CORRECTLY");
else
mozPaymentProvider.paymentFailed("invalid hash " + window.location.hash);
}
document.addEventListener("DOMContentLoaded", start);
</script>
</head>
</html>

View File

@ -0,0 +1,10 @@
package org.mozilla.gecko.tests;
import org.mozilla.gecko.*;
public class testMozPay extends JavascriptTest {
public testMozPay() {
super("testMozPay.js");
}
}

View File

@ -0,0 +1,102 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* 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/. */
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Components.utils.import("resource://gre/modules/SharedPreferences.jsm");
Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js");
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
let deferred = 0;
let shouldPass = true;
let reqId = 0;
function getRequestId(increment) {
reqId += increment;
return "Request" + reqId;
}
let paymentSuccess = {
receiveMessage: function(aMsg) {
let msg = aMsg.json;
if (shouldPass) {
do_check_eq(msg.requestId, getRequestId(0));
} else {
do_throw("Test should not have passed");
}
deferred.resolve();
}
}
let paymentFailed = {
receiveMessage: function(aMsg) {
let msg = aMsg.json;
if (shouldPass) {
do_throw("Test should not have failed: " + msg.errorMsg);
} else {
do_check_eq(msg.requestId, getRequestId(0));
do_check_eq(msg.errorMsg, "FAILED CORRECTLY");
}
deferred.resolve();
}
}
add_task(function test_get_set() {
let ui = Cc["@mozilla.org/payment/ui-glue;1"].getService(Ci.nsIPaymentUIGlue);
deferred = Promise.defer();
let id = getRequestId(1);
ui.confirmPaymentRequest(id,
[{ wrappedJSObject: { type: "Fake Provider" } }],
function(aRequestId, type) {
do_check_eq(type, "Fake Provider");
deferred.resolve();
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
});
add_task(function test_default() {
ppmm.addMessageListener("Payment:Success", paymentSuccess);
ppmm.addMessageListener("Payment:Failed", paymentFailed);
let ui = Cc["@mozilla.org/payment/ui-glue;1"].getService(Ci.nsIPaymentUIGlue);
deferred = Promise.defer();
let id = getRequestId(1);
shouldPass = true;
ui.showPaymentFlow(id,
{
uri: "chrome://roboextender/content/paymentsUI.html",
jwt: "#pass"
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
deferred = Promise.defer();
let id = getRequestId(1);
shouldPass = false;
ui.showPaymentFlow(id,
{
uri: "chrome://roboextender/content/paymentsUI.html",
jwt: "#fail"
},
function(id, msg) {
do_throw("confirmPaymentRequest should not have failed");
deferred.resolve();
});
yield deferred.promise;
ppmm.removeMessageListener("Payment:Success", paymentSuccess);
ppmm.removeMessageListener("Payment:Failed", paymentFailed);
});
run_next_test();

View File

@ -961,7 +961,12 @@ public class ActivityChooserModel extends DataSetObservable {
for (int i = 0; i < activityCount; i++) {
ActivityResolveInfo activity = activities.get(i);
activity.weight = 0.0f;
String packageName = activity.resolveInfo.activityInfo.packageName;
// Make sure we're using a non-ambiguous name here
ComponentName chosenName = new ComponentName(
activity.resolveInfo.activityInfo.packageName,
activity.resolveInfo.activityInfo.name);
String packageName = chosenName.flattenToString();
packageNameToActivityMap.put(packageName, activity);
}
@ -969,7 +974,7 @@ public class ActivityChooserModel extends DataSetObservable {
float nextRecordWeight = 1;
for (int i = lastShareIndex; i >= 0; i--) {
HistoricalRecord historicalRecord = historicalRecords.get(i);
String packageName = historicalRecord.activity.getPackageName();
String packageName = historicalRecord.activity.flattenToString();
ActivityResolveInfo activity = packageNameToActivityMap.get(packageName);
if (activity != null) {
activity.weight += historicalRecord.weight * nextRecordWeight;

View File

@ -8,6 +8,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/JNI.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
@ -32,9 +33,17 @@ function paymentFailed(aRequestId) {
}
let paymentTabs = {};
let cancelTabCallbacks = {};
function paymentCanceled(aRequestId) {
return function() {
paymentFailed(aRequestId)();
}
}
function closePaymentTab(aId, aCallback) {
if (paymentTabs[aId]) {
paymentTabs[aId].browser.removeEventListener("TabClose", cancelTabCallbacks[aId]);
delete cancelTabCallbacks[aId];
// We ask the UI to close the selected payment flow.
let content = Services.wm.getMostRecentWindow("navigator:browser");
if (content) {
@ -127,8 +136,39 @@ PaymentUI.prototype = {
tab.browser.addEventListener("DOMContentLoaded", function loadPaymentShim() {
let frame = tab.browser.contentDocument.defaultView;
try {
frame.wrappedJSObject.paymentSuccess = paymentSuccess(aRequestId);
frame.wrappedJSObject.paymentFailed = paymentFailed(aRequestId);
frame.wrappedJSObject.mozPaymentProvider = {
__exposedProps__: {
paymentSuccess: 'r',
paymentFailed: 'r',
mnc: 'r',
mcc: 'r',
},
_getNetworkInfo: function(type) {
let jni = new JNI();
let cls = jni.findClass("org/mozilla/gecko/GeckoNetworkManager");
let method = jni.getStaticMethodID(cls, "get" + type.toUpperCase(), "()I");
let val = jni.callStaticIntMethod(cls, method);
jni.close();
if (val < 0)
return null;
return val;
},
get mnc() {
delete this.mnc;
return this.mnc = this._getNetworkInfo("mnc");
},
get mcc() {
delete this.mcc;
return this.mcc = this._getNetworkInfo("mcc");
},
paymentSuccess: paymentSuccess(aRequestId),
paymentFailed: paymentFailed(aRequestId)
};
} catch (e) {
_error(aRequestId, "ERROR_ADDING_METHODS");
} finally {
@ -136,13 +176,12 @@ PaymentUI.prototype = {
}
}, true);
// fail the payment if the tab is closed on its own
tab.browser.addEventListener("TabClose", function paymentCanceled() {
paymentFailed(aRequestId)();
});
// Store a reference to the tab so that we can close it when the payment succeeds or fails.
paymentTabs[aRequestId] = tab;
cancelTabCallbacks[aRequestId] = paymentCanceled(aRequestId);
// Fail the payment if the tab is closed on its own
tab.browser.addEventListener("TabClose", cancelTabCallbacks[aRequestId]);
},
cleanup: function cleanup() {

View File

@ -160,9 +160,7 @@ function eventSource(aProto) {
listener.apply(null, arguments);
} catch (e) {
// Prevent a bad listener from interfering with the others.
let msg = e + ": " + e.stack;
Cu.reportError(msg);
dumpn(msg);
DevToolsUtils.reportException("notify event '" + name + "'", e);
}
}
}
@ -322,10 +320,7 @@ DebuggerClient.requester = function DC_requester(aPacketSkeleton, { telemetry,
try {
thisCallback(aResponse);
} catch (e) {
let msg = "Error executing callback passed to debugger client: "
+ e + "\n" + e.stack;
dumpn(msg);
Cu.reportError(msg);
DevToolsUtils.reportException("DebuggerClient.requester callback", e);
}
}
@ -650,10 +645,10 @@ DebuggerClient.prototype = {
resolve(packet).then(aPacket => {
if (!aPacket.from) {
let msg = "Server did not specify an actor, dropping packet: " +
JSON.stringify(aPacket);
Cu.reportError(msg);
dumpn(msg);
DevToolsUtils.reportException(
"onPacket",
new Error("Server did not specify an actor, dropping packet: " +
JSON.stringify(aPacket)));
return;
}
@ -703,8 +698,7 @@ DebuggerClient.prototype = {
this._sendRequests();
}, function (ex) {
dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack);
Cu.reportError(ex.message + "\n" + ex.stack);
DevToolsUtils.reportException("onPacket handler", ex);
});
},
@ -830,14 +824,13 @@ ProtocolCompatibility.prototype = {
this.rejectFeature(feature.name);
break;
default:
Cu.reportError(new Error(
"Bad return value from `onPacketTest` for feature '"
+ feature.name + "'"));
DevToolsUtils.reportException(
"PC__detectFeatures",
new Error("Bad return value from `onPacketTest` for feature '"
+ feature.name + "'"));
}
} catch (ex) {
Cu.reportError("Error detecting support for feature '"
+ feature.name + "':" + ex.message + "\n"
+ ex.stack);
DevToolsUtils.reportException("PC__detectFeatures", ex);
}
}
},
@ -1700,11 +1693,6 @@ function TraceClient(aClient, aActor) {
this._activeTraces = new Set();
this._waitingPackets = new Map();
this._expectedPacket = 0;
this.onPacket = this.onPacket.bind(this);
this._client.addListener(UnsolicitedNotifications.enteredFrame, this.onPacket);
this._client.addListener(UnsolicitedNotifications.exitedFrame, this.onPacket);
this.request = this._client.request;
}
@ -1777,32 +1765,9 @@ TraceClient.prototype = {
return aResponse;
},
telemetry: "STOPTRACE"
}),
/**
* Called when the trace actor notifies that a frame has been
* entered or exited.
*
* @param aEvent string
* The type of the unsolicited packet (enteredFrame|exitedFrame).
*
* @param aPacket object
* Packet received over the RDP from the trace actor.
*/
onPacket: function JSTC_onPacket(aEvent, aPacket) {
this._waitingPackets.set(aPacket.sequence, aPacket);
while (this._waitingPackets.has(this._expectedPacket)) {
let packet = this._waitingPackets.get(this._expectedPacket);
this._waitingPackets.delete(this._expectedPacket);
this.notify(packet.type, packet);
this._expectedPacket++;
}
}
})
};
eventSource(TraceClient.prototype);
/**
* Grip clients are used to retrieve information about the relevant object.
*
@ -2224,9 +2189,7 @@ this.debuggerSocketConnect = function debuggerSocketConnect(aHost, aPort)
transport = new DebuggerTransport(s.openInputStream(0, 0, 0),
s.openOutputStream(0, 0, 0));
} catch(e) {
let msg = e + ": " + e.stack;
Cu.reportError(msg);
dumpn(msg);
DevToolsUtils.reportException("debuggerSocketConnect", e);
throw e;
}
return transport;

View File

@ -14,6 +14,39 @@ const { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
const { setTimeout } = require("sdk/timers");
/**
* The number of milliseconds we should buffer frame enter/exit packets before
* sending.
*/
const BUFFER_SEND_DELAY = 50;
/**
* The maximum number of arguments we will send for any single function call.
*/
const MAX_ARGUMENTS = 5;
/**
* The maximum number of an object's properties we will serialize.
*/
const MAX_PROPERTIES = 5;
/**
* The complete set of trace types supported.
*/
const TRACE_TYPES = new Set([
"time",
"return",
"throw",
"yield",
"name",
"location",
"callsite",
"parameterNames",
"arguments"
]);
/**
* Creates a TraceActor. TraceActor provides a stream of function
* call/return packets to a remote client gathering a full trace.
@ -24,11 +57,18 @@ function TraceActor(aConn, aParentActor)
this._activeTraces = new MapStack();
this._totalTraces = 0;
this._startTime = 0;
// Keep track of how many different trace requests have requested what kind of
// tracing info. This way we can minimize the amount of data we are collecting
// at any given time.
this._requestsForTraceType = Object.create(null);
for (let type of TraceTypes.types) {
for (let type of TRACE_TYPES) {
this._requestsForTraceType[type] = 0;
}
this._sequence = 0;
this._bufferSendTimer = null;
this._buffer = [];
this.global = aParentActor.window.wrappedJSObject;
}
@ -41,24 +81,19 @@ TraceActor.prototype = {
get tracing() { return this._attached && this._activeTraces.size > 0; },
/**
* Handle a TraceTypes.Events event by calling each handler which has been
* requested by an active trace and adding its result to the packet.
*
* @param aEvent string
* The event to dispatch.
*
* @param aPacket object
* The debugger protocol packet.
*
* @param aArgs object
* The arguments object for the handler.
* Buffer traces and only send them every BUFFER_SEND_DELAY milliseconds.
*/
_handleEvent: function(aEvent, aPacket, aArgs) {
let handlersForEvent = TraceTypes.handlers[aEvent];
for (let traceType in handlersForEvent) {
if (this._requestsForTraceType[traceType]) {
aPacket[traceType] = handlersForEvent[traceType].call(null, aArgs);
}
_send: function(aPacket) {
this._buffer.push(aPacket);
if (this._bufferSendTimer === null) {
this._bufferSendTimer = setTimeout(() => {
this.conn.send({
from: this.actorID,
type: "traces",
traces: this._buffer.splice(0, this._buffer.length)
});
this._bufferSendTimer = null;
}, BUFFER_SEND_DELAY);
}
},
@ -151,7 +186,11 @@ TraceActor.prototype = {
this._attached = true;
return { type: "attached", traceTypes: TraceTypes.types };
return {
type: "attached",
traceTypes: Object.keys(this._requestsForTraceType)
.filter(k => !!this._requestsForTraceType[k])
};
},
/**
@ -168,7 +207,7 @@ TraceActor.prototype = {
this.dbg = null;
this._attached = false;
this.conn.send({ from: this.actorID, type: "detached" });
return { type: "detached" };
},
/**
@ -179,7 +218,7 @@ TraceActor.prototype = {
*/
onStartTrace: function(aRequest) {
for (let traceType of aRequest.trace) {
if (TraceTypes.types.indexOf(traceType) < 0) {
if (!TRACE_TYPES.has(traceType)) {
return {
error: "badParameterType",
message: "No such trace type: " + traceType
@ -190,7 +229,7 @@ TraceActor.prototype = {
if (this.idle) {
this.dbg.enabled = true;
this._sequence = 0;
this._startTime = +new Date;
this._startTime = Date.now();
}
// Start recording all requested trace types.
@ -257,19 +296,61 @@ TraceActor.prototype = {
onEnterFrame: function(aFrame) {
let callee = aFrame.callee;
let packet = {
from: this.actorID,
type: "enteredFrame",
sequence: this._sequence++
};
this._handleEvent(TraceTypes.Events.enterFrame, packet, {
frame: aFrame,
startTime: this._startTime
});
if (this._requestsForTraceType.name) {
packet.name = aFrame.callee
? aFrame.callee.displayName || "(anonymous function)"
: "(" + aFrame.type + ")";
}
if (this._requestsForTraceType.location && aFrame.script) {
// We should return the location of the start of the script, but
// Debugger.Script does not provide complete start locations (bug
// 901138). Instead, return the current offset (the location of the first
// statement in the function).
packet.location = {
url: aFrame.script.url,
line: aFrame.script.getOffsetLine(aFrame.offset),
column: getOffsetColumn(aFrame.offset, aFrame.script)
};
}
if (this._requestsForTraceType.callsite
&& aFrame.older
&& aFrame.older.script) {
let older = aFrame.older;
packet.callsite = {
url: older.script.url,
line: older.script.getOffsetLine(older.offset),
column: getOffsetColumn(older.offset, older.script)
};
}
if (this._requestsForTraceType.time) {
packet.time = Date.now() - this._startTime;
}
if (this._requestsForTraceType.parameterNames && aFrame.callee) {
packet.parameterNames = aFrame.callee.parameterNames;
}
if (this._requestsForTraceType.arguments && aFrame.arguments) {
packet.arguments = [];
let i = 0;
for (let arg of aFrame.arguments) {
if (i++ > MAX_ARGUMENTS) {
break;
}
packet.arguments.push(createValueGrip(arg, true));
}
}
aFrame.onPop = this.onExitFrame.bind(this);
this.conn.send(packet);
this._send(packet);
},
/**
@ -281,7 +362,6 @@ TraceActor.prototype = {
*/
onExitFrame: function(aCompletion) {
let packet = {
from: this.actorID,
type: "exitedFrame",
sequence: this._sequence++,
};
@ -296,12 +376,25 @@ TraceActor.prototype = {
packet.why = "throw";
}
this._handleEvent(TraceTypes.Events.exitFrame, packet, {
value: aCompletion,
startTime: this._startTime
});
if (this._requestsForTraceType.time) {
packet.time = Date.now() - this._startTime;
}
this.conn.send(packet);
if (aCompletion) {
if (this._requestsForTraceType.return) {
packet.return = createValueGrip(aCompletion.return, true);
}
if (this._requestsForTraceType.throw) {
packet.throw = createValueGrip(aCompletion.throw, true);
}
if (this._requestsForTraceType.yield) {
packet.yield = createValueGrip(aCompletion.yield, true);
}
}
this._send(packet);
}
};
@ -419,91 +512,6 @@ MapStack.prototype = {
}
};
/**
* TraceTypes is a collection of handlers which generate optional trace
* information. Handlers are associated with an event (from TraceTypes.Event)
* and a trace type, and return a value to be embedded in the packet associated
* with that event.
*/
let TraceTypes = {
handlers: {},
types: [],
register: function(aType, aEvent, aHandler) {
if (!this.handlers[aEvent]) {
this.handlers[aEvent] = {};
}
this.handlers[aEvent][aType] = aHandler;
if (this.types.indexOf(aType) < 0) {
this.types.push(aType);
}
}
};
TraceTypes.Events = {
"enterFrame": "enterFrame",
"exitFrame": "exitFrame"
};
TraceTypes.register("name", TraceTypes.Events.enterFrame, function({ frame }) {
return frame.callee
? frame.callee.displayName || "(anonymous function)"
: "(" + frame.type + ")";
});
TraceTypes.register("location", TraceTypes.Events.enterFrame, function({ frame }) {
if (!frame.script) {
return undefined;
}
// We should return the location of the start of the script, but
// Debugger.Script does not provide complete start locations
// (bug 901138). Instead, return the current offset (the location of
// the first statement in the function).
return {
url: frame.script.url,
line: frame.script.getOffsetLine(frame.offset),
column: getOffsetColumn(frame.offset, frame.script)
};
});
TraceTypes.register("callsite", TraceTypes.Events.enterFrame, function({ frame }) {
let older = frame.older;
if (!older || !older.script) {
return undefined;
}
return {
url: older.script.url,
line: older.script.getOffsetLine(older.offset),
column: getOffsetColumn(older.offset, older.script)
};
});
TraceTypes.register("time", TraceTypes.Events.enterFrame, timeSinceTraceStarted);
TraceTypes.register("time", TraceTypes.Events.exitFrame, timeSinceTraceStarted);
TraceTypes.register("parameterNames", TraceTypes.Events.enterFrame, function({ frame }) {
return frame.callee ? frame.callee.parameterNames : undefined;
});
TraceTypes.register("arguments", TraceTypes.Events.enterFrame, function({ frame }) {
if (!frame.arguments) {
return undefined;
}
let args = Array.prototype.slice.call(frame.arguments);
return args.map(arg => createValueGrip(arg, true));
});
TraceTypes.register("return", TraceTypes.Events.exitFrame,
serializeCompletionValue.bind(null, "return"));
TraceTypes.register("throw", TraceTypes.Events.exitFrame,
serializeCompletionValue.bind(null, "throw"));
TraceTypes.register("yield", TraceTypes.Events.exitFrame,
serializeCompletionValue.bind(null, "yield"));
// TODO bug 863089: use Debugger.Script.prototype.getOffsetColumn when
// it is implemented.
function getOffsetColumn(aOffset, aScript) {
@ -530,27 +538,6 @@ function getOffsetColumn(aOffset, aScript) {
return bestOffsetMapping.columnNumber;
}
/**
* Returns elapsed time since the given start time.
*/
function timeSinceTraceStarted({ startTime }) {
return +new Date - startTime;
}
/**
* Creates a value grip for the given completion value, to be
* serialized by JSON.stringify.
*
* @param aType string
* The type of completion value to serialize (return, throw, or yield).
*/
function serializeCompletionValue(aType, { value }) {
if (!Object.hasOwnProperty.call(value, aType)) {
return undefined;
}
return createValueGrip(value[aType], true);
}
// Serialization helper functions. Largely copied from script.js and modified
// for use in serialization rather than object actor requests.
@ -657,24 +644,27 @@ function objectGrip(aObject) {
function objectDescriptor(aObject) {
let desc = objectGrip(aObject);
let ownProperties = Object.create(null);
let names;
try {
names = aObject.getOwnPropertyNames();
} catch(ex) {
// The above can throw if aObject points to a dead object.
// TODO: we should use Cu.isDeadWrapper() - see bug 885800.
if (Cu.isDeadWrapper(aObject)) {
desc.prototype = createValueGrip(null);
desc.ownProperties = ownProperties;
desc.safeGetterValues = Object.create(null);
return desc;
}
const names = aObject.getOwnPropertyNames();
let i = 0;
for (let name of names) {
ownProperties[name] = propertyDescriptor(name, aObject);
if (i++ > MAX_PROPERTIES) {
break;
}
let desc = propertyDescriptor(name, aObject);
if (desc) {
ownProperties[name] = desc;
}
}
desc.prototype = createValueGrip(aObject.proto);
desc.ownProperties = ownProperties;
desc.safeGetterValues = findSafeGetterValues(ownProperties, aObject);
return desc;
}
@ -708,7 +698,8 @@ function propertyDescriptor(aName, aObject) {
};
}
if (!desc) {
// Skip objects since we only support shallow objects anyways.
if (!desc || typeof desc.value == "object" && desc.value !== null) {
return undefined;
}
@ -730,104 +721,3 @@ function propertyDescriptor(aName, aObject) {
}
return retval;
}
/**
* Find the safe getter values for the given Debugger.Object.
*
* @param aOwnProperties object
* The object that holds the list of known ownProperties for |aObject|.
*
* @param Debugger.Object object
* The object to find safe getter values for.
*
* @return object
* An object that maps property names to safe getter descriptors.
*/
function findSafeGetterValues(aOwnProperties, aObject) {
let safeGetterValues = Object.create(null);
let obj = aObject;
let level = 0;
while (obj) {
let getters = findSafeGetters(obj);
for (let name of getters) {
// Avoid overwriting properties from prototypes closer to this.obj. Also
// avoid providing safeGetterValues from prototypes if property |name|
// is already defined as an own property.
if (name in safeGetterValues ||
(obj != aObject && name in aOwnProperties)) {
continue;
}
let desc = null, getter = null;
try {
desc = obj.getOwnPropertyDescriptor(name);
getter = desc.get;
} catch (ex) {
// The above can throw if the cache becomes stale.
}
if (!getter) {
continue;
}
let result = getter.call(aObject);
if (result && !("throw" in result)) {
let getterValue = undefined;
if ("return" in result) {
getterValue = result.return;
} else if ("yield" in result) {
getterValue = result.yield;
}
// WebIDL attributes specified with the LenientThis extended attribute
// return undefined and should be ignored.
if (getterValue !== undefined) {
safeGetterValues[name] = {
getterValue: createValueGrip(getterValue),
getterPrototypeLevel: level,
enumerable: desc.enumerable,
writable: level == 0 ? desc.writable : true,
};
}
}
}
obj = obj.proto;
level++;
}
return safeGetterValues;
}
/**
* Find the safe getters for a given Debugger.Object. Safe getters are native
* getters which are safe to execute.
*
* @param Debugger.Object aObject
* The Debugger.Object where you want to find safe getters.
*
* @return Set
* A Set of names of safe getters.
*/
function findSafeGetters(aObject) {
let getters = new Set();
for (let name of aObject.getOwnPropertyNames()) {
let desc = null;
try {
desc = aObject.getOwnPropertyDescriptor(name);
} catch (e) {
// Calling getOwnPropertyDescriptor on wrapped native prototypes is not
// allowed (bug 560072).
}
if (!desc || desc.value !== undefined || !("get" in desc)) {
continue;
}
let fn = desc.get;
if (fn && fn.callable && fn.class == "Function" &&
fn.script === undefined) {
getters.add(name);
}
}
return getters;
}

View File

@ -31,43 +31,50 @@ function run_test()
function test_enter_exit_frame()
{
let packetsSeen = 0;
let packetNames = [];
let tracesSeen = 0;
let traceNames = [];
let traceStopped = defer();
gTraceClient.addListener("enteredFrame", function(aEvent, aPacket) {
packetsSeen++;
do_check_eq(aPacket.type, "enteredFrame",
'enteredFrame response should have type "enteredFrame"');
do_check_eq(typeof aPacket.sequence, "number",
'enteredFrame response should have sequence number');
do_check_true(!isNaN(aPacket.sequence),
'enteredFrame sequence should be a number');
do_check_eq(typeof aPacket.name, "string",
'enteredFrame response should have function name');
packetNames[aPacket.sequence] = aPacket.name;
});
gClient.addListener("traces", function onTraces(aEvent, { traces }) {
for (let t of traces) {
tracesSeen++;
gTraceClient.addListener("exitedFrame", function(aEvent, aPacket) {
packetsSeen++;
do_check_eq(aPacket.type, "exitedFrame",
'exitedFrame response should have type "exitedFrame"');
do_check_eq(typeof aPacket.sequence, "number",
'exitedFrame response should have sequence number');
do_check_true(!isNaN(aPacket.sequence),
'exitedFrame sequence should be a number');
if (t.type == "enteredFrame") {
do_check_eq(t.type, "enteredFrame",
'enteredFrame response should have type "enteredFrame"');
do_check_eq(typeof t.sequence, "number",
'enteredFrame response should have sequence number');
do_check_true(!isNaN(t.sequence),
'enteredFrame sequence should be a number');
do_check_eq(typeof t.name, "string",
'enteredFrame response should have function name');
traceNames[t.sequence] = t.name;
} else {
do_check_eq(t.type, "exitedFrame",
'exitedFrame response should have type "exitedFrame"');
do_check_eq(typeof t.sequence, "number",
'exitedFrame response should have sequence number');
do_check_true(!isNaN(t.sequence),
'exitedFrame sequence should be a number');
}
if (tracesSeen == 10) {
gClient.removeListener("traces", onTraces);
traceStopped.resolve();
}
}
});
start_trace()
.then(eval_code)
.then(() => traceStopped.promise)
.then(stop_trace)
.then(function() {
do_check_eq(packetsSeen, 10,
'Should have seen two packets for each of 5 stack frames');
do_check_eq(packetNames[2], "baz",
do_check_eq(traceNames[2], "baz",
'Should have entered "baz" frame in third packet');
do_check_eq(packetNames[3], "bar",
do_check_eq(traceNames[3], "bar",
'Should have entered "bar" frame in fourth packet');
do_check_eq(packetNames[4], "foo",
do_check_eq(traceNames[4], "foo",
'Should have entered "foo" frame in fifth packet');
finishClient(gClient);
});

View File

@ -6,7 +6,7 @@
* "arguments", and "return" trace types.
*/
let {defer} = devtools.require("sdk/core/promise");
let { defer } = devtools.require("sdk/core/promise");
var gDebuggee;
var gClient;
@ -28,106 +28,90 @@ function run_test()
do_test_pending();
}
function check_number(value, name)
function check_number(value)
{
do_check_eq(typeof value, "number", name + ' should be a number');
do_check_true(!isNaN(value), name + ' should be a number');
do_check_eq(typeof value, "number");
do_check_true(!isNaN(value));
}
function check_location(actual, expected, name)
function check_location(actual, expected)
{
do_check_eq(typeof actual, "object",
name + ' missing expected source location');
do_check_eq(typeof actual, "object");
check_number(actual.line, name + ' line');
check_number(actual.column, name + ' column');
check_number(actual.line);
check_number(actual.column);
do_check_eq(actual.url, expected.url,
name + ' location should have url ' + expected.url);
do_check_eq(actual.line, expected.line,
name + ' location should have source line of ' + expected.line);
do_check_eq(actual.column, expected.column,
name + ' location should have source column of ' + expected.line);
do_check_eq(actual.url, expected.url);
do_check_eq(actual.line, expected.line);
do_check_eq(actual.column, expected.column);
}
function test_enter_exit_frame()
{
let packets = [];
let traces = [];
let traceStopped = defer();
gTraceClient.addListener("enteredFrame", function(aEvent, aPacket) {
do_check_eq(aPacket.type, "enteredFrame",
'enteredFrame response should have type "enteredFrame"');
do_check_eq(typeof aPacket.name, "string",
'enteredFrame response should have function name');
do_check_eq(typeof aPacket.location, "object",
'enteredFrame response should have source location');
gClient.addListener("traces", function(aEvent, aPacket) {
for (let t of aPacket.traces) {
if (t.type == "enteredFrame") {
do_check_eq(typeof t.name, "string");
do_check_eq(typeof t.location, "object");
check_number(aPacket.sequence, 'enteredFrame sequence');
check_number(aPacket.time, 'enteredFrame time');
check_number(aPacket.location.line, 'enteredFrame source line');
check_number(aPacket.location.column, 'enteredFrame source column');
if (aPacket.callsite) {
check_number(aPacket.callsite.line, 'enteredFrame callsite line');
check_number(aPacket.callsite.column, 'enteredFrame callsite column');
check_number(t.sequence);
check_number(t.time);
check_number(t.location.line);
check_number(t.location.column);
if (t.callsite) {
check_number(t.callsite.line);
check_number(t.callsite.column);
}
} else {
check_number(t.sequence);
check_number(t.time);
}
traces[t.sequence] = t;
if (traces.length === 4) {
traceStopped.resolve();
}
}
packets[aPacket.sequence] = aPacket;
});
gTraceClient.addListener("exitedFrame", function(aEvent, aPacket) {
do_check_eq(aPacket.type, "exitedFrame",
'exitedFrame response should have type "exitedFrame"');
check_number(aPacket.sequence, 'exitedFrame sequence');
check_number(aPacket.time, 'exitedFrame time');
packets[aPacket.sequence] = aPacket;
});
start_trace()
.then(eval_code)
.then(() => traceStopped.promise)
.then(stop_trace)
.then(function() {
let url = getFileUrl("tracerlocations.js");
check_location(packets[0].location, { url: url, line: 1, column: 0 },
'global entry packet');
check_location(traces[0].location, { url: url, line: 1, column: 0 });
do_check_eq(packets[1].name, "foo",
'Second packet in sequence should be entry to "foo" frame');
do_check_eq(traces[1].name, "foo");
// foo's definition is at tracerlocations.js:3:0, but
// Debugger.Script does not provide complete definition
// locations (bug 901138). tracerlocations.js:4:2 is the first
// statement in the function (used as an approximation).
check_location(packets[1].location, { url: url, line: 4, column: 2 },
'foo source');
check_location(packets[1].callsite, { url: url, line: 8, column: 0 },
'foo callsite');
check_location(traces[1].location, { url: url, line: 4, column: 2 });
check_location(traces[1].callsite, { url: url, line: 8, column: 0 });
do_check_eq(typeof packets[1].parameterNames, "object",
'foo entry packet should have parameterNames');
do_check_eq(packets[1].parameterNames.length, 1,
'foo should have only one formal parameter');
do_check_eq(packets[1].parameterNames[0], "x",
'foo should have formal parameter "x"');
do_check_eq(typeof traces[1].parameterNames, "object");
do_check_eq(traces[1].parameterNames.length, 1);
do_check_eq(traces[1].parameterNames[0], "x");
do_check_eq(typeof packets[1].arguments, "object",
'foo entry packet should have arguments');
do_check_true(Array.isArray(packets[1].arguments),
'foo entry packet arguments should be an array');
do_check_eq(packets[1].arguments.length, 1,
'foo should have only one actual parameter');
do_check_eq(packets[1].arguments[0], 42,
'foo should have actual parameter 42');
do_check_eq(typeof traces[1].arguments, "object");
do_check_true(Array.isArray(traces[1].arguments));
do_check_eq(traces[1].arguments.length, 1);
do_check_eq(traces[1].arguments[0], 42);
do_check_eq(typeof packets[2].return, "string",
'Fourth packet in sequence should be exit from "foo" frame');
do_check_eq(packets[2].return, "bar",
'foo should return "bar"');
do_check_eq(typeof traces[2].return, "string");
do_check_eq(traces[2].return, "bar");
finishClient(gClient);
}, error => {
DevToolsUtils.reportException("test_trace_actor-05.js", error);
do_check_true(false);
});
}

View File

@ -6,7 +6,7 @@
* and exitedFrame packets.
*/
let {defer} = devtools.require("sdk/core/promise");
let { defer } = devtools.require("sdk/core/promise");
var gDebuggee;
var gClient;
@ -30,11 +30,20 @@ function run_test()
function test_enter_exit_frame()
{
gTraceClient.addListener("enteredFrame", check_packet);
gTraceClient.addListener("exitedFrame", check_packet);
const traceStopped = defer();
gClient.addListener("traces", (aEvent, { traces }) => {
for (let t of traces) {
check_trace(t);
if (t.sequence === 27) {
traceStopped.resolve();
}
}
});
start_trace()
.then(eval_code)
.then(() => traceStopped.promise)
.then(stop_trace)
.then(function() {
finishClient(gClient);
@ -58,17 +67,23 @@ function eval_code()
let circular = {};
circular.self = circular;
// Make sure there is only 5 properties per object because that is the value
// of MAX_PROPERTIES in the server.
let obj = {
num: 0,
str: "foo",
bool: false,
undef: undefined,
nil: null,
nil: null
};
let obj2 = {
inf: Infinity,
ninf: -Infinity,
nan: NaN,
nzero: -0,
obj: circular,
obj: circular
};
let obj3 = {
arr: [1,2,3,4,5]
};
@ -83,6 +98,8 @@ function eval_code()
identity(NaN);
identity(-0);
identity(obj);
identity(obj2);
identity(obj3);
} + ")()");
}
@ -93,17 +110,15 @@ function stop_trace()
return deferred.promise;
}
function check_packet(aEvent, aPacket)
function check_trace(aTrace)
{
let value = (aPacket.type === "enteredFrame" && aPacket.arguments)
? aPacket.arguments[0]
: aPacket.return;
switch(aPacket.sequence) {
let value = (aTrace.type === "enteredFrame" && aTrace.arguments)
? aTrace.arguments[0]
: aTrace.return;
switch(aTrace.sequence) {
case 2:
do_check_eq(typeof aPacket.arguments, "object",
"zero-argument function call should send arguments list");
do_check_eq(aPacket.arguments.length, 0,
"zero-argument function call should send zero-length arguments list");
do_check_eq(typeof aTrace.arguments, "object");
do_check_eq(aTrace.arguments.length, 0);
break;
case 3:
check_value(value, "object", "undefined");
@ -146,8 +161,15 @@ function check_packet(aEvent, aPacket)
break;
case 22:
case 23:
check_object(aPacket.type, value);
check_obj(aTrace.type, value);
break;
case 24:
case 25:
check_obj2(aTrace.type, value);
break;
case 26:
case 27:
check_obj3(aTrace.type, value);
}
}
@ -157,67 +179,50 @@ function check_value(aActual, aExpectedType, aExpectedValue)
do_check_eq(aExpectedType === "object" ? aActual.type : aActual, aExpectedValue);
}
function check_object(aType, aObj) {
do_check_eq(typeof aObj, "object",
'serialized object should be present in packet');
do_check_eq(typeof aObj.prototype, "object",
'serialized object should have prototype');
do_check_eq(typeof aObj.ownProperties, "object",
'serialized object should have ownProperties list');
do_check_eq(typeof aObj.safeGetterValues, "object",
'serialized object should have safeGetterValues');
function check_obj(aType, aObj) {
do_check_eq(typeof aObj, "object");
do_check_eq(typeof aObj.ownProperties, "object");
do_check_eq(typeof aObj.ownProperties.num, "object",
'serialized object should have property "num"');
do_check_eq(typeof aObj.ownProperties.str, "object",
'serialized object should have property "str"');
do_check_eq(typeof aObj.ownProperties.bool, "object",
'serialized object should have property "bool"');
do_check_eq(typeof aObj.ownProperties.undef, "object",
'serialized object should have property "undef"');
do_check_eq(typeof aObj.ownProperties.undef.value, "object",
'serialized object property "undef" should be a grip');
do_check_eq(typeof aObj.ownProperties.nil, "object",
'serialized object should have property "nil"');
do_check_eq(typeof aObj.ownProperties.nil.value, "object",
'serialized object property "nil" should be a grip');
do_check_eq(typeof aObj.ownProperties.obj, "object",
'serialized object should have property "aObj"');
do_check_eq(typeof aObj.ownProperties.obj.value, "object",
'serialized object property "aObj" should be a grip');
do_check_eq(typeof aObj.ownProperties.arr, "object",
'serialized object should have property "arr"');
do_check_eq(typeof aObj.ownProperties.arr.value, "object",
'serialized object property "arr" should be a grip');
do_check_eq(typeof aObj.ownProperties.inf, "object",
'serialized object should have property "inf"');
do_check_eq(typeof aObj.ownProperties.inf.value, "object",
'serialized object property "inf" should be a grip');
do_check_eq(typeof aObj.ownProperties.ninf, "object",
'serialized object should have property "ninf"');
do_check_eq(typeof aObj.ownProperties.ninf.value, "object",
'serialized object property "ninf" should be a grip');
do_check_eq(typeof aObj.ownProperties.nan, "object",
'serialized object should have property "nan"');
do_check_eq(typeof aObj.ownProperties.nan.value, "object",
'serialized object property "nan" should be a grip');
do_check_eq(typeof aObj.ownProperties.nzero, "object",
'serialized object should have property "nzero"');
do_check_eq(typeof aObj.ownProperties.nzero.value, "object",
'serialized object property "nzero" should be a grip');
do_check_eq(aObj.prototype.type, "object");
do_check_eq(typeof aObj.ownProperties.num, "object");
do_check_eq(aObj.ownProperties.num.value, 0);
do_check_eq(typeof aObj.ownProperties.str, "object");
do_check_eq(aObj.ownProperties.str.value, "foo");
do_check_eq(typeof aObj.ownProperties.bool, "object");
do_check_eq(aObj.ownProperties.bool.value, false);
do_check_eq(typeof aObj.ownProperties.undef, "object");
do_check_eq(typeof aObj.ownProperties.undef.value, "object");
do_check_eq(aObj.ownProperties.undef.value.type, "undefined");
do_check_eq(typeof aObj.ownProperties.nil, "object");
do_check_eq(typeof aObj.ownProperties.nil.value, "object");
do_check_eq(aObj.ownProperties.nil.value.type, "null");
do_check_eq(aObj.ownProperties.obj.value.type, "object");
do_check_eq(aObj.ownProperties.obj.value.class, "Object");
do_check_eq(aObj.ownProperties.arr.value.type, "object");
do_check_eq(aObj.ownProperties.arr.value.class, "Array");
do_check_eq(aObj.ownProperties.inf.value.type, "Infinity");
do_check_eq(aObj.ownProperties.ninf.value.type, "-Infinity");
do_check_eq(aObj.ownProperties.nan.value.type, "NaN");
do_check_eq(aObj.ownProperties.nzero.value.type, "-0");
}
function check_obj2(aType, aObj) {
do_check_eq(typeof aObj.ownProperties.inf, "object");
do_check_eq(typeof aObj.ownProperties.inf.value, "object");
do_check_eq(aObj.ownProperties.inf.value.type, "Infinity");
do_check_eq(typeof aObj.ownProperties.ninf, "object");
do_check_eq(typeof aObj.ownProperties.ninf.value, "object");
do_check_eq(aObj.ownProperties.ninf.value.type, "-Infinity");
do_check_eq(typeof aObj.ownProperties.nan, "object");
do_check_eq(typeof aObj.ownProperties.nan.value, "object");
do_check_eq(aObj.ownProperties.nan.value.type, "NaN");
do_check_eq(typeof aObj.ownProperties.nzero, "object");
do_check_eq(typeof aObj.ownProperties.nzero.value, "object");
do_check_eq(aObj.ownProperties.nzero.value.type, "-0");
// Sub-objects aren't added.
do_check_eq(typeof aObj.ownProperties.obj, "undefined");
}
function check_obj3(aType, aObj) {
// Sub-objects aren't added.
do_check_eq(typeof aObj.ownProperties.arr, "undefined");
}

View File

@ -29,7 +29,13 @@ function run_test()
function test_exit_frame_whys()
{
gTraceClient.addListener("exitedFrame", check_packet);
gClient.addListener("traces", (aEvent, { traces }) => {
for (let t of traces) {
if (t.type == "exitedFrame") {
check_trace(t);
}
}
});
start_trace()
.then(eval_code)
@ -83,7 +89,7 @@ function stop_trace()
return deferred.promise;
}
function check_packet(aEvent, { sequence, why })
function check_trace(aEvent, { sequence, why })
{
switch(sequence) {
case 3:

View File

@ -1,101 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that TraceClient emits enteredFrame and exitedFrame events in
* order when receiving packets out of order.
*/
let {defer, resolve} = devtools.require("sdk/core/promise");
var gDebuggee;
var gClient;
var gTraceClient;
function run_test()
{
initTestTracerServer();
gDebuggee = addTestGlobal("test-tracer-actor");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTab(gClient, "test-tracer-actor", function(aResponse, aTabClient) {
gClient.attachTracer(aResponse.traceActor, function(aResponse, aTraceClient) {
gTraceClient = aTraceClient;
test_packet_order();
});
});
});
do_test_pending();
}
function test_packet_order()
{
let sequence = 0;
function check_packet(aEvent, aPacket) {
do_check_eq(aPacket.sequence, sequence,
'packet should have sequence number ' + sequence);
sequence++;
}
gTraceClient.addListener("enteredFrame", check_packet);
gTraceClient.addListener("exitedFrame", check_packet);
start_trace()
.then(mock_packets)
.then(start_trace)
.then(mock_packets.bind(null, 14))
.then(stop_trace)
.then(stop_trace)
.then(function() {
// All traces were stopped, so the sequence number resets
sequence = 0;
return resolve();
})
.then(start_trace)
.then(mock_packets)
.then(stop_trace)
.then(function() {
finishClient(gClient);
});
}
function start_trace()
{
let deferred = defer();
gTraceClient.startTrace([], null, function() { deferred.resolve(); });
return deferred.promise;
}
function stop_trace()
{
let deferred = defer();
gTraceClient.stopTrace(null, function() { deferred.resolve(); });
return deferred.promise;
}
function mock_packets(s = 0)
{
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 5 });
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 3 });
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 2 });
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 4 });
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 1 });
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 7 });
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 8 });
// Triggers 0-5
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 0 });
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 9 });
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 10 });
// Triggers 6-10
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 6 });
// Each following packet is expected; event is fired immediately
gTraceClient.onPacket("", { type: "enteredFrame", sequence: s + 11 });
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 12 });
gTraceClient.onPacket("", { type: "exitedFrame", sequence: s + 13 });
}

View File

@ -190,4 +190,3 @@ reason = bug 820380
[test_trace_actor-06.js]
[test_trace_actor-07.js]
[test_ignore_caught_exceptions.js]
[test_trace_client-01.js]

View File

@ -517,7 +517,7 @@ if (IS_WIN) {
function lockDirectory(aDir) {
var file = aDir.clone();
file.append(kLockFileName);
file.create(file.NORMAL_FILE_TYPE, 4 * 64 + 4 * 8 + 4); // 0444
file.create(file.NORMAL_FILE_TYPE, 0o444);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READONLY;
file.fileAttributesWin &= ~file.WFA_READWRITE;
@ -577,7 +577,7 @@ function copyMinimumAppFiles(aSrcDir, aDestDir, aDestLeafName) {
deplibsFile.append("dependentlibs.list");
let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(AUS_Ci.nsIFileInputStream);
istream.init(deplibsFile, 0x01, 4 * 64 + 4 * 8 + 4, 0); // 0444
istream.init(deplibsFile, 0x01, 0o444, 0);
istream.QueryInterface(AUS_Ci.nsILineInputStream);
let hasMore;
@ -723,21 +723,6 @@ function shouldRunServiceTest(aFirstTest) {
// the newer bin that we have.
attemptServiceInstall();
const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" +
"3932ecacee736d366d6436db0f55bce4";
let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
createInstance(AUS_Ci.nsIWindowsRegKey);
try {
key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64);
}
catch (e) {
logTestInfo("this test can only run on the buildbot build system at this " +
"time.");
return false;
}
let binDir = getGREDir();
let updaterBin = binDir.clone();
updaterBin.append(FILE_UPDATER_BIN);
@ -750,6 +735,29 @@ function shouldRunServiceTest(aFirstTest) {
updaterBinPath = '"' + updaterBinPath + '"';
}
const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" +
"3932ecacee736d366d6436db0f55bce4";
let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
createInstance(AUS_Ci.nsIWindowsRegKey);
try {
key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64);
}
catch (e) {
#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
// The build system could sign the files and not have the test registry key
// in which case we should fail the test by throwing so it can be fixed.
if (isBinarySigned(updaterBinPath)) {
do_throw("binary is signed but the test registry key does not exists!");
}
#endif
logTestInfo("this test can only run on the buildbot build system at this " +
"time.");
return false;
}
// Check to make sure the service is installed
let helperBin = getTestDirFile(FILE_HELPER_BIN);
let args = ["wait-for-service-stop", "MozillaMaintenance", "10"];
@ -759,8 +767,8 @@ function shouldRunServiceTest(aFirstTest) {
logTestInfo("Checking if the service exists on this machine.");
process.run(true, args, args.length);
if (process.exitValue == 0xEE) {
logTestInfo("this test can only run when the service is installed.");
return false;
do_throw("test registry key exists but this test can only run on systems " +
"with the maintenance service installed.");
} else {
logTestInfo("Service exists, return value: " + process.exitValue);
}
@ -773,23 +781,34 @@ function shouldRunServiceTest(aFirstTest) {
process.exitValue);
}
#ifdef DISABLE_UPDATER_AUTHENTICODE_CHECK
// We won't be performing signature checks.
#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
if (!isBinarySigned(updaterBinPath)) {
logTestInfo("this test can only run on builds with signed binaries.");
return false;
}
#endif
return true;
#else
// Make sure the binaries are signed
args = ["check-signature", updaterBinPath];
process = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
}
/**
* Helper function to check whether the a binary is signed.
*
* @param aBinPath The path to the file to check if it is signed.
* @return true if the file is signed and false if it isn't.
*/
function isBinarySigned(aBinPath) {
let helperBin = getTestDirFile(FILE_HELPER_BIN);
let args = ["check-signature", aBinPath];
let process = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
process.init(helperBin);
process.run(true, args, args.length);
if (process.exitValue == 0) {
return true;
if (process.exitValue != 0) {
logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " +
process.exitValue + " for file " + aBinPath);
return false;
}
logTestInfo("this test can only run on builds with signed binaries. " +
FILE_HELPER_BIN + " returned " + process.exitValue)
return false;
#endif
return true;
}
/**
@ -817,7 +836,7 @@ function copyBinToApplyToDir(filename) {
* This is useful for XP where we have permission to upgrade in case an
* older service installer exists. Also if the user manually installed into
* a unprivileged location.
*/
*/
function attemptServiceInstall() {
var version = AUS_Cc["@mozilla.org/system-info;1"]
.getService(AUS_Ci.nsIPropertyBag2)

View File

@ -280,7 +280,8 @@ MetroWidget::Destroy()
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
observerService->RemoveObserver(this, "apzc-scroll-offset-changed");
observerService->RemoveObserver(this, "Metro:ZoomToRect");
observerService->RemoveObserver(this, "apzc-zoom-to-rect");
observerService->RemoveObserver(this, "apzc-disable-zoom");
}
}
@ -991,7 +992,8 @@ CompositorParent* MetroWidget::NewCompositorParent(int aSurfaceWidth, int aSurfa
nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
observerService->AddObserver(this, "apzc-scroll-offset-changed", false);
observerService->AddObserver(this, "Metro:ZoomToRect", false);
observerService->AddObserver(this, "apzc-zoom-to-rect", false);
observerService->AddObserver(this, "apzc-disable-zoom", false);
}
}
@ -1601,7 +1603,7 @@ MetroWidget::Observe(nsISupports *subject, const char *topic, const PRUnichar *d
mController->UpdateScrollOffset(ScrollableLayerGuid(mRootLayerTreeId, presShellId, scrollId),
scrollOffset);
}
else if (!strcmp(topic, "Metro:ZoomToRect")) {
else if (!strcmp(topic, "apzc-zoom-to-rect")) {
CSSRect rect = CSSRect();
uint64_t viewId = 0;
int32_t presShellId = 0;
@ -1610,12 +1612,25 @@ MetroWidget::Observe(nsISupports *subject, const char *topic, const PRUnichar *d
&rect.x, &rect.y, &rect.width, &rect.height,
&presShellId, &viewId);
if(reScan != 6) {
NS_WARNING("Malformed Metro:ZoomToRect message");
NS_WARNING("Malformed apzc-zoom-to-rect message");
}
ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
APZController::sAPZC->ZoomToRect(guid, rect);
}
else if (!strcmp(topic, "apzc-disable-zoom")) {
uint64_t viewId = 0;
int32_t presShellId = 0;
int reScan = swscanf(data, L"%d,%llu",
&presShellId, &viewId);
if (reScan != 2) {
NS_WARNING("Malformed apzc-disable-zoom message");
}
ScrollableLayerGuid guid = ScrollableLayerGuid(mRootLayerTreeId, presShellId, viewId);
APZController::sAPZC->UpdateZoomConstraints(guid, false, CSSToScreenScale(1.0f), CSSToScreenScale(1.0f));
}
else {
return NS_OK;
}