Merge m-c to f-t

This commit is contained in:
Phil Ringnalda 2014-11-27 17:45:52 -08:00
commit 341e5aef60
57 changed files with 1471 additions and 674 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "78d735b50d94254ff236fc34a6fbaa5ed27692a0",
"revision": "415520315b048f40979e9bac344bec99e18df901",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6499615ecece69e726657dc5caaeefa05fbb66bf"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="80bc1445959db79e9d2e947cc56e1eb7b0d3d0f0"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="1fff49c664f905f11a86426a9835e6df6b58e825"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="50ad16a280fe9cfa0716f8c6ba16afdf7f266b49"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -488,3 +488,4 @@ skip-if = e10s # Bug 1100687 - test directly manipulates content (content.docume
skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
[browser_mcb_redirect.js]
skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
[browser_windowactivation.js]

View File

@ -0,0 +1,152 @@
/*
* This test checks that window activation state is set properly with multiple tabs.
*/
let testPage = "data:text/html,<body><style>:-moz-window-inactive { background-color: red; }</style><div id='area'></div></body>";
let colorChangeNotifications = 0;
let otherWindow;
let browser1, browser2;
function test() {
waitForExplicitFinish();
let tab1 = gBrowser.addTab();
let tab2 = gBrowser.addTab();
browser1 = gBrowser.getBrowserForTab(tab1);
browser2 = gBrowser.getBrowserForTab(tab2);
gURLBar.focus();
var loadCount = 0;
function check()
{
// wait for both tabs to load
if (++loadCount != 2) {
return;
}
browser1.removeEventListener("load", check, true);
browser2.removeEventListener("load", check, true);
sendGetBackgroundRequest(true);
}
// The test performs four checks, using -moz-window-inactive on two child tabs.
// First, the initial state should be transparent. The second check is done
// while another window is focused. The third check is done after that window
// is closed and the main window focused again. The fourth check is done after
// switching to the second tab.
window.messageManager.addMessageListener("Test:BackgroundColorChanged", function(message) {
colorChangeNotifications++;
switch (colorChangeNotifications) {
case 1:
is(message.data.color, "transparent", "first window initial");
break;
case 2:
is(message.data.color, "transparent", "second window initial");
runOtherWindowTests();
break;
case 3:
is(message.data.color, "rgb(255, 0, 0)", "first window lowered");
break;
case 4:
is(message.data.color, "rgb(255, 0, 0)", "second window lowered");
sendGetBackgroundRequest(true);
otherWindow.close();
break;
case 5:
is(message.data.color, "transparent", "first window raised");
break;
case 6:
is(message.data.color, "transparent", "second window raised");
gBrowser.selectedTab = tab2;
break;
case 7:
is(message.data.color, "transparent", "first window after tab switch");
break;
case 8:
is(message.data.color, "transparent", "second window after tab switch");
finishTest();
break;
case 9:
ok(false, "too many color change notifications");
break;
}
});
window.messageManager.addMessageListener("Test:FocusReceived", function(message) {
// No color change should occur after a tab switch.
if (colorChangeNotifications == 6) {
sendGetBackgroundRequest(false);
}
});
browser1.addEventListener("load", check, true);
browser2.addEventListener("load", check, true);
browser1.contentWindow.location = testPage;
browser2.contentWindow.location = testPage;
browser1.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
browser2.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
gBrowser.selectedTab = tab1;
}
function sendGetBackgroundRequest(ifChanged)
{
browser1.messageManager.sendAsyncMessage("Test:GetBackgroundColor", { ifChanged: ifChanged });
browser2.messageManager.sendAsyncMessage("Test:GetBackgroundColor", { ifChanged: ifChanged });
}
function runOtherWindowTests() {
otherWindow = window.open("data:text/html,<body>Hi</body>", "", "chrome");
waitForFocus(function () {
sendGetBackgroundRequest(true);
}, otherWindow);
}
function finishTest()
{
gBrowser.removeCurrentTab();
gBrowser.removeCurrentTab();
otherWindow = null;
finish();
}
function childFunction()
{
let oldColor = null;
let expectingResponse = false;
let ifChanged = true;
addMessageListener("Test:GetBackgroundColor", function(message) {
expectingResponse = true;
ifChanged = message.data.ifChanged;
});
content.addEventListener("focus", function () {
sendAsyncMessage("Test:FocusReceived", { });
}, false);
content.setInterval(function () {
if (!expectingResponse) {
return;
}
let area = content.document.getElementById("area");
if (!area) {
return; /* hasn't loaded yet */
}
let color = content.getComputedStyle(area, "").backgroundColor;
if (oldColor != color || !ifChanged) {
expectingResponse = false;
oldColor = color;
sendAsyncMessage("Test:BackgroundColorChanged", { color: color });
}
}, 20);
}

View File

@ -41,6 +41,7 @@
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/TextDecoder.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/ShadowRoot.h"
@ -98,6 +99,7 @@
#include "nsIDocShell.h"
#include "nsIDocument.h"
#include "nsIDocumentEncoder.h"
#include "nsIDOMChromeWindow.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMEvent.h"
@ -180,6 +182,11 @@
#include "nsIBidiKeyboard.h"
#if defined(XP_WIN)
// Undefine LoadImage to prevent naming conflict with Windows.
#undef LoadImage
#endif
extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end,
const char** next, char16_t* result);
extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end,
@ -7067,3 +7074,54 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
CopyUTF8toUTF16(hostname, aHost);
}
void
nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
CallOnRemoteChildFunction aCallback,
void* aArg)
{
uint32_t tabChildCount = 0;
aManager->GetChildCount(&tabChildCount);
for (uint32_t j = 0; j < tabChildCount; ++j) {
nsCOMPtr<nsIMessageListenerManager> childMM;
aManager->GetChildAt(j, getter_AddRefs(childMM));
if (!childMM) {
continue;
}
nsCOMPtr<nsIMessageBroadcaster> nonLeafMM = do_QueryInterface(childMM);
if (nonLeafMM) {
CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg);
continue;
}
nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
mozilla::dom::ipc::MessageManagerCallback* cb =
static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
if (cb) {
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
PBrowserParent* remoteBrowser = fl->GetRemoteBrowser();
TabParent* remote = static_cast<TabParent*>(remoteBrowser);
if (remote && aCallback) {
aCallback(remote, aArg);
}
}
}
}
void
nsContentUtils::CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
CallOnRemoteChildFunction aCallback,
void* aArg)
{
nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aWindow));
if (chromeWindow) {
nsCOMPtr<nsIMessageBroadcaster> windowMM;
chromeWindow->GetMessageManager(getter_AddRefs(windowMM));
if (windowMM) {
CallOnAllRemoteChildren(windowMM, aCallback, aArg);
}
}
}

View File

@ -73,6 +73,7 @@ class nsIInterfaceRequestor;
class nsIIOService;
class nsIJSRuntimeService;
class nsILineBreaker;
class nsIMessageBroadcaster;
class nsNameSpaceManager;
class nsIObserver;
class nsIParser;
@ -121,6 +122,7 @@ class Element;
class EventTarget;
class NodeInfo;
class Selection;
class TabParent;
} // namespace dom
namespace layers {
@ -168,6 +170,9 @@ struct nsShortcutCandidate {
bool mIgnoreShift;
};
typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
void* aArg);
class nsContentUtils
{
friend class nsAutoScriptBlockerSuppressNodeRemoved;
@ -2211,6 +2216,14 @@ public:
*/
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
/*
* Call the given callback on all remote children of the given top-level
* window.
*/
static void CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
CallOnRemoteChildFunction aCallback,
void* aArg);
private:
static bool InitializeEventTable();
@ -2246,6 +2259,10 @@ private:
static AutocompleteAttrState InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
mozilla::dom::AutocompleteInfo& aInfo);
static void CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
CallOnRemoteChildFunction aCallback,
void* aArg);
static nsIXPConnect *sXPConnect;
static nsIScriptSecurityManager *sSecurityManager;

View File

@ -47,6 +47,7 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include <algorithm>
#ifdef MOZ_XUL
@ -172,6 +173,7 @@ static const char* kObservedPrefs[] = {
};
nsFocusManager::nsFocusManager()
: mParentFocusType(ParentFocusType_Ignore)
{ }
nsFocusManager::~nsFocusManager()
@ -706,15 +708,12 @@ nsFocusManager::WindowRaised(nsIDOMWindow* aWindow)
}
}
// inform the DOM window that it has activated, so that the active attribute
// is updated on the window
window->ActivateOrDeactivate(true);
// send activate event
nsContentUtils::DispatchTrustedEvent(window->GetExtantDoc(),
window,
NS_LITERAL_STRING("activate"),
true, true, nullptr);
// If this is a parent or single process window, send the activate event.
// Events for child process windows will be sent when ParentActivated
// is called.
if (mParentFocusType == ParentFocusType_Ignore) {
ActivateOrDeactivate(window, true);
}
// retrieve the last focused element within the window that was raised
nsCOMPtr<nsPIDOMWindow> currentWindow;
@ -771,15 +770,12 @@ nsFocusManager::WindowLowered(nsIDOMWindow* aWindow)
// clear the mouse capture as the active window has changed
nsIPresShell::SetCapturingContent(nullptr, 0);
// inform the DOM window that it has deactivated, so that the active
// attribute is updated on the window
window->ActivateOrDeactivate(false);
// send deactivate event
nsContentUtils::DispatchTrustedEvent(window->GetExtantDoc(),
window,
NS_LITERAL_STRING("deactivate"),
true, true, nullptr);
// If this is a parent or single process window, send the deactivate event.
// Events for child process windows will be sent when ParentActivated
// is called.
if (mParentFocusType == ParentFocusType_Ignore) {
ActivateOrDeactivate(window, false);
}
// keep track of the window being lowered, so that attempts to raise the
// window can be prevented until we return. Otherwise, focus can get into
@ -906,6 +902,10 @@ nsFocusManager::WindowShown(nsIDOMWindow* aWindow, bool aNeedsFocus)
EnsureCurrentWidgetFocused();
}
if (mParentFocusType == ParentFocusType_Active) {
ActivateOrDeactivate(window, true);
}
return NS_OK;
}
@ -1065,6 +1065,19 @@ nsFocusManager::FocusPlugin(nsIContent* aContent)
return NS_OK;
}
NS_IMETHODIMP
nsFocusManager::ParentActivated(nsIDOMWindow* aWindow, bool aActive)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
window = window->GetOuterWindow();
mParentFocusType = aActive ? ParentFocusType_Active : ParentFocusType_Inactive;
ActivateOrDeactivate(window, aActive);
return NS_OK;
}
/* static */
void
nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
@ -1109,6 +1122,36 @@ nsFocusManager::EnsureCurrentWidgetFocused()
}
}
void
ActivateOrDeactivateChild(TabParent* aParent, void* aArg)
{
bool active = static_cast<bool>(aArg);
unused << aParent->SendParentActivated(active);
}
void
nsFocusManager::ActivateOrDeactivate(nsPIDOMWindow* aWindow, bool aActive)
{
if (!aWindow) {
return;
}
// Inform the DOM window that it has activated or deactivated, so that
// the active attribute is updated on the window.
aWindow->ActivateOrDeactivate(aActive);
// Send the activate event.
nsContentUtils::DispatchTrustedEvent(aWindow->GetExtantDoc(),
aWindow,
aActive ? NS_LITERAL_STRING("activate") :
NS_LITERAL_STRING("deactivate"),
true, true, nullptr);
// Look for any remote child frames, iterate over them and send the activation notification.
nsContentUtils::CallOnAllRemoteChildren(aWindow, ActivateOrDeactivateChild,
(void *)aActive);
}
void
nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
bool aFocusChanged, bool aAdjustWidget)

View File

@ -22,9 +22,16 @@
class nsIContent;
class nsIDocShellTreeItem;
class nsPIDOMWindow;
class nsIMessageBroadcaster;
struct nsDelayedBlurOrFocusEvent;
enum ParentFocusType {
ParentFocusType_Ignore, // Parent or single process window or unknown
ParentFocusType_Active, // Child process window in active parent
ParentFocusType_Inactive, // Child process window in inactive parent
};
/**
* The focus manager keeps track of where the focus is, that is, the node
* which receives key events.
@ -90,6 +97,15 @@ public:
*/
void UpdateCaretForCaretBrowsingMode();
bool IsParentActivated()
{
if (mParentFocusType == ParentFocusType_Ignore) {
return mActiveWindow != nullptr;
}
return mParentFocusType == ParentFocusType_Active;
}
/**
* Returns the content node that would be focused if aWindow was in an
* active window. This will traverse down the frame hierarchy, starting at
@ -134,6 +150,17 @@ protected:
*/
void EnsureCurrentWidgetFocused();
/**
* Iterate over the children of the message broadcaster and notify them
* of the activation change.
*/
void ActivateOrDeactivateChildren(nsIMessageBroadcaster* aManager, bool aActive);
/**
* Activate or deactivate the window and send the activate/deactivate events.
*/
void ActivateOrDeactivate(nsPIDOMWindow* aWindow, bool aActive);
/**
* Blur whatever is currently focused and focus aNewContent. aFlags is a
* bitmask of the flags defined in nsIFocusManager. If aFocusChanged is
@ -526,6 +553,9 @@ private:
// moving focus.
nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
// Indicates a child process that is in an active window.
ParentFocusType mParentFocusType;
static bool sTestMode;
// the single focus manager

View File

@ -1234,6 +1234,12 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
if (sWindowsById) {
sWindowsById->Put(mWindowID, this);
}
// Ensure that the current active state is initialized for child process windows.
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
mIsActive = fm->IsParentActivated();
}
}
/* static */
@ -9821,17 +9827,21 @@ nsGlobalWindow::ActivateOrDeactivate(bool aActivate)
{
MOZ_ASSERT(IsOuterWindow());
if (!mDoc) {
return;
}
// Set / unset mIsActive on the top level window, which is used for the
// :-moz-window-inactive pseudoclass, and its sheet (if any).
nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
if (!mainWidget)
return;
// Get the top level widget (if the main widget is a sheet, this will
// be the sheet's top (non-sheet) parent).
nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
if (!topLevelWidget) {
topLevelWidget = mainWidget;
nsCOMPtr<nsIWidget> topLevelWidget;
if (mainWidget) {
// Get the top level widget (if the main widget is a sheet, this will
// be the sheet's top (non-sheet) parent).
topLevelWidget = mainWidget->GetSheetWindowParent();
if (!topLevelWidget) {
topLevelWidget = mainWidget;
}
}
nsCOMPtr<nsPIDOMWindow> piMainWindow(

View File

@ -187,6 +187,7 @@ static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
static bool sNeedsFullCC = false;
static bool sNeedsGCAfterCC = false;
static bool sIncrementalCC = false;
static bool sDidPaintAfterPreviousICCSlice = false;
static nsScriptNameSpaceManager *gNameSpaceManager;
@ -1708,7 +1709,8 @@ nsJSContext::RunCycleCollectorSlice()
}
}
nsCycleCollector_collectSlice(budget);
nsCycleCollector_collectSlice(budget, sDidPaintAfterPreviousICCSlice);
sDidPaintAfterPreviousICCSlice = false;
gCCStats.FinishCycleCollectionSlice();
}
@ -2856,6 +2858,12 @@ nsJSContext::EnsureStatics()
sIsInitialized = true;
}
void
nsJSContext::NotifyDidPaint()
{
sDidPaintAfterPreviousICCSlice = true;
}
nsScriptNameSpaceManager*
mozilla::dom::GetNameSpaceManager()
{

View File

@ -136,6 +136,8 @@ public:
JSObject* global = GetWindowProxy();
return global ? mGlobalObjectRef.get() : nullptr;
}
static void NotifyDidPaint();
protected:
virtual ~nsJSContext();

View File

@ -8,7 +8,7 @@
interface nsIDocument;
interface nsIContent;
[scriptable, uuid(51db277b-7ee7-4bce-9b84-fd2efcd2c8bd)]
[scriptable, uuid(c0716002-5602-4002-a0de-cc69b924b2c6)]
/**
* The focus manager deals with all focus related behaviour. Only one element
* in the entire application may have the focus at a time; this element
@ -250,4 +250,10 @@ interface nsIFocusManager : nsISupports
* widget focus state is the responsibility of the caller.
*/
[noscript] void focusPlugin(in nsIContent aPlugin);
/**
* Used in a child process to indicate that the parent window is now
* active or deactive.
*/
[noscript] void parentActivated(in nsIDOMWindow aWindow, in bool active);
};

View File

@ -442,6 +442,8 @@ child:
Deactivate();
ParentActivated(bool aActivated);
/**
* @see nsIDOMWindowUtils sendMouseEvent.
*/

View File

@ -52,6 +52,7 @@
#include "nsIDOMEvent.h"
#include "nsIDOMWindow.h"
#include "nsIDOMWindowUtils.h"
#include "nsFocusManager.h"
#include "nsIDocShell.h"
#include "nsIFrame.h"
#include "nsIURI.h"
@ -2222,6 +2223,16 @@ bool TabChild::RecvDeactivate()
return true;
}
bool TabChild::RecvParentActivated(const bool& aActivated)
{
nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, true);
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(WebNavigation());
fm->ParentActivated(window, aActivated);
return true;
}
bool
TabChild::RecvMouseEvent(const nsString& aType,
const float& aX,

View File

@ -503,6 +503,8 @@ protected:
virtual bool RecvRequestNotifyAfterRemotePaint();
virtual bool RecvParentActivated(const bool& aActivated) MOZ_OVERRIDE;
#ifdef MOZ_WIDGET_GONK
void MaybeRequestPreinitCamera();
#endif

View File

@ -609,17 +609,9 @@ Nfc.prototype = {
* Process a message from the gMessageManager.
*/
receiveMessage: function receiveMessage(message) {
let isRFAPI = message.name == "NFC:ChangeRFState";
let isSendFile = message.name == "NFC:SendFile";
let isInfoAPI = message.name == "NFC:QueryInfo";
if (!isRFAPI && !isInfoAPI && (this.rfState != NFC.NFC_RF_STATE_DISCOVERY)) {
debug("NFC is not enabled. current rfState:" + this.rfState);
this.sendNfcErrorResponse(message, NFC.NFC_GECKO_ERROR_NOT_ENABLED);
return null;
}
if (!isRFAPI && !isSendFile && !isInfoAPI) {
if (["NFC:ChangeRFState",
"NFC:SendFile",
"NFC:QueryInfo"].indexOf(message.name) == -1) {
// Update the current sessionId before sending to the NFC service.
message.data.sessionId = SessionHelper.getId(message.data.sessionToken);
}

View File

@ -26,14 +26,12 @@ this.DEBUG_NFC = DEBUG_ALL || false;
this.NFC_GECKO_SUCCESS = 0;
this.NFC_GECKO_ERROR_GENERIC_FAILURE = 1;
this.NFC_GECKO_ERROR_P2P_REG_INVALID = 2;
this.NFC_GECKO_ERROR_NOT_ENABLED = 3;
this.NFC_GECKO_ERROR_SEND_FILE_FAILED = 4;
this.NFC_GECKO_ERROR_BAD_SESSION_TOKEN = 5;
this.NFC_GECKO_ERROR_SEND_FILE_FAILED = 3;
this.NFC_GECKO_ERROR_BAD_SESSION_TOKEN = 4;
this.NFC_ERROR_MSG = {};
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_GENERIC_FAILURE] = "NfcGenericFailureError";
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_P2P_REG_INVALID] = "NfcP2PRegistrationInvalid";
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_NOT_ENABLED] = "NfcNotEnabledError";
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_SEND_FILE_FAILED] = "NfcSendFileFailed";
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_BAD_SESSION_TOKEN] = "NfcBadSessionToken";

View File

@ -1,3 +1,5 @@
if (!this.hasOwnProperty("TypedObject"))
quit();
gczeal(2);
var Vec3u16Type = TypedObject.uint16.array(3);

View File

@ -1,3 +1,5 @@
if (!this.hasOwnProperty("TypedObject"))
quit();
var Vec3u16Type = TypedObject.uint16.array(3);

View File

@ -3438,6 +3438,7 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
if (!ins->resultTypeSet() || ins->resultTypeSet()->unknown())
return true;
types::TemporaryTypeSet *oldType = ins->resultTypeSet();
types::TemporaryTypeSet *type;
// Decide either to set or filter.
@ -3448,27 +3449,30 @@ IonBuilder::improveTypesAtTest(MDefinition *ins, bool trueBranch, MTest *test)
{
return true;
}
type = ins->resultTypeSet()->filter(alloc_->lifoAlloc(), true, true);
type = oldType->filter(alloc_->lifoAlloc(), true, true);
} else {
// According to the standards, we cannot filter out:
// Strings, Int32, Double, Booleans, Objects (if they emulate undefined)
// According to the standards, we cannot filter out: Strings,
// Int32, Double, Booleans, Objects (if they emulate undefined)
uint32_t flags = types::TYPE_FLAG_PRIMITIVE;
// If the typeset does not emulate undefined. Then we can filter out objects.
if (!ins->resultTypeSet()->maybeEmulatesUndefined())
flags &= ~types::TYPE_FLAG_ANYOBJECT;
// If the typeset does emulate undefined, then we cannot filter out
// objects.
if (oldType->maybeEmulatesUndefined())
flags |= types::TYPE_FLAG_ANYOBJECT;
// Only intersect the typesets if it will generate a more narrow typeset.
if (!ins->resultTypeSet()->hasAnyFlag(~flags & types::TYPE_FLAG_BASE_MASK) &&
ins->resultTypeSet()->getObjectCount() == 0)
// Only intersect the typesets if it will generate a more narrow
// typeset. The first part takes care of primitives and AnyObject,
// while the second line specific (type)objects.
if (!oldType->hasAnyFlag(~flags & types::TYPE_FLAG_BASE_MASK) &&
(oldType->maybeEmulatesUndefined() || !oldType->maybeObject()))
{
return true;
}
types::TemporaryTypeSet base(flags, static_cast<types::TypeObjectKey**>(nullptr));
type = types::TypeSet::intersectSets(&base, ins->resultTypeSet(), alloc_->lifoAlloc());
replaceTypeSet(ins, type, test);
type = types::TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc());
}
replaceTypeSet(ins, type, test);
}
}

View File

@ -4354,27 +4354,27 @@ nsLayoutUtils::ComputeCBDependentValue(nscoord aPercentBasis,
}
/* static */ nscoord
nsLayoutUtils::ComputeWidthValue(
nsLayoutUtils::ComputeISizeValue(
nsRenderingContext* aRenderingContext,
nsIFrame* aFrame,
nscoord aContainingBlockWidth,
nscoord aContainingBlockISize,
nscoord aContentEdgeToBoxSizing,
nscoord aBoxSizingToMarginEdge,
const nsStyleCoord& aCoord)
{
NS_PRECONDITION(aFrame, "non-null frame expected");
NS_PRECONDITION(aRenderingContext, "non-null rendering context expected");
NS_WARN_IF_FALSE(aContainingBlockWidth != NS_UNCONSTRAINEDSIZE,
"have unconstrained width; this should only result from "
"very large sizes, not attempts at intrinsic width "
NS_WARN_IF_FALSE(aContainingBlockISize != NS_UNCONSTRAINEDSIZE,
"have unconstrained inline-size; this should only result from "
"very large sizes, not attempts at intrinsic inline-size "
"calculation");
NS_PRECONDITION(aContainingBlockWidth >= 0,
"width less than zero");
NS_PRECONDITION(aContainingBlockISize >= 0,
"inline-size less than zero");
nscoord result;
if (aCoord.IsCoordPercentCalcUnit()) {
result = nsRuleNode::ComputeCoordPercentCalc(aCoord,
aContainingBlockWidth);
aContainingBlockISize);
// The result of a calc() expression might be less than 0; we
// should clamp at runtime (below). (Percentages and coords that
// are less than 0 have already been dropped by the parser.)
@ -4389,24 +4389,24 @@ nsLayoutUtils::ComputeWidthValue(
switch (val) {
case NS_STYLE_WIDTH_MAX_CONTENT:
result = aFrame->GetPrefISize(aRenderingContext);
NS_ASSERTION(result >= 0, "width less than zero");
NS_ASSERTION(result >= 0, "inline-size less than zero");
break;
case NS_STYLE_WIDTH_MIN_CONTENT:
result = aFrame->GetMinISize(aRenderingContext);
NS_ASSERTION(result >= 0, "width less than zero");
NS_ASSERTION(result >= 0, "inline-size less than zero");
break;
case NS_STYLE_WIDTH_FIT_CONTENT:
{
nscoord pref = aFrame->GetPrefISize(aRenderingContext),
min = aFrame->GetMinISize(aRenderingContext),
fill = aContainingBlockWidth -
fill = aContainingBlockISize -
(aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
result = std::max(min, std::min(pref, fill));
NS_ASSERTION(result >= 0, "width less than zero");
NS_ASSERTION(result >= 0, "inline-size less than zero");
}
break;
case NS_STYLE_WIDTH_AVAILABLE:
result = aContainingBlockWidth -
result = aContainingBlockISize -
(aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
}
}
@ -4415,28 +4415,28 @@ nsLayoutUtils::ComputeWidthValue(
}
/* static */ nscoord
nsLayoutUtils::ComputeHeightDependentValue(
nscoord aContainingBlockHeight,
nsLayoutUtils::ComputeBSizeDependentValue(
nscoord aContainingBlockBSize,
const nsStyleCoord& aCoord)
{
// XXXldb Some callers explicitly check aContainingBlockHeight
// XXXldb Some callers explicitly check aContainingBlockBSize
// against NS_AUTOHEIGHT *and* unit against eStyleUnit_Percent or
// calc()s containing percents before calling this function.
// However, it would be much more likely to catch problems without
// the unit conditions.
// XXXldb Many callers pass a non-'auto' containing block height when
// according to CSS2.1 they should be passing 'auto'.
NS_PRECONDITION(NS_AUTOHEIGHT != aContainingBlockHeight ||
NS_PRECONDITION(NS_AUTOHEIGHT != aContainingBlockBSize ||
!aCoord.HasPercent(),
"unexpected containing block height");
"unexpected containing block block-size");
if (aCoord.IsCoordPercentCalcUnit()) {
return nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockHeight);
return nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockBSize);
}
NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
aCoord.GetUnit() == eStyleUnit_Auto,
"unexpected height value");
"unexpected block-size value");
return 0;
}
@ -4499,10 +4499,11 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
const nsStylePosition* stylePos = aFrame->StylePosition();
// If we're a flex item, we'll compute our size a bit differently.
bool isVertical = aWM.IsVertical();
const nsStyleCoord* inlineStyleCoord =
aWM.IsVertical() ? &stylePos->mHeight : &stylePos->mWidth;
isVertical ? &stylePos->mHeight : &stylePos->mWidth;
const nsStyleCoord* blockStyleCoord =
aWM.IsVertical() ? &stylePos->mWidth : &stylePos->mHeight;
isVertical ? &stylePos->mWidth : &stylePos->mHeight;
bool isFlexItem = aFrame->IsFlexItem();
bool isInlineFlexItem = false;
@ -4548,7 +4549,7 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
// or (a * b) / c (which are equivalent).
const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto;
const bool isAutoBSize = IsAutoHeight(*blockStyleCoord, aCBSize.BSize(aWM));
const bool isAutoBSize = IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
LogicalSize boxSizingAdjust(aWM);
switch (stylePos->mBoxSizing) {
@ -4565,16 +4566,19 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize;
if (!isAutoISize) {
iSize = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
iSize = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
boxSizingToMarginEdgeISize, *inlineStyleCoord);
}
if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None &&
const nsStyleCoord& maxISizeCoord =
isVertical ? stylePos->mMaxHeight : stylePos->mMaxWidth;
if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
!(isFlexItem && isInlineFlexItem)) {
maxISize = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
maxISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
boxSizingToMarginEdgeISize, stylePos->mMaxWidth);
boxSizingToMarginEdgeISize, maxISizeCoord);
} else {
maxISize = nscoord_MAX;
}
@ -4582,11 +4586,15 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
// NOTE: Flex items ignore their min & max sizing properties in their
// flex container's main-axis. (Those properties get applied later in
// the flexbox algorithm.)
if (stylePos->mMinWidth.GetUnit() != eStyleUnit_Auto &&
const nsStyleCoord& minISizeCoord =
isVertical ? stylePos->mMinHeight : stylePos->mMinWidth;
if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
!(isFlexItem && isInlineFlexItem)) {
minISize = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
minISize = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
aFrame, aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
boxSizingToMarginEdgeISize, stylePos->mMinWidth);
boxSizingToMarginEdgeISize, minISizeCoord);
} else {
// Treat "min-width: auto" as 0.
// NOTE: Technically, "auto" is supposed to behave like "min-content" on
@ -4597,25 +4605,29 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
}
if (!isAutoBSize) {
bSize = nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
*blockStyleCoord);
}
if (!IsAutoHeight(stylePos->mMaxHeight, aCBSize.BSize(aWM)) &&
const nsStyleCoord& maxBSizeCoord =
isVertical ? stylePos->mMaxWidth : stylePos->mMaxHeight;
if (!IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
!(isFlexItem && !isInlineFlexItem)) {
maxBSize = nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
stylePos->mMaxHeight);
maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM), maxBSizeCoord);
} else {
maxBSize = nscoord_MAX;
}
if (!IsAutoHeight(stylePos->mMinHeight, aCBSize.BSize(aWM)) &&
const nsStyleCoord& minBSizeCoord =
isVertical ? stylePos->mMinWidth : stylePos->mMinHeight;
if (!IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
!(isFlexItem && !isInlineFlexItem)) {
minBSize = nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
stylePos->mMinHeight);
minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM), minBSizeCoord);
} else {
minBSize = 0;
}
@ -4625,10 +4637,10 @@ nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE,
"Our containing block must not have unconstrained inline-size!");
const nsStyleCoord& isizeCoord(aWM.IsVertical() ?
aIntrinsicSize.height : aIntrinsicSize.width);
const nsStyleCoord& bsizeCoord(aWM.IsVertical() ?
aIntrinsicSize.width : aIntrinsicSize.height);
const nsStyleCoord& isizeCoord =
isVertical ? aIntrinsicSize.height : aIntrinsicSize.width;
const nsStyleCoord& bsizeCoord =
isVertical ? aIntrinsicSize.width : aIntrinsicSize.height;
bool hasIntrinsicISize, hasIntrinsicBSize;
nscoord intrinsicISize, intrinsicBSize;

View File

@ -1295,45 +1295,86 @@ public:
* and margin that goes outside the rect chosen by box-sizing.
* @param aCoord The width value to compute.
*/
// XXX to be removed
static nscoord ComputeWidthValue(
nsRenderingContext* aRenderingContext,
nsIFrame* aFrame,
nscoord aContainingBlockWidth,
nscoord aContentEdgeToBoxSizing,
nscoord aBoxSizingToMarginEdge,
const nsStyleCoord& aCoord);
const nsStyleCoord& aCoord)
{
return ComputeISizeValue(aRenderingContext,
aFrame,
aContainingBlockWidth,
aContentEdgeToBoxSizing,
aBoxSizingToMarginEdge,
aCoord);
}
static nscoord ComputeISizeValue(
nsRenderingContext* aRenderingContext,
nsIFrame* aFrame,
nscoord aContainingBlockISize,
nscoord aContentEdgeToBoxSizing,
nscoord aBoxSizingToMarginEdge,
const nsStyleCoord& aCoord);
/*
* Convert nsStyleCoord to nscoord when percentages depend on the
* containing block height.
*/
// XXX to be removed
static nscoord ComputeHeightDependentValue(
nscoord aContainingBlockHeight,
const nsStyleCoord& aCoord)
{
return ComputeBSizeDependentValue(aContainingBlockHeight, aCoord);
}
static nscoord ComputeBSizeDependentValue(
nscoord aContainingBlockBSize,
const nsStyleCoord& aCoord);
/*
* Likewise, but for 'height', 'min-height', or 'max-height'.
*/
// XXX to be removed
static nscoord ComputeHeightValue(nscoord aContainingBlockHeight,
nscoord aContentEdgeToBoxSizingBoxEdge,
const nsStyleCoord& aCoord)
{
MOZ_ASSERT(aContainingBlockHeight != nscoord_MAX || !aCoord.HasPercent(),
"caller must deal with %% of unconstrained height");
return ComputeBSizeValue(aContainingBlockHeight,
aContentEdgeToBoxSizingBoxEdge,
aCoord);
}
static nscoord ComputeBSizeValue(nscoord aContainingBlockBSize,
nscoord aContentEdgeToBoxSizingBoxEdge,
const nsStyleCoord& aCoord)
{
MOZ_ASSERT(aContainingBlockBSize != nscoord_MAX || !aCoord.HasPercent(),
"caller must deal with %% of unconstrained block-size");
MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
nscoord result =
nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockHeight);
nsRuleNode::ComputeCoordPercentCalc(aCoord, aContainingBlockBSize);
// Clamp calc(), and the subtraction for box-sizing.
return std::max(0, result - aContentEdgeToBoxSizingBoxEdge);
}
// XXX to be removed
static bool IsAutoHeight(const nsStyleCoord &aCoord, nscoord aCBHeight)
{
return IsAutoBSize(aCoord, aCBHeight);
}
static bool IsAutoBSize(const nsStyleCoord &aCoord, nscoord aCBBSize)
{
nsStyleUnit unit = aCoord.GetUnit();
return unit == eStyleUnit_Auto || // only for 'height'
unit == eStyleUnit_None || // only for 'max-height'
(aCBHeight == nscoord_MAX && aCoord.HasPercent());
(aCBBSize == nscoord_MAX && aCoord.HasPercent());
}
static bool IsPaddingZero(const nsStyleCoord &aCoord)

View File

@ -1752,6 +1752,12 @@ nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument,
return true;
}
static void
NotifyUIResolutionChanged(TabParent* aTabParent, void* aArg)
{
aTabParent->UIResolutionChanged();
}
void
nsPresContext::UIResolutionChangedInternal()
{
@ -1762,52 +1768,15 @@ nsPresContext::UIResolutionChangedInternal()
AppUnitsPerDevPixelChanged();
}
nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(mDocument->GetWindow()));
nsCOMPtr<nsIMessageBroadcaster> windowMM;
if (chromeWindow) {
chromeWindow->GetMessageManager(getter_AddRefs(windowMM));
}
if (windowMM) {
NotifyUIResolutionChanged(windowMM);
}
// Recursively notify all remote leaf descendants that the
// resolution of the user interface has changed.
nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
NotifyUIResolutionChanged, nullptr);
mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
nullptr);
}
void
nsPresContext::NotifyUIResolutionChanged(nsIMessageBroadcaster* aManager)
{
uint32_t tabChildCount = 0;
aManager->GetChildCount(&tabChildCount);
for (uint32_t j = 0; j < tabChildCount; ++j) {
nsCOMPtr<nsIMessageListenerManager> childMM;
aManager->GetChildAt(j, getter_AddRefs(childMM));
if (!childMM) {
continue;
}
nsCOMPtr<nsIMessageBroadcaster> nonLeafMM = do_QueryInterface(childMM);
if (nonLeafMM) {
NotifyUIResolutionChanged(nonLeafMM);
continue;
}
nsCOMPtr<nsIMessageSender> tabMM = do_QueryInterface(childMM);
mozilla::dom::ipc::MessageManagerCallback* cb =
static_cast<nsFrameMessageManager*>(tabMM.get())->GetCallback();
if (cb) {
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
PBrowserParent* remoteBrowser = fl->GetRemoteBrowser();
TabParent* remote = static_cast<TabParent*>(remoteBrowser);
if (remote) {
remote->UIResolutionChanged();
}
}
}
}
void
nsPresContext::EmulateMedium(const nsAString& aMediaType)
{

View File

@ -799,12 +799,6 @@ public:
*/
void UIResolutionChanged();
/**
* Recursively notify all remote leaf descendants of a given message manager
* that the resolution of the user interface has changed.
*/
void NotifyUIResolutionChanged(nsIMessageBroadcaster* aManager);
/*
* Notify the pres context that a system color has changed
*/

View File

@ -50,7 +50,7 @@
#include "mozilla/dom/ScriptSettings.h"
#include "nsDocShell.h"
#include "nsISimpleEnumerator.h"
#include "nsJSEnvironment.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
@ -1369,6 +1369,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
if (nsContentUtils::XPConnect()) {
nsContentUtils::XPConnect()->NotifyDidPaint();
nsJSContext::NotifyDidPaint();
}
}

View File

@ -4139,15 +4139,12 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
boxSizingAdjust.ISize(aWM);
const nsStyleCoord* inlineStyleCoord;
const nsStyleCoord* blockStyleCoord;
if (aWM.IsVertical()) {
inlineStyleCoord = &(stylePos->mHeight);
blockStyleCoord = &(stylePos->mWidth);
} else {
inlineStyleCoord = &(stylePos->mWidth);
blockStyleCoord = &(stylePos->mHeight);
}
bool isVertical = aWM.IsVertical();
const nsStyleCoord* inlineStyleCoord =
isVertical ? &(stylePos->mHeight) : &(stylePos->mWidth);
const nsStyleCoord* blockStyleCoord =
isVertical ? &(stylePos->mWidth) : &(stylePos->mHeight);
bool isFlexItem = IsFlexItem();
bool isInlineFlexItem = false;
@ -4188,30 +4185,36 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
if (inlineStyleCoord->GetUnit() != eStyleUnit_Auto) {
result.ISize(aWM) =
nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
nsLayoutUtils::ComputeISizeValue(aRenderingContext, this,
aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
*inlineStyleCoord);
}
const nsStyleCoord& maxISizeCoord =
isVertical ? stylePos->mMaxHeight : stylePos->mMaxWidth;
// Flex items ignore their min & max sizing properties in their
// flex container's main-axis. (Those properties get applied later in
// the flexbox algorithm.)
if (stylePos->mMaxWidth.GetUnit() != eStyleUnit_None &&
if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
!(isFlexItem && isInlineFlexItem)) {
nscoord maxISize =
nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
nsLayoutUtils::ComputeISizeValue(aRenderingContext, this,
aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
stylePos->mMaxWidth);
maxISizeCoord);
result.ISize(aWM) = std::min(maxISize, result.ISize(aWM));
}
const nsStyleCoord& minISizeCoord =
isVertical ? stylePos->mMinHeight : stylePos->mMinWidth;
nscoord minISize;
if (stylePos->mMinWidth.GetUnit() != eStyleUnit_Auto &&
if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
!(isFlexItem && isInlineFlexItem)) {
minISize =
nsLayoutUtils::ComputeWidthValue(aRenderingContext, this,
nsLayoutUtils::ComputeISizeValue(aRenderingContext, this,
aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
stylePos->mMinWidth);
minISizeCoord);
} else {
// Treat "min-width: auto" as 0.
// NOTE: Technically, "auto" is supposed to behave like "min-content" on
@ -4226,30 +4229,36 @@ nsFrame::ComputeSize(nsRenderingContext *aRenderingContext,
// (but not if we're auto-height or if we recieved the "eUseAutoHeight"
// flag -- then, we'll just stick with the height that we already calculated
// in the initial ComputeAutoSize() call.)
if (!nsLayoutUtils::IsAutoHeight(*blockStyleCoord, aCBSize.BSize(aWM)) &&
if (!nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM)) &&
!(aFlags & nsIFrame::eUseAutoHeight)) {
result.BSize(aWM) =
nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
*blockStyleCoord);
nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
*blockStyleCoord);
}
const nsStyleCoord& maxBSizeCoord =
isVertical ? stylePos->mMaxWidth : stylePos->mMaxHeight;
if (result.BSize(aWM) != NS_UNCONSTRAINEDSIZE) {
if (!nsLayoutUtils::IsAutoHeight(stylePos->mMaxHeight, aCBSize.BSize(aWM)) &&
if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
!(isFlexItem && !isInlineFlexItem)) {
nscoord maxBSize =
nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
stylePos->mMaxHeight);
nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
maxBSizeCoord);
result.BSize(aWM) = std::min(maxBSize, result.BSize(aWM));
}
if (!nsLayoutUtils::IsAutoHeight(stylePos->mMinHeight, aCBSize.BSize(aWM)) &&
const nsStyleCoord& minBSizeCoord =
isVertical ? stylePos->mMinWidth : stylePos->mMinHeight;
if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
!(isFlexItem && !isInlineFlexItem)) {
nscoord minBSize =
nsLayoutUtils::ComputeHeightValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
stylePos->mMinHeight);
nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
minBSizeCoord);
result.BSize(aWM) = std::max(minBSize, result.BSize(aWM));
}
}

View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.wrapper {
display: inline-block;
vertical-align: top;
margin: 20px;
}
.outer {
height: 250px;
width: 200px;
border: 10px solid #ddd;
}
.inner {
font: 12px monospace;
background: yellow;
overflow: hidden;
}
.test1 {
width: 180px;
height: 150px;
}
.test2 {
width: 150px;
height: 200px;
}
.lr {
writing-mode: vertical-lr;
}
.rl {
writing-mode: vertical-rl;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<div class="inner test1 lr">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
<br>
<div class="wrapper">
<div class="outer">
<div class="inner test2 lr">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.wrapper {
display: inline-block;
vertical-align: top;
margin: 20px;
}
.outer {
height: 250px;
width: 200px;
border: 10px solid #ddd;
}
.inner {
font: 12px monospace;
background: yellow;
overflow: hidden;
}
.test1 {
min-width: 180px;
max-width: 180px;
min-height: 150px;
max-height: 150px;
}
.test2 {
min-width: 150px;
max-width: 150px;
min-height: 200px;
max-height: 200px;
}
.lr {
writing-mode: vertical-lr;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<div class="inner test1 lr">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
<br>
<div class="wrapper">
<div class="outer">
<div class="inner test2 lr">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.wrapper {
display: inline-block;
vertical-align: top;
margin: 20px;
}
.outer {
height: 250px;
width: 200px;
border: 10px solid #ddd;
}
.inner {
overflow: hidden;
background: yellow;
}
.test1 {
width: 100px;
height: 150px;
}
.test2 {
width: 150px;
height: 100px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<img class="inner test1" src="foo">
</div>
</div>
<div class="wrapper">
<div class="outer">
<img class="inner test1" src="foo">
</div>
</div>
<br>
<div class="wrapper">
<div class="outer">
<img class="inner test2" src="foo">
</div>
</div>
<div class="wrapper">
<div class="outer">
<img class="inner test2" src="foo">
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.wrapper {
display: inline-block;
vertical-align: top;
margin: 20px;
}
.outer {
height: 250px;
width: 200px;
border: 10px solid #ddd;
}
.inner {
overflow: hidden;
background: yellow;
}
.test1 {
min-width: 100px;
max-width: 100px;
min-height: 150px;
max-height: 150px;
}
.test2 {
min-width: 150px;
max-width: 150px;
min-height: 100px;
max-height: 100px;
}
.lr {
writing-mode: vertical-lr;
}
.rl {
writing-mode: vertical-rl;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<img class="inner test1 lr" src="foo">
</div>
</div>
<div class="wrapper">
<div class="outer">
<img class="inner test1 rl" src="foo">
</div>
</div>
<br>
<div class="wrapper">
<div class="outer">
<img class="inner test2 lr" src="foo">
</div>
</div>
<div class="wrapper">
<div class="outer">
<img class="inner test2 rl" src="foo">
</div>
</div>
</body>
</html>

View File

@ -25,3 +25,5 @@ random-if(gtk2Widget) == 1094434-2.html 1094434-2-ref.html # bug 1094845
== 1096224-1a.html 1096224-1-ref.html
== 1096224-1b.html 1096224-1-ref.html
== 1103613-1.html 1103613-1-ref.html
== 1105268-1-min-max-dimensions.html 1105268-1-min-max-dimensions-ref.html
== 1105268-2-min-max-dimensions.html 1105268-2-min-max-dimensions-ref.html

View File

@ -523,6 +523,12 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end,
return codedBands;
}
#if !defined(__clang__) && defined(__GNUC__) && defined(__arm__) && \
__GNUC__ == 4 && __GNUC_MINOR__ == 8
#warning "OPUS library causes an internal compiler error for gcc-4.8 based toolchain in arm"
#pragma GCC push_options
#pragma GCC optimize ("O0")
#endif
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
{
@ -635,4 +641,7 @@ int compute_allocation(const CELTMode *m, int start, int end, const int *offsets
RESTORE_STACK;
return codedBands;
}
#if !defined(__clang__) && defined(__GNUC__) && defined(__arm__) && \
__GNUC__ == 4 && __GNUC_MINOR__ == 8
#pragma GCC pop_options
#endif

View File

@ -0,0 +1,39 @@
From 609166a46f6a22ae2d0a0ab7c64415c779c65f37 Mon Sep 17 00:00:00 2001
From: Juan Gomez <atilag@gmail.com>
Date: Wed, 26 Nov 2014 23:57:49 +0100
Subject: [PATCH] Bug 1056337 - Upgrade toolchain used for B2G ICS builds *
Patch for gcc ICE in OPUS library (arm)
---
media/libopus/celt/rate.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/media/libopus/celt/rate.c b/media/libopus/celt/rate.c
index e13d839..1055e63 100644
--- a/media/libopus/celt/rate.c
+++ b/media/libopus/celt/rate.c
@@ -523,6 +523,12 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end,
return codedBands;
}
+#if !defined(__clang__) && defined(__GNUC__) && defined(__arm__) && \
+ __GNUC__ == 4 && __GNUC_MINOR__ == 8
+#warning "OPUS library causes an internal compiler error for gcc-4.8 based toolchain in arm"
+#pragma GCC push_options
+#pragma GCC optimize ("O0")
+#endif
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
{
@@ -635,4 +641,7 @@ int compute_allocation(const CELTMode *m, int start, int end, const int *offsets
RESTORE_STACK;
return codedBands;
}
-
+#if !defined(__clang__) && defined(__GNUC__) && defined(__arm__) && \
+ __GNUC__ == 4 && __GNUC_MINOR__ == 8
+#pragma GCC pop_options
+#endif
--
2.1.0

View File

@ -74,4 +74,4 @@ sed -e "s/DEFINES\['OPUS_VERSION'\][ \t]*=[ \t]*'\".*\"'/DEFINES['OPUS_VERSION']
python gen-sources.py $1
# apply outstanding local patches
# ... no patches to apply ...
patch -p3 < ./gcc-4.8-ICE.patch

View File

@ -3569,14 +3569,17 @@ pref("font.name.monospace.x-western", "Fira Mono");
pref("font.name.serif.zh-CN", "Charis SIL Compact");
pref("font.name.sans-serif.zh-CN", "Fira Sans");
pref("font.name.monospace.zh-CN", "Fira Mono");
pref("font.name-list.sans-serif.zh-CN", "Fira Sans,Droid Sans Fallback");
pref("font.name.serif.zh-HK", "Charis SIL Compact");
pref("font.name.sans-serif.zh-HK", "Fira Sans");
pref("font.name.monospace.zh-HK", "Fira Mono");
pref("font.name-list.sans-serif.zh-HK", "Fira Sans,Droid Sans Fallback");
pref("font.name.serif.zh-TW", "Charis SIL Compact");
pref("font.name.sans-serif.zh-TW", "Fira Sans");
pref("font.name.monospace.zh-TW", "Fira Mono");
pref("font.name-list.sans-serif.zh-TW", "Fira Sans,Droid Sans Fallback");
#elif defined(ANDROID)
// We use the bundled fonts for Firefox for Android

View File

@ -490,6 +490,8 @@ class CCacheStats(object):
]
DIRECTORY_DESCRIPTION = "cache directory"
PRIMARY_CONFIG_DESCRIPTION = "primary config"
SECONDARY_CONFIG_DESCRIPTION = "secondary config (readonly)"
ABSOLUTE_KEYS = {'cache_max_size'}
FORMAT_KEYS = {'cache_size', 'cache_max_size'}
@ -501,6 +503,8 @@ class CCacheStats(object):
"""Construct an instance from the output of ccache -s."""
self._values = {}
self.cache_dir = ""
self.primary_config = ""
self.secondary_config = ""
if not output:
return
@ -513,15 +517,20 @@ class CCacheStats(object):
def _parse_line(self, line):
if line.startswith(self.DIRECTORY_DESCRIPTION):
self.cache_dir = self._strip_prefix(line, self.DIRECTORY_DESCRIPTION)
return
for stat_key, stat_description in self.STATS_KEYS:
if line.startswith(stat_description):
raw_value = self._strip_prefix(line, stat_description)
self._values[stat_key] = self._parse_value(raw_value)
break
elif line.startswith(self.PRIMARY_CONFIG_DESCRIPTION):
self.primary_config = self._strip_prefix(
line, self.PRIMARY_CONFIG_DESCRIPTION)
elif line.startswith(self.SECONDARY_CONFIG_DESCRIPTION):
self.secondary_config = self._strip_prefix(
line, self.SECONDARY_CONFIG_DESCRIPTION)
else:
raise ValueError('Failed to parse ccache stats output: %s' % line)
for stat_key, stat_description in self.STATS_KEYS:
if line.startswith(stat_description):
raw_value = self._strip_prefix(line, stat_description)
self._values[stat_key] = self._parse_value(raw_value)
break
else:
raise ValueError('Failed to parse ccache stats output: %s' % line)
@staticmethod
def _strip_prefix(line, prefix):

View File

@ -59,6 +59,27 @@ class TestCcacheStats(unittest.TestCase):
cache size 2.0 Gbytes
max cache size 16.0 Gbytes"""
STAT3 = """
cache directory /Users/tlin/.ccache
primary config /Users/tlin/.ccache/ccache.conf
secondary config (readonly) /usr/local/Cellar/ccache/3.2/etc/ccache.conf
cache hit (direct) 12004
cache hit (preprocessed) 1786
cache miss 26348
called for link 2338
called for preprocessing 6313
compile failed 399
preprocessor error 390
bad compiler arguments 86
unsupported source language 66
autoconf compile/link 2439
unsupported compiler option 187
no input file 1068
files in cache 18044
cache size 7.5 GB
max cache size 8.6 GB
"""
def test_parse_garbage_stats_message(self):
self.assertRaises(ValueError, CCacheStats, self.STAT_GARBAGE)
@ -88,6 +109,13 @@ class TestCcacheStats(unittest.TestCase):
self.assertFalse(stats_diff_negative1)
self.assertFalse(stats_diff_negative2)
def test_stats_version32(self):
stat2 = CCacheStats(self.STAT2)
stat3 = CCacheStats(self.STAT3)
stats_diff = stat3 - stat2
self.assertTrue(stat3)
self.assertTrue(stats_diff)
if __name__ == '__main__':
main()

View File

@ -1210,9 +1210,9 @@ retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
.forgetIntolerance(socketInfo->GetHostName(), socketInfo->GetPort());
return false;
} else if ((err == SSL_ERROR_NO_CYPHER_OVERLAP ||
err == PR_END_OF_FILE_ERROR) &&
nsNSSComponent::AreAnyWeakCiphersEnabled()) {
}
if ((err == SSL_ERROR_NO_CYPHER_OVERLAP || err == PR_END_OF_FILE_ERROR) &&
nsNSSComponent::AreAnyWeakCiphersEnabled()) {
if (socketInfo->SharedState().IOLayerHelpers()
.rememberStrongCiphersFailed(socketInfo->GetHostName(),
socketInfo->GetPort(), err)) {

View File

@ -33,7 +33,11 @@ TEST_F(TLSIntoleranceTest, Test_Full_Fallback_Process)
ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
ASSERT_EQ(StrongCipherStatusUnknown, strongCipherStatus);
ASSERT_TRUE(helpers.rememberStrongCiphersFailed(HOST, PORT, 0));
ASSERT_TRUE(
helpers.rememberStrongCiphersFailed(
HOST, PORT, SSL_ERROR_NO_CYPHER_OVERLAP));
ASSERT_EQ(SSL_ERROR_NO_CYPHER_OVERLAP,
helpers.getIntoleranceReason(HOST, PORT));
}
{

View File

@ -37,68 +37,67 @@ MobileIdentityVerificationFlow.prototype = {
return Promise.reject(ERROR_INTERNAL_UNEXPECTED);
}
this.sessionToken = registerResult.msisdnSessionToken;
return this._doVerification();
// We save the timestamp of the start of the verification timeout to be
// able to provide to the UI the remaining time on each retry.
if (!this.timer) {
log.debug("Creating verification code timer");
this.timerCreation = Date.now();
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(this.onVerificationCodeTimeout.bind(this),
VERIFICATIONCODE_TIMEOUT,
this.timer.TYPE_ONE_SHOT);
}
if (!this.verifyStrategy) {
return Promise.reject(ERROR_INTERNAL_INVALID_VERIFICATION_FLOW);
}
return this.verifyStrategy()
.then(() => {
return this._doVerification();
}, (reason) => {
this.verificationCodeDeferred.reject(reason);
});
}
)
},
_doVerification: function() {
log.debug("_doVerification");
// We save the timestamp of the start of the verification timeout to be
// able to provide to the UI the remaining time on each retry.
if (!this.timer) {
log.debug("Creating verification code timer");
this.timerCreation = Date.now();
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(this.onVerificationCodeTimeout.bind(this),
VERIFICATIONCODE_TIMEOUT,
this.timer.TYPE_ONE_SHOT);
}
if (!this.verifyStrategy) {
return Promise.reject(ERROR_INTERNAL_INVALID_VERIFICATION_FLOW);
}
this.verificationCodeDeferred = Promise.defer();
this.verifyStrategy()
.then(
() => {
// If the verification flow can be for an external phone number,
// we need to ask the user for the verification code.
// In that case we don't do a notification about the verification
// process being done until the user enters the verification code
// in the UI.
if (this.verificationOptions.external) {
let timeLeft = 0;
if (this.timer) {
timeLeft = this.timerCreation + VERIFICATIONCODE_TIMEOUT -
Date.now();
}
this.ui.verificationCodePrompt(this.retries,
VERIFICATIONCODE_TIMEOUT / 1000,
timeLeft / 1000)
.then(
(verificationCode) => {
if (!verificationCode) {
return this.verificationCodeDeferred.reject(
ERROR_INTERNAL_INVALID_PROMPT_RESULT);
}
// If the user got the verification code that means that the
// introduced phone number didn't belong to any of the inserted
// SIMs.
this.ui.verify();
this.verificationCodeDeferred.resolve(verificationCode);
}
);
} else {
this.ui.verify();
}
},
(reason) => {
this.verificationCodeDeferred.reject(reason);
// If the verification flow can be for an external phone number,
// we need to ask the user for the verification code.
// In that case we don't do a notification about the verification
// process being done until the user enters the verification code
// in the UI.
if (this.verificationOptions.external) {
let timeLeft = 0;
if (this.timer) {
timeLeft = this.timerCreation + VERIFICATIONCODE_TIMEOUT -
Date.now();
}
);
this.ui.verificationCodePrompt(this.retries,
VERIFICATIONCODE_TIMEOUT / 1000,
timeLeft / 1000)
.then(
(verificationCode) => {
if (!verificationCode) {
return this.verificationCodeDeferred.reject(
ERROR_INTERNAL_INVALID_PROMPT_RESULT);
}
// If the user got the verification code that means that the
// introduced phone number didn't belong to any of the inserted
// SIMs.
this.ui.verify();
this.verificationCodeDeferred.resolve(verificationCode);
}
);
} else {
this.ui.verify();
}
return this.verificationCodeDeferred.promise.then(
this.onVerificationCode.bind(this)
);
@ -145,8 +144,11 @@ MobileIdentityVerificationFlow.prototype = {
log.error("Retries left " + this.retries);
if (!this.retries) {
this.ui.error(ERROR_NO_RETRIES_LEFT);
this.timer.cancel();
this.timer = null;
return Promise.reject(ERROR_NO_RETRIES_LEFT);
}
this.ui.error(ERROR_INVALID_VERIFICATION_CODE);
this.verifying = false;
if (this.queuedTimeout) {
this.onVerificationCodeTimeout();

View File

@ -5,6 +5,8 @@ const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
"use strict";
const Cm = Components.manager;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -17,3 +19,444 @@ Cu.import("resource://gre/modules/Services.jsm");
Services.prefs.setCharPref("services.mobileid.server.uri",
"https://dummyurl.com");
}).call(this);
const DEBUG = false;
const GET_ASSERTION_IPC_MSG = "MobileId:GetAssertion";
const GET_ASSERTION_RETURN_OK = "MobileId:GetAssertion:Return:OK";
const GET_ASSERTION_RETURN_KO = "MobileId:GetAssertion:Return:KO";
// === Globals ===
const ORIGIN = "app://afakeorigin";
const APP_ID = 1;
const PRINCIPAL = {
origin: ORIGIN,
appId: APP_ID
};
const PHONE_NUMBER = "+34666555444";
const ANOTHER_PHONE_NUMBER = "+44123123123";
const VERIFICATION_CODE = "123456";
const SESSION_TOKEN = "aSessionToken";
const ICC_ID = "aIccId";
const ANOTHER_ICC_ID = "anotherIccId";
const MNC = "aMnc";
const ANOTHER_MNC = "anotherMnc";
const MCC = "aMcc";
const ANOTHER_MCC = "anotherMcc";
const OPERATOR = "aOperator";
const ANOTHER_OPERATOR = "anotherOperator";
const RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: ICC_ID,
mcc: MCC,
mnc: MNC,
msisdn: PHONE_NUMBER,
operator: OPERATOR
}
},
voice: {
network: {
shortName: OPERATOR
},
roaming: false
},
data: {
network: {
shortName: OPERATOR
}
}
};
const ANOTHER_RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: ANOTHER_ICC_ID,
mcc: ANOTHER_MCC,
mnc: ANOTHER_MNC,
msisdn: ANOTHER_PHONE_NUMBER,
operator: ANOTHER_OPERATOR
}
},
voice: {
network: {
shortName: ANOTHER_OPERATOR
},
roaming: false
},
data: {
network: {
shortName: ANOTHER_OPERATOR
}
}
};
const INVALID_RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: null,
mcc: "",
mnc: "",
msisdn: "",
operator: ""
}
},
voice: {
network: {
shortName: ""
},
roaming: undefined
},
data: {
network: {
shortName: ""
}
}
};
const CERTIFICATE = "eyJhbGciOiJEUzI1NiJ9.eyJsYXN0QXV0aEF0IjoxNDA0NDY5NzkyODc3LCJ2ZXJpZmllZE1TSVNETiI6IiszMTYxNzgxNTc1OCIsInB1YmxpYy1rZXkiOnsiYWxnb3JpdGhtIjoiRFMiLCJ5IjoiNGE5YzkzNDY3MWZhNzQ3YmM2ZjMyNjE0YTg1MzUyZjY5NDcwMDdhNTRkMDAxMDY4OWU5ZjJjZjc0ZGUwYTEwZTRlYjlmNDk1ZGFmZTA0NGVjZmVlNDlkN2YwOGU4ODQyMDJiOTE5OGRhNWZhZWE5MGUzZjRmNzE1YzZjNGY4Yjc3MGYxZTU4YWZhNDM0NzVhYmFiN2VlZGE1MmUyNjk2YzFmNTljNzMzYjFlYzBhNGNkOTM1YWIxYzkyNzAxYjNiYTA5ZDRhM2E2MzNjNTJmZjE2NGYxMWY3OTg1YzlmZjY3ZThmZDFlYzA2NDU3MTdkMjBiNDE4YmM5M2YzYzVkNCIsInAiOiJmZjYwMDQ4M2RiNmFiZmM1YjQ1ZWFiNzg1OTRiMzUzM2Q1NTBkOWYxYmYyYTk5MmE3YThkYWE2ZGMzNGY4MDQ1YWQ0ZTZlMGM0MjlkMzM0ZWVlYWFlZmQ3ZTIzZDQ4MTBiZTAwZTRjYzE0OTJjYmEzMjViYTgxZmYyZDVhNWIzMDVhOGQxN2ViM2JmNGEwNmEzNDlkMzkyZTAwZDMyOTc0NGE1MTc5MzgwMzQ0ZTgyYTE4YzQ3OTMzNDM4Zjg5MWUyMmFlZWY4MTJkNjljOGY3NWUzMjZjYjcwZWEwMDBjM2Y3NzZkZmRiZDYwNDYzOGMyZWY3MTdmYzI2ZDAyZTE3IiwicSI6ImUyMWUwNGY5MTFkMWVkNzk5MTAwOGVjYWFiM2JmNzc1OTg0MzA5YzMiLCJnIjoiYzUyYTRhMGZmM2I3ZTYxZmRmMTg2N2NlODQxMzgzNjlhNjE1NGY0YWZhOTI5NjZlM2M4MjdlMjVjZmE2Y2Y1MDhiOTBlNWRlNDE5ZTEzMzdlMDdhMmU5ZTJhM2NkNWRlYTcwNGQxNzVmOGViZjZhZjM5N2Q2OWUxMTBiOTZhZmIxN2M3YTAzMjU5MzI5ZTQ4MjliMGQwM2JiYzc4OTZiMTViNGFkZTUzZTEzMDg1OGNjMzRkOTYyNjlhYTg5MDQxZjQwOTEzNmM3MjQyYTM4ODk1YzlkNWJjY2FkNGYzODlhZjFkN2E0YmQxMzk4YmQwNzJkZmZhODk2MjMzMzk3YSJ9LCJwcmluY2lwYWwiOiIwMzgxOTgyYS0xZTgzLTI1NjYtNjgzZS05MDRmNDA0NGM1MGRAbXNpc2RuLWRldi5zdGFnZS5tb3phd3MubmV0IiwiaWF0IjoxNDA0NDY5NzgyODc3LCJleHAiOjE0MDQ0OTEzOTI4NzcsImlzcyI6Im1zaXNkbi1kZXYuc3RhZ2UubW96YXdzLm5ldCJ9."
// === Helpers ===
function addPermission(aAction) {
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(ORIGIN, null, null);
let _principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getAppCodebasePrincipal(uri, APP_ID, false);
let pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
pm.addFromPrincipal(_principal, MOBILEID_PERM, aAction);
}
function removePermission() {
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(ORIGIN, null, null);
let _principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getAppCodebasePrincipal(uri, APP_ID, false);
let pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
pm.removeFromPrincipal(_principal, MOBILEID_PERM);
}
// === Mocks ===
let Mock = function(aOptions) {
if (!aOptions) {
aOptions = {};
}
this._options = aOptions;
this._spied = {};
};
Mock.prototype = {
_: function(aMethod) {
DEBUG && do_print("_ " + aMethod + JSON.stringify(this._spied));
let self = this;
return {
callsLength: function(aNumberOfCalls) {
if (aNumberOfCalls == 0) {
do_check_eq(self._spied[aMethod], undefined);
return;
}
do_check_eq(self._spied[aMethod].length, aNumberOfCalls);
},
call: function(aCallNumber) {
return {
arg: function(aArgNumber, aValue) {
let _arg = self._spied[aMethod][aCallNumber - 1][aArgNumber - 1];
if (Array.isArray(aValue)) {
do_check_eq(_arg.length, aValue.length)
for (let i = 0; i < _arg.length; i++) {
do_check_eq(_arg[i], aValue[i]);
}
return;
}
if (typeof aValue === 'object') {
do_check_eq(JSON.stringify(_arg), JSON.stringify(aValue));
return;
}
do_check_eq(_arg, aValue);
}
}
}
}
},
_spy: function(aMethod, aArgs) {
DEBUG && do_print(aMethod + " - " + JSON.stringify(aArgs));
if (!this._spied[aMethod]) {
this._spied[aMethod] = [];
}
this._spied[aMethod].push(aArgs);
},
getSpiedCalls: function(aMethod) {
return this._spied[aMethod];
}
};
// UI Glue mock up.
let MockUi = function(aOptions) {
Mock.call(this, aOptions);
};
MockUi.prototype = {
__proto__: Mock.prototype,
_startFlowResult: {
phoneNumber: PHONE_NUMBER,
mcc: MNC
},
_verifyCodePromptResult: {
verificationCode: VERIFICATION_CODE
},
startFlow: function() {
this._spy("startFlow", arguments);
return Promise.resolve(this._options.startFlowResult ||
this._startFlowResult);
},
verificationCodePrompt: function() {
this._spy("verifyCodePrompt", arguments);
return Promise.resolve(this._options.verificationCodePromptResult ||
this._verifyCodePromptResult);
},
verify: function() {
this._spy("verify", arguments);
},
error: function() {
this._spy("error", arguments);
},
verified: function() {
this._spy("verified", arguments);
},
set oncancel(aCallback) {
},
set onresendcode(aCallback) {
}
};
// Credentials store mock up.
let MockCredStore = function(aOptions) {
Mock.call(this, aOptions);
};
MockCredStore.prototype = {
__proto__: Mock.prototype,
_getByOriginResult: null,
_getByMsisdnResult: null,
_getByIccIdResult: null,
getByOrigin: function() {
this._spy("getByOrigin", arguments);
let result = this._getByOriginResult;
if (this._options.getByOriginResult) {
if (Array.isArray(this._options.getByOriginResult)) {
result = this._options.getByOriginResult.length ?
this._options.getByOriginResult.shift() : null;
} else {
result = this._options.getByOriginResult;
}
}
return Promise.resolve(result);
},
getByMsisdn: function() {
this._spy("getByMsisdn", arguments);
return Promise.resolve(this._options.getByMsisdnResult ||
this._getByMsisdnResult);
},
getByIccId: function() {
this._spy("getByIccId", arguments);
return Promise.resolve(this._options.getByIccIdResult ||
this._getByIccIdResult);
},
add: function() {
this._spy("add", arguments);
return Promise.resolve();
},
setDeviceIccIds: function() {
this._spy("setDeviceIccIds", arguments);
return Promise.resolve();
},
removeOrigin: function() {
this._spy("removeOrigin", arguments);
return Promise.resolve();
},
delete: function() {
this._spy("delete", arguments);
return Promise.resolve();
}
};
// Client mock up.
let MockClient = function(aOptions) {
Mock.call(this, aOptions);
};
MockClient.prototype = {
__proto__: Mock.prototype,
_discoverResult: {
verificationMethods: ["sms/mt"],
verificationDetails: {
"sms/mt": {
mtSender: "123",
url: "https://msisdn.accounts.firefox.com/v1/msisdn/sms/mt/verify"
}
}
},
_registerResult: {
msisdnSessionToken: SESSION_TOKEN
},
_smsMtVerifyResult: {},
_verifyCodeResult: {
msisdn: PHONE_NUMBER
},
_signResult: {
cert: CERTIFICATE
},
hawk: {
now: function() {
return Date.now();
}
},
discover: function() {
this._spy("discover", arguments);
return Promise.resolve(this._options.discoverResult ||
this._discoverResult);
},
register: function() {
this._spy("register", arguments);
return Promise.resolve(this._options.registerResult ||
this._registerResult);
},
smsMtVerify: function() {
this._spy("smsMtVerify", arguments);
return Promise.resolve(this._options.smsMtVerifyResult ||
this._smsMtVerifyResult);
},
verifyCode: function() {
this._spy("verifyCode", arguments);
if (this._options.verifyCodeError) {
let error = Array.isArray(this._options.verifyCodeError) ?
this._options.verifyCodeError.shift() :
this._options.verifyCodeError;
if (!this._options.verifyCodeError.length) {
this._options.verifyCodeError = null;
}
return Promise.reject(error);
}
return Promise.resolve(this._options.verifyCodeResult ||
this._verifyCodeResult);
},
sign: function() {
this._spy("sign", arguments);
if (this._options.signError) {
let error = Array.isArray(this._options.signError) ?
this._options.signError.shift() :
this._options.signError;
return Promise.reject(error);
}
return Promise.resolve(this._options.signResult || this._signResult);
}
};
// Override MobileIdentityUIGlue.
const kMobileIdentityUIGlueUUID = "{05df0566-ca8a-4ec7-bc76-78626ebfbe9a}";
const kMobileIdentityUIGlueContractID =
"@mozilla.org/services/mobileid-ui-glue;1";
// Save original factory.
/*const kMobileIdentityUIGlueFactory =
Cm.getClassObject(Cc[kMobileIdentityUIGlueContractID], Ci.nsIFactory);*/
let fakeMobileIdentityUIGlueFactory = {
createInstance: function(aOuter, aIid) {
return MobileIdentityUIGlue.QueryInterface(aIid);
}
};
// MobileIdentityUIGlue fake component.
let MobileIdentityUIGlue = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileIdentityUIGlue]),
};
(function registerFakeMobileIdentityUIGlue() {
Cm.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(Components.ID(kMobileIdentityUIGlueUUID),
"MobileIdentityUIGlue",
kMobileIdentityUIGlueContractID,
fakeMobileIdentityUIGlueFactory);
})();
// The tests rely on having an app registered. Otherwise, it will throw.
// Override XULAppInfo.
const XUL_APP_INFO_UUID = Components.ID("{84fdc459-d96d-421c-9bff-a8193233ae75}");
const XUL_APP_INFO_CONTRACT_ID = "@mozilla.org/xre/app-info;1";
let (XULAppInfo = {
vendor: "Mozilla",
name: "MobileIdTest",
ID: "{230de50e-4cd1-11dc-8314-0800200b9a66}",
version: "1",
appBuildID: "2007010101",
platformVersion: "",
platformBuildID: "2007010101",
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIXULAppInfo,
Ci.nsIXULRuntime,
])
}) {
let XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return XULAppInfo.QueryInterface(iid);
}
};
Cm.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(XUL_APP_INFO_UUID,
"XULAppInfo",
XUL_APP_INFO_CONTRACT_ID,
XULAppInfoFactory);
}

View File

@ -3,424 +3,16 @@
"use strict";
const Cm = Components.manager;
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/MobileIdentityManager.jsm");
Cu.import("resource://gre/modules/MobileIdentityCommon.jsm");
const DEBUG = false;
const GET_ASSERTION_IPC_MSG = "MobileId:GetAssertion";
const GET_ASSERTION_RETURN_OK = "MobileId:GetAssertion:Return:OK";
const GET_ASSERTION_RETURN_KO = "MobileId:GetAssertion:Return:KO";
// === Globals ===
const ORIGIN = "app://afakeorigin";
const APP_ID = 1;
const PRINCIPAL = {
origin: ORIGIN,
appId: APP_ID
};
const PHONE_NUMBER = "+34666555444";
const ANOTHER_PHONE_NUMBER = "+44123123123";
const VERIFICATION_CODE = "123456";
const SESSION_TOKEN = "aSessionToken";
const ICC_ID = "aIccId";
const ANOTHER_ICC_ID = "anotherIccId";
const MNC = "aMnc";
const ANOTHER_MNC = "anotherMnc";
const MCC = "aMcc";
const ANOTHER_MCC = "anotherMcc";
const OPERATOR = "aOperator";
const ANOTHER_OPERATOR = "anotherOperator";
const RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: ICC_ID,
mcc: MCC,
mnc: MNC,
msisdn: PHONE_NUMBER,
operator: OPERATOR
}
},
voice: {
network: {
shortName: OPERATOR
},
roaming: false
},
data: {
network: {
shortName: OPERATOR
}
}
};
const ANOTHER_RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: ANOTHER_ICC_ID,
mcc: ANOTHER_MCC,
mnc: ANOTHER_MNC,
msisdn: ANOTHER_PHONE_NUMBER,
operator: ANOTHER_OPERATOR
}
},
voice: {
network: {
shortName: ANOTHER_OPERATOR
},
roaming: false
},
data: {
network: {
shortName: ANOTHER_OPERATOR
}
}
};
const INVALID_RADIO_INTERFACE = {
rilContext: {
iccInfo: {
iccid: null,
mcc: "",
mnc: "",
msisdn: "",
operator: ""
}
},
voice: {
network: {
shortName: ""
},
roaming: undefined
},
data: {
network: {
shortName: ""
}
}
};
const CERTIFICATE = "eyJhbGciOiJEUzI1NiJ9.eyJsYXN0QXV0aEF0IjoxNDA0NDY5NzkyODc3LCJ2ZXJpZmllZE1TSVNETiI6IiszMTYxNzgxNTc1OCIsInB1YmxpYy1rZXkiOnsiYWxnb3JpdGhtIjoiRFMiLCJ5IjoiNGE5YzkzNDY3MWZhNzQ3YmM2ZjMyNjE0YTg1MzUyZjY5NDcwMDdhNTRkMDAxMDY4OWU5ZjJjZjc0ZGUwYTEwZTRlYjlmNDk1ZGFmZTA0NGVjZmVlNDlkN2YwOGU4ODQyMDJiOTE5OGRhNWZhZWE5MGUzZjRmNzE1YzZjNGY4Yjc3MGYxZTU4YWZhNDM0NzVhYmFiN2VlZGE1MmUyNjk2YzFmNTljNzMzYjFlYzBhNGNkOTM1YWIxYzkyNzAxYjNiYTA5ZDRhM2E2MzNjNTJmZjE2NGYxMWY3OTg1YzlmZjY3ZThmZDFlYzA2NDU3MTdkMjBiNDE4YmM5M2YzYzVkNCIsInAiOiJmZjYwMDQ4M2RiNmFiZmM1YjQ1ZWFiNzg1OTRiMzUzM2Q1NTBkOWYxYmYyYTk5MmE3YThkYWE2ZGMzNGY4MDQ1YWQ0ZTZlMGM0MjlkMzM0ZWVlYWFlZmQ3ZTIzZDQ4MTBiZTAwZTRjYzE0OTJjYmEzMjViYTgxZmYyZDVhNWIzMDVhOGQxN2ViM2JmNGEwNmEzNDlkMzkyZTAwZDMyOTc0NGE1MTc5MzgwMzQ0ZTgyYTE4YzQ3OTMzNDM4Zjg5MWUyMmFlZWY4MTJkNjljOGY3NWUzMjZjYjcwZWEwMDBjM2Y3NzZkZmRiZDYwNDYzOGMyZWY3MTdmYzI2ZDAyZTE3IiwicSI6ImUyMWUwNGY5MTFkMWVkNzk5MTAwOGVjYWFiM2JmNzc1OTg0MzA5YzMiLCJnIjoiYzUyYTRhMGZmM2I3ZTYxZmRmMTg2N2NlODQxMzgzNjlhNjE1NGY0YWZhOTI5NjZlM2M4MjdlMjVjZmE2Y2Y1MDhiOTBlNWRlNDE5ZTEzMzdlMDdhMmU5ZTJhM2NkNWRlYTcwNGQxNzVmOGViZjZhZjM5N2Q2OWUxMTBiOTZhZmIxN2M3YTAzMjU5MzI5ZTQ4MjliMGQwM2JiYzc4OTZiMTViNGFkZTUzZTEzMDg1OGNjMzRkOTYyNjlhYTg5MDQxZjQwOTEzNmM3MjQyYTM4ODk1YzlkNWJjY2FkNGYzODlhZjFkN2E0YmQxMzk4YmQwNzJkZmZhODk2MjMzMzk3YSJ9LCJwcmluY2lwYWwiOiIwMzgxOTgyYS0xZTgzLTI1NjYtNjgzZS05MDRmNDA0NGM1MGRAbXNpc2RuLWRldi5zdGFnZS5tb3phd3MubmV0IiwiaWF0IjoxNDA0NDY5NzgyODc3LCJleHAiOjE0MDQ0OTEzOTI4NzcsImlzcyI6Im1zaXNkbi1kZXYuc3RhZ2UubW96YXdzLm5ldCJ9."
// === Helpers ===
function addPermission(aAction) {
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(ORIGIN, null, null);
let _principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getAppCodebasePrincipal(uri, APP_ID, false);
let pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
pm.addFromPrincipal(_principal, MOBILEID_PERM, aAction);
}
function removePermission() {
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(ORIGIN, null, null);
let _principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager)
.getAppCodebasePrincipal(uri, APP_ID, false);
let pm = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
pm.removeFromPrincipal(_principal, MOBILEID_PERM);
}
// === Mocks ===
let Mock = function(aOptions) {
if (!aOptions) {
aOptions = {};
}
this._options = aOptions;
this._spied = {};
};
Mock.prototype = {
_: function(aMethod) {
DEBUG && do_print("_ " + aMethod + JSON.stringify(this._spied));
let self = this;
return {
callsLength: function(aNumberOfCalls) {
if (aNumberOfCalls == 0) {
do_check_eq(self._spied[aMethod], undefined);
return;
}
do_check_eq(self._spied[aMethod].length, aNumberOfCalls);
},
call: function(aCallNumber) {
return {
arg: function(aArgNumber, aValue) {
let _arg = self._spied[aMethod][aCallNumber - 1][aArgNumber - 1];
if (Array.isArray(aValue)) {
do_check_eq(_arg.length, aValue.length)
for (let i = 0; i < _arg.length; i++) {
do_check_eq(_arg[i], aValue[i]);
}
return;
}
if (typeof aValue === 'object') {
do_check_eq(JSON.stringify(_arg), JSON.stringify(aValue));
return;
}
do_check_eq(_arg, aValue);
}
}
}
}
},
_spy: function(aMethod, aArgs) {
DEBUG && do_print(aMethod + " - " + JSON.stringify(aArgs));
if (!this._spied[aMethod]) {
this._spied[aMethod] = [];
}
this._spied[aMethod].push(aArgs);
},
getSpiedCalls: function(aMethod) {
return this._spied[aMethod];
}
};
// UI Glue mock up.
let MockUi = function(aOptions) {
Mock.call(this, aOptions);
};
MockUi.prototype = {
__proto__: Mock.prototype,
_startFlowResult: {
phoneNumber: PHONE_NUMBER,
mcc: MNC
},
_verifyCodePromptResult: {
verificationCode: VERIFICATION_CODE
},
startFlow: function() {
this._spy("startFlow", arguments);
return Promise.resolve(this._options.startFlowResult ||
this._startFlowResult);
},
verificationCodePrompt: function() {
this._spy("verifyCodePrompt", arguments);
return Promise.resolve(this._options.verificationCodePromptResult ||
this._verifyCodePromptResult);
},
verify: function() {
this._spy("verify", arguments);
},
error: function() {
this._spy("error", arguments);
},
verified: function() {
this._spy("verified", arguments);
},
set oncancel(aCallback) {
},
set onresendcode(aCallback) {
}
};
// Save original credential store instance.
const kMobileIdentityCredStore = MobileIdentityManager.credStore;
// Credentials store mock up.
let MockCredStore = function(aOptions) {
Mock.call(this, aOptions);
};
MockCredStore.prototype = {
__proto__: Mock.prototype,
_getByOriginResult: null,
_getByMsisdnResult: null,
_getByIccIdResult: null,
getByOrigin: function() {
this._spy("getByOrigin", arguments);
let result = this._getByOriginResult;
if (this._options.getByOriginResult) {
if (Array.isArray(this._options.getByOriginResult)) {
result = this._options.getByOriginResult.length ?
this._options.getByOriginResult.shift() : null;
} else {
result = this._options.getByOriginResult;
}
}
return Promise.resolve(result);
},
getByMsisdn: function() {
this._spy("getByMsisdn", arguments);
return Promise.resolve(this._options.getByMsisdnResult ||
this._getByMsisdnResult);
},
getByIccId: function() {
this._spy("getByIccId", arguments);
return Promise.resolve(this._options.getByIccIdResult ||
this._getByIccIdResult);
},
add: function() {
this._spy("add", arguments);
return Promise.resolve();
},
setDeviceIccIds: function() {
this._spy("setDeviceIccIds", arguments);
return Promise.resolve();
},
removeOrigin: function() {
this._spy("removeOrigin", arguments);
return Promise.resolve();
},
delete: function() {
this._spy("delete", arguments);
return Promise.resolve();
}
};
// Save original client instance.
const kMobileIdentityClient = MobileIdentityManager.client;
// Client mock up.
let MockClient = function(aOptions) {
Mock.call(this, aOptions);
};
MockClient.prototype = {
__proto__: Mock.prototype,
_discoverResult: {
verificationMethods: ["sms/mt"],
verificationDetails: {
"sms/mt": {
mtSender: "123",
url: "https://msisdn.accounts.firefox.com/v1/msisdn/sms/mt/verify"
}
}
},
_registerResult: {
msisdnSessionToken: SESSION_TOKEN
},
_smsMtVerifyResult: {},
_verifyCodeResult: {
msisdn: PHONE_NUMBER
},
_signResult: {
cert: CERTIFICATE
},
hawk: {
now: function() {
return Date.now();
}
},
discover: function() {
this._spy("discover", arguments);
return Promise.resolve(this._options.discoverResult ||
this._discoverResult);
},
register: function() {
this._spy("register", arguments);
return Promise.resolve(this._options.registerResult ||
this._registerResult);
},
smsMtVerify: function() {
this._spy("smsMtVerify", arguments);
return Promise.resolve(this._options.smsMtVerifyResult ||
this._smsMtVerifyResult);
},
verifyCode: function() {
this._spy("verifyCode", arguments);
return Promise.resolve(this._options.verifyCodeResult ||
this._verifyCodeResult);
},
sign: function() {
this._spy("sign", arguments);
if (this._options.signError) {
let error = Array.isArray(this._options.signError) ?
this._options.signError.shift() :
this._options.signError;
return Promise.reject(error);
}
return Promise.resolve(this._options.signResult || this._signResult);
}
};
// The test rely on having an app registered. Otherwise, it will throw.
// Override XULAppInfo.
const XUL_APP_INFO_UUID = Components.ID("{84fdc459-d96d-421c-9bff-a8193233ae75}");
const XUL_APP_INFO_CONTRACT_ID = "@mozilla.org/xre/app-info;1";
let (XULAppInfo = {
vendor: "Mozilla",
name: "MobileIdTest",
ID: "{230de50e-4cd1-11dc-8314-0800200b9a66}",
version: "1",
appBuildID: "2007010101",
platformVersion: "",
platformBuildID: "2007010101",
inSafeMode: false,
logConsoleErrors: true,
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIXULAppInfo,
Ci.nsIXULRuntime,
])
}) {
let XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return XULAppInfo.QueryInterface(iid);
}
};
Cm.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(XUL_APP_INFO_UUID,
"XULAppInfo",
XUL_APP_INFO_CONTRACT_ID,
XULAppInfoFactory);
}
// === Global cleanup ===
function cleanup() {
MobileIdentityManager.credStore = kMobileIdentityCredStore;
MobileIdentityManager.client = kMobileIdentityClient;
@ -431,7 +23,6 @@ function cleanup() {
// Unregister mocks and restore original code.
do_register_cleanup(cleanup);
// === Tests ===
function run_test() {
run_next_test();

View File

@ -0,0 +1,42 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/MobileIdentityVerificationFlow.jsm");
function verifyStrategy() {
return Promise.resolve();
}
function cleanupStrategy() {
}
function run_test() {
do_print("= Bug 1101444: Invalid verification code shouldn't restart " +
"verification flow =");
let client = new MockClient({
// This will emulate two invalid attempts. The third time it will work.
verifyCodeError: ["INVALID", "INVALID"]
});
let ui = new MockUi();
let verificationFlow = new MobileIdentityVerificationFlow({
external: true,
sessionToken: SESSION_TOKEN,
msisdn: PHONE_NUMBER
}, ui, client, verifyStrategy, cleanupStrategy);
verificationFlow.doVerification().then(() => {
// We should only do the registration process once. We only try registering
// again when the timeout fires, but not when we enter an invalid
// verification code.
client._("register").callsLength(1);
client._("verifyCode").callsLength(3);
// Because we do two invalid attempts, we should show the invalid code error twice.
ui._("error").callsLength(2);
});
do_test_finished();
};

View File

@ -1,7 +1,8 @@
[DEFAULT]
head = head.js
tail =
skip-if = toolkit == 'gonk'
[test_mobileid_manager.js]
skip-if = 1
[test_mobileid_client.js]
[test_mobileid_verification_flow.js]

View File

@ -5,7 +5,7 @@
from setuptools import setup
PACKAGE_NAME = 'mozdevice'
PACKAGE_VERSION = '0.43'
PACKAGE_VERSION = '0.44'
deps = ['mozfile >= 1.0',
'mozlog >= 2.1',

View File

@ -1312,7 +1312,8 @@ public:
bool Collect(ccType aCCType,
SliceBudget& aBudget,
nsICycleCollectorListener* aManualListener);
nsICycleCollectorListener* aManualListener,
bool aPreferShorterSlices = false);
void Shutdown();
void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
@ -3600,7 +3601,8 @@ PrintPhase(const char* aPhase)
bool
nsCycleCollector::Collect(ccType aCCType,
SliceBudget& aBudget,
nsICycleCollectorListener* aManualListener)
nsICycleCollectorListener* aManualListener,
bool aPreferShorterSlices)
{
CheckThreadSafety();
@ -3623,7 +3625,7 @@ nsCycleCollector::Collect(ccType aCCType,
++mResults.mNumSlices;
bool continueSlice = true;
bool continueSlice = aBudget.isUnlimited() || !aPreferShorterSlices;
do {
switch (mIncrementalPhase) {
case IdlePhase:
@ -3640,7 +3642,8 @@ nsCycleCollector::Collect(ccType aCCType,
// (There's no need to check if we've finished graph building, because
// if we haven't, we've already exceeded our budget, and will finish
// this slice anyways.)
continueSlice = aBudget.isUnlimited() || mResults.mNumSlices < 3;
continueSlice = aBudget.isUnlimited() ||
(mResults.mNumSlices < 3 && !aPreferShorterSlices);
break;
case ScanAndCollectWhitePhase:
// We do ScanRoots and CollectWhite in a single slice to ensure
@ -4225,7 +4228,8 @@ nsCycleCollector_collect(nsICycleCollectorListener* aManualListener)
}
void
nsCycleCollector_collectSlice(SliceBudget& budget)
nsCycleCollector_collectSlice(SliceBudget& budget,
bool aPreferShorterSlices)
{
CollectorData* data = sCollectorData.get();
@ -4236,7 +4240,7 @@ nsCycleCollector_collectSlice(SliceBudget& budget)
PROFILER_LABEL("nsCycleCollector", "collectSlice",
js::ProfileEntry::Category::CC);
data->mCollector->Collect(SliceCC, budget, nullptr);
data->mCollector->Collect(SliceCC, budget, nullptr, aPreferShorterSlices);
}
void

View File

@ -58,7 +58,8 @@ already_AddRefed<nsICycleCollectorLogSink> nsCycleCollector_createLogSink();
void nsCycleCollector_collect(nsICycleCollectorListener* aManualListener);
void nsCycleCollector_collectSlice(js::SliceBudget& budget);
void nsCycleCollector_collectSlice(js::SliceBudget& budget,
bool aPreferShorterSlices = false);
uint32_t nsCycleCollector_suspectedCount();
void nsCycleCollector_shutdown();