diff --git a/browser/base/content/socialchat.xml b/browser/base/content/socialchat.xml
index d133de707171..25811f31719b 100644
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -122,7 +122,7 @@
-
+
@@ -130,6 +130,12 @@
+
+ // to avoid reflows we cache the values for various widths.
+ this.cachedWidthOpen = 0;
+ this.cachedWidthMinimized = 0;
+ this.cachedWidthNub = 0;
+
document.getAnonymousElementByAttribute(this, "anonid", "innerbox");
@@ -143,22 +149,27 @@
document.getAnonymousElementByAttribute(this, "anonid", "nub");
-
-
- return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
-
-
-
@@ -167,55 +178,48 @@
new WeakMap()
new Map();
-
+
+
+
+
+
-
+
-
+
-
- child.viewWidth) {
- this.showChat(child);
- }
- if (!this.firstCollapsedChild) {
- window.removeEventListener("resize", this);
- this.menupopup.parentNode.collapsed = true;
- }
- ]]>
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -296,9 +347,10 @@
@@ -312,11 +364,7 @@
if (cb) {
cb = cb.get();
if (cb.parentNode) {
- // ensure this chatbox is visible
- if (this.selectedChat != cb)
- this.selectedChat = cb;
- if (cb.collapsed)
- this.showChat(cb);
+ this.showChat(cb);
if (aCallback)
aCallback(cb.iframe.contentWindow);
return;
@@ -330,6 +378,75 @@
this.insertBefore(cb, this.firstChild);
cb.init(aProvider, aURL, aCallback);
this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
+ this.resize();
+ ]]>
+
+
+
+ availWidth) {
+ // we need to collapse some.
+ let toCollapse = [];
+ for (let child of this.collapsibleChildren) {
+ if (currentWidth <= availWidth)
+ break;
+ toCollapse.push(child);
+ currentWidth -= this.getTotalChildWidth(child);
+ }
+ if (toCollapse.length) {
+ for (let child of toCollapse)
+ this.collapseChat(child);
+ }
+ } else if (currentWidth < availWidth) {
+ // we *might* be able to expand some - see how many.
+ // XXX - if this was clever, it could know when removing the nub
+ // leaves enough space to show all collapsed
+ let toShow = [];
+ for (let child of this.collapsedChildren) {
+ currentWidth += this.getTotalChildWidth(child);
+ if (currentWidth > availWidth)
+ break;
+ toShow.push(child);
+ }
+ for (let child of toShow)
+ this._showChat(child);
+
+ // If none remain collapsed remove the nub.
+ if (!this.hasCollapsedChildren) {
+ this.nub.collapsed = true;
+ }
+ }
+ // else: achievement unlocked - we are pixel-perfect!
+ ]]>
+
+
+
+
+
@@ -338,18 +455,11 @@
-
+
diff --git a/browser/base/content/test/browser_social_chatwindow.js b/browser/base/content/test/browser_social_chatwindow.js
index 8c170cd439e0..9a1cbc92f125 100644
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -12,10 +12,12 @@ function test() {
workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
};
+ let oldwidth = window.outerWidth; // we futz with this, so we restore it
runSocialTestWithProvider(manifest, function (finishcb) {
runSocialTests(tests, undefined, undefined, function () {
let chats = document.getElementById("pinnedchats");
ok(chats.children.length == 0, "no chatty children left behind");
+ window.resizeTo(oldwidth, window.outerHeight);
finishcb();
});
});
@@ -109,8 +111,8 @@ var tests = {
chats.selectedChat.close();
}
ok(!chats.selectedChat, "chats are all closed");
- port.close();
ensureSocialUrlNotRemembered(chatUrl);
+ port.close();
next();
break;
}
@@ -138,6 +140,7 @@ var tests = {
evt.initCustomEvent("socialTest-CloseSelf", true, true, {});
doc.documentElement.dispatchEvent(evt);
ok(!chat.parentNode, "chat is now closed");
+ port.close();
next();
break;
}
@@ -162,6 +165,7 @@ var tests = {
let chats = document.getElementById("pinnedchats");
chats.selectedChat.close();
is(chats.selectedChat, null, "should only have been one chat open");
+ port.close();
next();
} else {
// first time we got the opened message, so re-request the same
@@ -173,6 +177,122 @@ var tests = {
}
port.postMessage({topic: "test-init", data: { id: 1 }});
},
+
+ // check removeAll does the right thing
+ testRemoveAll: function(next, mode) {
+ let port = Social.provider.getWorkerPort();
+ port.postMessage({topic: "test-init"});
+ get3ChatsForCollapsing(mode || "normal", function() {
+ let chatbar = window.SocialChatBar.chatbar;
+ chatbar.removeAll();
+ // should be no evidence of any chats left.
+ is(chatbar.childNodes.length, 0, "should be no chats left");
+ checkPopup();
+ is(chatbar.selectedChat, null, "nothing should be selected");
+ is(chatbar.chatboxForURL.size, 0, "chatboxForURL map should be empty");
+ port.close();
+ next();
+ });
+ },
+
+ testRemoveAllMinimized: function(next) {
+ this.testRemoveAll(next, "minimized");
+ },
+
+ // resize and collapse testing.
+ testBrowserResize: function(next, mode) {
+ let chats = document.getElementById("pinnedchats");
+ let port = Social.provider.getWorkerPort();
+ port.postMessage({topic: "test-init"});
+ get3ChatsForCollapsing(mode || "normal", function(first, second, third) {
+ let chatWidth = chats.getTotalChildWidth(first);
+ ok(chatWidth, "have a chatwidth");
+ let popupWidth = getPopupWidth();
+ ok(popupWidth, "have a popupwidth");
+ info("starting resize tests - each chat's width is " + chatWidth +
+ " and the popup width is " + popupWidth);
+ resizeAndCheckWidths(first, second, third, [
+ [chatWidth-1, false, false, true, "to < 1 chat width - only last should be visible."],
+ [chatWidth+1, false, false, true, "one pixel more then one fully exposed (not counting popup) - still only 1."],
+ [chatWidth+popupWidth+1, false, false, true, "one pixel more than one fully exposed (including popup) - still only 1."],
+ [chatWidth*2-1, false, false, true, "second not showing by 1 pixel (not counting popup) - only 1 exposed."],
+ [chatWidth*2+popupWidth-1, false, false, true, "second not showing by 1 pixel (including popup) - only 1 exposed."],
+ [chatWidth*2+popupWidth+1, false, true, true, "big enough to fit 2 - nub remains visible as first is still hidden"],
+ [chatWidth*3+popupWidth-1, false, true, true, "one smaller than the size necessary to display all three - first still hidden"],
+ [chatWidth*3+popupWidth+1, true, true, true, "big enough to fit all - all exposed (which removes the nub)"],
+ [chatWidth*3, true, true, true, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."],
+ [chatWidth*3-1, false, true, true, "one pixel less and the first is again collapsed (and the nub re-appears)"],
+ [chatWidth*2+popupWidth+1, false, true, true, "back down to just big enough to fit 2"],
+ [chatWidth*2+popupWidth-1, false, false, true, "back down to just not enough to fit 2"],
+ [chatWidth*3+popupWidth+1, true, true, true, "now a large jump to make all 3 visible (ie, affects 2)"],
+ [chatWidth*1.5, false, false, true, "and a large jump back down to 1 visible (ie, affects 2)"],
+ ], function() {
+ closeAllChats();
+ port.close();
+ next();
+ });
+ });
+ },
+
+ testBrowserResizeMinimized: function(next) {
+ this.testBrowserResize(next, "minimized");
+ },
+
+ testShowWhenCollapsed: function(next) {
+ let port = Social.provider.getWorkerPort();
+ port.postMessage({topic: "test-init"});
+ get3ChatsForCollapsing("normal", function(first, second, third) {
+ let chatbar = window.SocialChatBar.chatbar;
+ chatbar.showChat(first);
+ ok(!first.collapsed, "first should no longer be collapsed");
+ ok(second.collapsed || third.collapsed, false, "one of the others should be collapsed");
+ closeAllChats();
+ port.close();
+ next();
+ });
+ },
+
+ testActivity: function(next) {
+ let port = Social.provider.getWorkerPort();
+ port.postMessage({topic: "test-init"});
+ get3ChatsForCollapsing("normal", function(first, second, third) {
+ let chatbar = window.SocialChatBar.chatbar;
+ is(chatbar.selectedChat, third, "third chat should be selected");
+ ok(!chatbar.selectedChat.hasAttribute("activity"), "third chat should have no activity");
+ // send an activity message to the second.
+ ok(!second.hasAttribute("activity"), "second chat should have no activity");
+ let iframe2 = second.iframe;
+ let evt = iframe2.contentDocument.createEvent("CustomEvent");
+ evt.initCustomEvent("socialChatActivity", true, true, {});
+ iframe2.contentDocument.documentElement.dispatchEvent(evt);
+ // second should have activity.
+ ok(second.hasAttribute("activity"), "second chat should now have activity");
+ // select the second - it should lose "activity"
+ chatbar.selectedChat = second;
+ ok(!second.hasAttribute("activity"), "second chat should no longer have activity");
+ // Now try the first - it is collapsed, so the 'nub' also gets activity attr.
+ ok(!first.hasAttribute("activity"), "first chat should have no activity");
+ let iframe1 = first.iframe;
+ let evt = iframe1.contentDocument.createEvent("CustomEvent");
+ evt.initCustomEvent("socialChatActivity", true, true, {});
+ iframe1.contentDocument.documentElement.dispatchEvent(evt);
+ ok(first.hasAttribute("activity"), "first chat should now have activity");
+ ok(chatbar.nub.hasAttribute("activity"), "nub should also have activity");
+ // first is collapsed, so use openChat to get it.
+ chatbar.openChat(Social.provider, first.getAttribute("src"));
+ ok(!first.hasAttribute("activity"), "first chat should no longer have activity");
+ // The nub should lose the activity flag here too
+ todo(!chatbar.nub.hasAttribute("activity"), "Bug 806266 - nub should no longer have activity");
+ // TODO: tests for bug 806266 should arrange to have 2 chats collapsed
+ // then open them checking the nub is updated correctly.
+ closeAllChats();
+ port.close();
+ next();
+ });
+ },
+
+ // XXX - note this must be the last test until we restore the login state
+ // between tests...
testCloseOnLogout: function(next) {
const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
let port = Social.provider.getWorkerPort();
@@ -184,6 +304,7 @@ var tests = {
case "got-chatbox-message":
ok(true, "got a chat window opened");
port.postMessage({topic: "test-logout"});
+ port.close();
waitForCondition(function() document.getElementById("pinnedchats").firstChild == null,
next,
"chat windows didn't close");
@@ -191,5 +312,163 @@ var tests = {
}
}
port.postMessage({topic: "test-worker-chat", data: chatUrl});
+ },
+}
+
+// And lots of helpers for the resize tests.
+function get3ChatsForCollapsing(mode, cb) {
+ // We make one chat, then measure its size. We then resize the browser to
+ // ensure a second can be created fully visible but a third can not - then
+ // create the other 2. first will will be collapsed, second fully visible
+ // and the third also visible and the "selected" one.
+ // To make our life easier we don't go via the worker and ports so we get
+ // more control over creation *and* to make the code much simpler. We
+ // assume the worker/port stuff is individually tested above.
+ let chatbar = window.SocialChatBar.chatbar;
+ let chatWidth = undefined;
+ let num = 0;
+ is(chatbar.childNodes.length, 0, "chatbar starting empty");
+ is(chatbar.menupopup.childNodes.length, 0, "popup starting empty");
+
+ makeChat(mode, "first chat", function() {
+ // got the first one.
+ checkPopup();
+ ok(chatbar.menupopup.parentNode.collapsed, "menu selection isn't visible");
+ // we kinda cheat here and get the width of the first chat, assuming
+ // that all future chats will have the same width when open.
+ chatWidth = chatbar.calcTotalWidthOf(chatbar.selectedChat);
+ let desired = chatWidth * 2.5;
+ resizeWindowToChatAreaWidth(desired, function(sizedOk) {
+ ok(sizedOk, "can't do any tests without this width");
+ checkPopup();
+ makeChat(mode, "second chat", function() {
+ is(chatbar.childNodes.length, 2, "now have 2 chats");
+ checkPopup();
+ // and create the third.
+ makeChat(mode, "third chat", function() {
+ is(chatbar.childNodes.length, 3, "now have 3 chats");
+ checkPopup();
+ // XXX - this is a hacky implementation detail around the order of
+ // the chats. Ideally things would be a little more sane wrt the
+ // other in which the children were created.
+ let second = chatbar.childNodes[2];
+ let first = chatbar.childNodes[1];
+ let third = chatbar.childNodes[0];
+ ok(first.collapsed && !second.collapsed && !third.collapsed, "collapsed state as promised");
+ is(chatbar.selectedChat, third, "third is selected as promised")
+ info("have 3 chats for collapse testing - starting actual test...");
+ cb(first, second, third);
+ }, mode);
+ }, mode);
+ });
+ }, mode);
+}
+
+function makeChat(mode, uniqueid, cb) {
+ const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
+ let provider = Social.provider;
+ window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) {
+ // we can't callback immediately or we might close the chat during
+ // this event which upsets the implementation - it is only 1/2 way through
+ // handling the load event.
+ chat.document.title = uniqueid;
+ executeSoon(cb);
+ }, mode);
+}
+
+function checkPopup() {
+ // popup only showing if any collapsed popup children.
+ let chatbar = window.SocialChatBar.chatbar;
+ let numCollapsed = 0;
+ for (let chat of chatbar.childNodes) {
+ if (chat.collapsed) {
+ numCollapsed += 1;
+ // and it have a menuitem weakmap
+ is(chatbar.menuitemMap.get(chat).nodeName, "menuitem", "collapsed chat has a menu item");
+ } else {
+ ok(!chatbar.menuitemMap.has(chat), "open chat has no menu item");
+ }
+ }
+ is(chatbar.menupopup.parentNode.collapsed, numCollapsed == 0, "popup matches child collapsed state");
+ is(chatbar.menupopup.childNodes.length, numCollapsed, "popup has correct count of children");
+ // todo - check each individual elt is what we expect?
+}
+
+// Resize the main window so the chat area's boxObject is |desired| wide.
+// Does a callback passing |true| if the window is now big enough or false
+// if we couldn't resize large enough to satisfy the test requirement.
+function resizeWindowToChatAreaWidth(desired, cb) {
+ let current = window.SocialChatBar.chatbar.getBoundingClientRect().width;
+ let delta = desired - current;
+ info("resizing window so chat area is " + desired + " wide, currently it is "
+ + current + ". Screen avail is " + window.screen.availWidth
+ + ", current outer width is " + window.outerWidth);
+
+ // WTF? Some test boxes will resize to fractional values - eg: we
+ // request 660px but actually get 659.5!?
+ let widthDeltaCloseEnough = function(d) {
+ return Math.abs(d) <= 0.5;
+ }
+
+ // attempting to resize by (0,0), unsurprisingly, doesn't cause a resize
+ // event - so just callback saying all is well.
+ if (widthDeltaCloseEnough(delta)) {
+ cb(true);
+ return;
+ }
+ // On lo-res screens we may already be maxed out but still smaller than the
+ // requested size, so asking to resize up also will not cause a resize event.
+ // So just callback now saying the test must be skipped.
+ if (window.screen.availWidth - window.outerWidth < delta) {
+ info("skipping this as screen available width is less than necessary");
+ cb(false);
+ return;
+ }
+ // Otherwise we request resize and expect a resize event
+ window.addEventListener("resize", function resize_handler() {
+ window.removeEventListener("resize", resize_handler);
+ // we did resize - but did we get far enough to be able to continue?
+ let newSize = window.SocialChatBar.chatbar.getBoundingClientRect().width;
+ let sizedOk = widthDeltaCloseEnough(newSize - desired);
+ if (!sizedOk) {
+ // not an error...
+ info("skipping this as we can't resize chat area to " + desired + " - got " + newSize);
+ }
+ cb(sizedOk);
+ });
+ window.resizeBy(delta, 0);
+}
+
+function resizeAndCheckWidths(first, second, third, checks, cb) {
+ if (checks.length == 0) {
+ cb(); // nothing more to check!
+ return;
+ }
+ let [width, firstVisible, secondVisible, thirdVisible, why] = checks.shift();
+ info("Check: " + why);
+ info("resizing window to " + width + ", expect visibility of " + firstVisible + "/" + secondVisible + "/" + thirdVisible);
+ resizeWindowToChatAreaWidth(width, function(sizedOk) {
+ checkPopup();
+ if (sizedOk) {
+ is(!first.collapsed, firstVisible, "first should be " + (firstVisible ? "visible" : "hidden"));
+ is(!second.collapsed, secondVisible, "second should be " + (secondVisible ? "visible" : "hidden"));
+ is(!third.collapsed, thirdVisible, "third should be " + (thirdVisible ? "visible" : "hidden"));
+ }
+ resizeAndCheckWidths(first, second, third, checks, cb);
+ });
+}
+
+function getPopupWidth() {
+ let popup = window.SocialChatBar.chatbar.menupopup;
+ ok(!popup.parentNode.collapsed, "asking for popup width when it is visible");
+ let cs = document.defaultView.getComputedStyle(popup.parentNode);
+ let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight);
+ return popup.parentNode.getBoundingClientRect().width + margins;
+}
+
+function closeAllChats() {
+ let chatbar = window.SocialChatBar.chatbar;
+ while (chatbar.selectedChat) {
+ chatbar.selectedChat.close();
}
}
diff --git a/build/mobile/remoteautomation.py b/build/mobile/remoteautomation.py
index 5c2d48f719d6..ab57977934a3 100644
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -73,6 +73,8 @@ class RemoteAutomation(Automation):
if (status == 1 and self._devicemanager.processExist(proc.procName)):
# Then we timed out, make sure Fennec is dead
+ print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \
+ "allowed maximum time of %d seconds" % (self.lastTestSeen, int(maxTime))
proc.kill()
return status
diff --git a/configure.in b/configure.in
index a1d48cb3d92d..417667f5fad0 100644
--- a/configure.in
+++ b/configure.in
@@ -411,8 +411,7 @@ if test -n "$MOZ_METRO"; then
AC_DEFINE(MOZ_METRO)
# Target the Windows 8 Kit
WINSDK_TARGETVER=602
- # Allow a higher api set
- WINVER=602
+ WINVER=502
# toolkit/library/makefile.in needs these, see nsDllMain.
CRTDLLVERSION=110
CRTEXPDLLVERSION=1-1-0
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 8e619ff04e26..732ef0ec67e1 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -21,6 +21,7 @@
#include "nsDOMOfflineResourceList.h"
#include "nsError.h"
#include "nsIIdleService.h"
+#include "nsIPowerManagerService.h"
#ifdef XP_WIN
#ifdef GetClassName
@@ -4588,6 +4589,17 @@ nsGlobalWindow::SetFullScreenInternal(bool aFullScreen, bool aRequireTrust)
nsIDocument::ExitFullScreen(false);
}
+ if (!mWakeLock && mFullScreen) {
+ nsCOMPtr pmService =
+ do_GetService(POWERMANAGERSERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(pmService, NS_OK);
+
+ pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"), this, getter_AddRefs(mWakeLock));
+ } else if (mWakeLock && !mFullScreen) {
+ mWakeLock->Unlock();
+ mWakeLock = NULL;
+ }
+
return NS_OK;
}
diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h
index 0520c13f6698..9552417cd931 100644
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -65,6 +65,7 @@
#include "nsWrapperCacheInlines.h"
#include "nsIDOMApplicationRegistry.h"
#include "nsIIdleObserver.h"
+#include "nsIDOMWakeLock.h"
// JS includes
#include "jsapi.h"
@@ -636,6 +637,8 @@ protected:
nsCOMPtr mIdleService;
+ nsCOMPtr mWakeLock;
+
static bool sIdleObserversAPIFuzzTimeDisabled;
friend class HashchangeCallback;
diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp
index a7a0ac6caa58..5e13cafd7e89 100644
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -174,7 +174,26 @@ static uint32_t sCleanupsSinceLastGC = UINT32_MAX;
static bool sNeedsFullCC = false;
static nsJSContext *sContextList = nullptr;
-nsScriptNameSpaceManager *gNameSpaceManager;
+static nsScriptNameSpaceManager *gNameSpaceManager;
+static nsIMemoryReporter *gReporter;
+
+NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ScriptNameSpaceManagerMallocSizeOf,
+ "script-namespace-manager")
+
+static int64_t
+GetScriptNameSpaceManagerSize()
+{
+ MOZ_ASSERT(gNameSpaceManager);
+ return gNameSpaceManager->SizeOfIncludingThis(
+ ScriptNameSpaceManagerMallocSizeOf);
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(ScriptNameSpaceManager,
+ "explicit/script-namespace-manager",
+ KIND_HEAP,
+ nsIMemoryReporter::UNITS_BYTES,
+ GetScriptNameSpaceManagerSize,
+ "Memory used for the script namespace manager.")
static nsIJSRuntimeService *sRuntimeService;
JSRuntime *nsJSRuntime::sRuntime;
@@ -3644,6 +3663,7 @@ nsJSRuntime::Startup()
sDisableExplicitCompartmentGC = false;
sNeedsFullCC = false;
gNameSpaceManager = nullptr;
+ gReporter = nullptr;
sRuntimeService = nullptr;
sRuntime = nullptr;
sIsInitialized = false;
@@ -3986,6 +4006,9 @@ nsJSRuntime::GetNameSpaceManager()
nsresult rv = gNameSpaceManager->Init();
NS_ENSURE_SUCCESS(rv, nullptr);
+
+ gReporter = new NS_MEMORY_REPORTER_NAME(ScriptNameSpaceManager);
+ NS_RegisterMemoryReporter(gReporter);
}
return gNameSpaceManager;
@@ -4002,6 +4025,10 @@ nsJSRuntime::Shutdown()
nsJSContext::KillInterSliceGCTimer();
NS_IF_RELEASE(gNameSpaceManager);
+ if (gReporter) {
+ (void)::NS_UnregisterMemoryReporter(gReporter);
+ gReporter = nullptr;
+ }
if (!sContextCount) {
// We're being shutdown, and there are no more contexts
diff --git a/dom/base/nsScriptNameSpaceManager.cpp b/dom/base/nsScriptNameSpaceManager.cpp
index 16c30712d78e..b9419136fde7 100644
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -8,6 +8,7 @@
#include "nsIComponentManager.h"
#include "nsIComponentRegistrar.h"
#include "nsICategoryManager.h"
+#include "nsIMemoryReporter.h"
#include "nsIServiceManager.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
@@ -37,6 +38,13 @@ public:
// Our hash table ops don't care about the order of these members
nsString mKey;
nsGlobalNameStruct mGlobalName;
+
+ size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) {
+ // Measurement of the following members may be added later if DMD finds it
+ // is worthwhile:
+ // - mGlobalName
+ return mKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
+ }
};
@@ -793,3 +801,22 @@ nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
s->mPrefEnabled = aPrefEnabled;
}
}
+
+static size_t
+SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, nsMallocSizeOfFun aMallocSizeOf,
+ void *aArg)
+{
+ GlobalNameMapEntry* entry = static_cast(aHdr);
+ return entry->SizeOfExcludingThis(aMallocSizeOf);
+}
+
+size_t
+nsScriptNameSpaceManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf)
+{
+ size_t n = 0;
+ n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames,
+ SizeOfEntryExcludingThis, aMallocSizeOf);
+ n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames,
+ SizeOfEntryExcludingThis, aMallocSizeOf);
+ return n;
+}
diff --git a/dom/base/nsScriptNameSpaceManager.h b/dom/base/nsScriptNameSpaceManager.h
index 858a6313b564..1cfdc85d92a2 100644
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -143,6 +143,8 @@ public:
mozilla::dom::DefineInterface aDefineDOMInterface,
mozilla::dom::PrefEnabled aPrefEnabled);
+ size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
+
private:
// Adds a new entry to the hash and returns the nsGlobalNameStruct
// that aKey will be mapped to. If mType in the returned
diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js
index d3da5a855d0e..6c1cfe3304a3 100644
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -3473,9 +3473,13 @@ let RIL = {
}
if (!updatedDataCall) {
- currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
- currentDataCall.rilMessageType = "datacallstatechange";
- this.sendDOMMessage(currentDataCall);
+ // If datacalls list is coming from REQUEST_SETUP_DATA_CALL response,
+ // we do not change state for any currentDataCalls not in datacalls list.
+ if (!newDataCallOptions) {
+ currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
+ currentDataCall.rilMessageType = "datacallstatechange";
+ this.sendDOMMessage(currentDataCall);
+ }
continue;
}
diff --git a/hal/gonk/GonkSensor.cpp b/hal/gonk/GonkSensor.cpp
index 32fc3c07d40e..afa6c66a30c7 100644
--- a/hal/gonk/GonkSensor.cpp
+++ b/hal/gonk/GonkSensor.cpp
@@ -32,6 +32,7 @@
using namespace mozilla::hal;
#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "GonkSensor" , ## args)
+#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "GonkSensor" , ## args)
namespace mozilla {
@@ -112,11 +113,6 @@ public:
SensorRunnable(const sensors_event_t& data, const sensor_t* sensors, ssize_t size)
{
mSensorData.sensor() = HardwareSensorToHalSensor(data.type);
- if (mSensorData.sensor() == SENSOR_UNKNOWN) {
- // Emulator is broken and gives us events without types set
- if (data.sensor < size)
- mSensorData.sensor() = HardwareSensorToHalSensor(sensors[data.sensor].type);
- }
mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data));
mSensorData.timestamp() = data.timestamp;
if (mSensorData.sensor() == SENSOR_GYROSCOPE) {
@@ -185,6 +181,20 @@ PollSensors()
if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD)
continue;
+ if (buffer[i].sensor >= size) {
+ LOGW("buffer type is hal sensor type SENSOR_UNKNOWN, and buffer sensor is not in a valid range");
+ continue;
+ }
+
+ if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) {
+ // Emulator is broken and gives us events without types set
+ if (HardwareSensorToHalSensor(sensors[buffer[i].sensor].type) != SENSOR_UNKNOWN) {
+ buffer[i].type = sensors[buffer[i].sensor].type;
+ } else {
+ continue;
+ }
+ }
+
NS_DispatchToMainThread(new SensorRunnable(buffer[i], sensors, size));
}
} while (true);
diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp
index 16b158fcfdd4..00fcf987ce36 100644
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -46,7 +46,7 @@ SPSProfiler::setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max
{
JS_ASSERT_IF(size_ && *size_ != 0, !enabled());
if (!strings.initialized())
- strings.init(max);
+ strings.init();
stack_ = stack;
size_ = size;
max_ = max;
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index d09096e4cf03..a9eef6d8af7f 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7805,6 +7805,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
}
if (aChange & nsChangeHint_UpdateTransformLayer) {
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
+ aFrame->AddStateBits(NS_FRAME_TRANSFORM_CHANGED);
// If we're not already going to do an invalidating paint, see
// if we can get away with only updating the transform on a
// layer for this frame, and not scheduling an invalidating
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 4b49c149f587..07cb77a5bdd1 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6984,12 +6984,10 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsRect& o = aOverflowAreas.Overflow(otype);
o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
}
- if (sizeChanged) {
- if (Preserves3DChildren()) {
- ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
- } else if (ChildrenHavePerspective()) {
- RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
- }
+ if ((sizeChanged || HasAnyStateBits(NS_FRAME_TRANSFORM_CHANGED)) && Preserves3DChildren()) {
+ ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
+ } else if (sizeChanged && ChildrenHavePerspective()) {
+ RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
}
} else {
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
@@ -6998,6 +6996,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
RecomputePerspectiveChildrenOverflow(this->GetStyleContext(), &newBounds);
}
}
+ RemoveStateBits(NS_FRAME_TRANSFORM_CHANGED);
bool anyOverflowChanged;
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 69cb8d08a81f..d8602cf2791b 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -252,6 +252,10 @@ typedef uint64_t nsFrameState;
// This bit acts as a loop flag for recursive paint server drawing.
#define NS_FRAME_DRAWING_AS_PAINTSERVER NS_FRAME_STATE_BIT(33)
+// Marks the frame as having a changed transform between processing
+// nsChangeHint_UpdateTransformLayer and calling FinishAndStoreOverflow.
+#define NS_FRAME_TRANSFORM_CHANGED NS_FRAME_STATE_BIT(34)
+
// Frame is a display root and the retained layer tree needs to be updated
// at the next paint via display list construction.
// Only meaningful for display roots, so we don't really need a global state
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp
index 930ae3284af0..d342bcf63818 100644
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -119,15 +119,22 @@ GetFrameMetrics(Layer* aLayer)
return container ? &container->GetFrameMetrics() : NULL;
}
+/**
+ * Gets the layer-pixel offset of aContainerFrame's content rect top-left
+ * from the nearest display item reference frame (which we assume will be inducing
+ * a ContainerLayer).
+ */
static nsIntPoint
-GetRootFrameOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
+GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
{
nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
// Offset to the content rect in case we have borders or padding
- nsPoint frameOffset =
- (aBuilder->ToReferenceFrame(aContainerFrame->GetParent()) +
- aContainerFrame->GetContentRect().TopLeft());
+ // Note that aContainerFrame could be a reference frame itself, so
+ // we need to be careful here to ensure that we call ToReferenceFrame
+ // on aContainerFrame and not its parent.
+ nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) +
+ (aContainerFrame->GetContentRect().TopLeft() - aContainerFrame->GetPosition());
return frameOffset.ToNearestPixels(auPerDevPixel);
}
@@ -278,10 +285,10 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
layerTransform = viewTransform;
if (metrics->IsRootScrollable()) {
- // Apply the root frame translation *before* we do the rest of the transforms.
- nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder);
+ // Apply the translation *before* we do the rest of the transforms.
+ nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder);
shadowTransform = shadowTransform *
- gfx3DMatrix::Translation(float(rootFrameOffset.x), float(rootFrameOffset.y), 0.0);
+ gfx3DMatrix::Translation(float(offset.x), float(offset.y), 0.0);
}
}
@@ -660,13 +667,13 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
}
static_cast(layer.get())->SetReferentId(id);
layer->SetVisibleRegion(aVisibleRect);
- nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder);
+ nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder);
// We can only have an offset if we're a child of an inactive
// container, but our display item is LAYER_ACTIVE_FORCE which
// forces all layers above to be active.
MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
gfx3DMatrix m =
- gfx3DMatrix::Translation(rootFrameOffset.x, rootFrameOffset.y, 0.0);
+ gfx3DMatrix::Translation(offset.x, offset.y, 0.0);
// Remote content can't be repainted by us, so we multiply down
// the resolution that our container expects onto our container.
m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
@@ -887,7 +894,7 @@ RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
ContainerLayer* container = GetRootLayer();
if (aBuilder->IsForEventDelivery() && container) {
ViewTransform offset =
- ViewTransform(GetRootFrameOffset(aFrame, aBuilder), 1, 1);
+ ViewTransform(GetContentRectLayerOffset(aFrame, aBuilder), 1, 1);
BuildListForLayer(container, mFrameLoader, offset,
aBuilder, shadowTree, aFrame);
} else {
diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py
index 9a800661d02c..7fce4614ff29 100644
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -6,6 +6,7 @@ import sys
import os
import time
import tempfile
+import traceback
# We need to know our current directory so that we can serve our test files from it.
SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
@@ -443,7 +444,8 @@ def main(args):
dm.recordLogcat()
reftest.runTests(manifest, options, cmdlineArgs)
except:
- print "TEST-UNEXPECTED-FAIL | | exception while running reftests"
+ print "Automation Error: Exception caught while running tests"
+ traceback.print_exc()
retVal = 1
reftest.stopWebServer(options)
diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py
index 4d03315490f2..654d6b741819 100644
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -547,7 +547,7 @@ def main(args=sys.argv[1:]):
retVal = reftest.runTests(manifest, options, cmdlineArgs)
except:
- print "TEST-UNEXPECTED-FAIL | %s | Exception caught while running tests." % sys.exc_info()[1]
+ print "Automation Error: Exception caught while running tests"
traceback.print_exc()
reftest.stopWebServer(options)
try:
diff --git a/mobile/android/base/AboutHomeContent.java b/mobile/android/base/AboutHomeContent.java
index 189b26c1bf5f..6b761868cef2 100644
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -29,7 +29,6 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.Path;
import android.graphics.Paint;
@@ -553,10 +552,10 @@ public class AboutHomeContent extends ScrollView
Favicons favicons = mActivity.getFavicons();
favicons.loadFavicon(pageUrl, iconUrl, true,
new Favicons.OnFaviconLoadedListener() {
- public void onFaviconLoaded(String url, Drawable favicon) {
+ public void onFaviconLoaded(String url, Bitmap favicon) {
if (favicon != null) {
ImageView icon = (ImageView) row.findViewById(R.id.addon_icon);
- icon.setImageDrawable(favicon);
+ icon.setImageBitmap(favicon);
}
}
});
@@ -590,7 +589,7 @@ public class AboutHomeContent extends ScrollView
}
ContentResolver resolver = mActivity.getContentResolver();
- final BitmapDrawable favicon = BrowserDB.getFaviconForUrl(resolver, url);
+ final Bitmap favicon = BrowserDB.getFaviconForUrl(resolver, url);
lastTabUrlsList.add(url);
AboutHomeContent.this.post(new Runnable() {
@@ -599,7 +598,7 @@ public class AboutHomeContent extends ScrollView
((TextView) container.findViewById(R.id.last_tab_title)).setText(tab.getSelectedTitle());
((TextView) container.findViewById(R.id.last_tab_url)).setText(tab.getSelectedUrl());
if (favicon != null) {
- ((ImageView) container.findViewById(R.id.last_tab_favicon)).setImageDrawable(favicon);
+ ((ImageView) container.findViewById(R.id.last_tab_favicon)).setImageBitmap(favicon);
}
container.setOnClickListener(new View.OnClickListener() {
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 018c1fa98fbb..5725adf2f571 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -582,7 +582,7 @@ abstract public class BrowserApp extends GeckoApp
long id = getFavicons().loadFavicon(tab.getURL(), tab.getFaviconURL(), !tab.isPrivate(),
new Favicons.OnFaviconLoadedListener() {
- public void onFaviconLoaded(String pageUrl, Drawable favicon) {
+ public void onFaviconLoaded(String pageUrl, Bitmap favicon) {
// Leave favicon UI untouched if we failed to load the image
// for some reason.
if (favicon == null)
diff --git a/mobile/android/base/BrowserToolbar.java b/mobile/android/base/BrowserToolbar.java
index 71e7a9ae0d41..b140b84a5090 100644
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -7,6 +7,7 @@ package org.mozilla.gecko;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -678,12 +679,12 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
mAwesomeBar.setContentDescription(title != null ? title : mTitle.getHint());
}
- public void setFavicon(Drawable image) {
+ public void setFavicon(Bitmap image) {
if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
return;
if (image != null)
- mFavicon.setImageDrawable(image);
+ mFavicon.setImageBitmap(image);
else
mFavicon.setImageResource(R.drawable.favicon);
}
diff --git a/mobile/android/base/Favicons.java b/mobile/android/base/Favicons.java
index f9b63b7a25c6..5a2dd04d238f 100644
--- a/mobile/android/base/Favicons.java
+++ b/mobile/android/base/Favicons.java
@@ -21,6 +21,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.http.AndroidHttpClient;
@@ -48,12 +49,12 @@ public class Favicons {
private Map mLoadTasks;
private long mNextFaviconLoadId;
- private LruCache mFaviconsCache;
+ private LruCache mFaviconsCache;
private static final String USER_AGENT = GeckoApp.mAppContext.getDefaultUAString();
private AndroidHttpClient mHttpClient;
public interface OnFaviconLoadedListener {
- public void onFaviconLoaded(String url, Drawable favicon);
+ public void onFaviconLoaded(String url, Bitmap favicon);
}
private class DatabaseHelper extends SQLiteOpenHelper {
@@ -144,11 +145,10 @@ public class Favicons {
mNextFaviconLoadId = 0;
// Create a favicon memory cache that have up to 1mb of size
- mFaviconsCache = new LruCache(1024 * 1024) {
+ mFaviconsCache = new LruCache(1024 * 1024) {
@Override
- protected int sizeOf(String url, Drawable image) {
- Bitmap bitmap = ((BitmapDrawable) image).getBitmap();
- return bitmap.getRowBytes() * bitmap.getHeight();
+ protected int sizeOf(String url, Bitmap image) {
+ return image.getRowBytes() * image.getHeight();
}
};
}
@@ -161,7 +161,7 @@ public class Favicons {
return mHttpClient;
}
- private void dispatchResult(final String pageUrl, final Drawable image,
+ private void dispatchResult(final String pageUrl, final Bitmap image,
final OnFaviconLoadedListener listener) {
if (pageUrl != null && image != null)
putFaviconInMemCache(pageUrl, image);
@@ -189,7 +189,7 @@ public class Favicons {
}
// Check if favicon is mem cached
- Drawable image = getFaviconFromMemCache(pageUrl);
+ Bitmap image = getFaviconFromMemCache(pageUrl);
if (image != null) {
dispatchResult(pageUrl, image, listener);
return -1;
@@ -205,11 +205,11 @@ public class Favicons {
return taskId;
}
- public Drawable getFaviconFromMemCache(String pageUrl) {
+ public Bitmap getFaviconFromMemCache(String pageUrl) {
return mFaviconsCache.get(pageUrl);
}
- public void putFaviconInMemCache(String pageUrl, Drawable image) {
+ public void putFaviconInMemCache(String pageUrl, Bitmap image) {
mFaviconsCache.put(pageUrl, image);
}
@@ -254,7 +254,7 @@ public class Favicons {
mHttpClient.close();
}
- private class LoadFaviconTask extends AsyncTask {
+ private class LoadFaviconTask extends AsyncTask {
private long mId;
private String mPageUrl;
private String mFaviconUrl;
@@ -274,15 +274,13 @@ public class Favicons {
}
// Runs in background thread
- private BitmapDrawable loadFaviconFromDb() {
+ private Bitmap loadFaviconFromDb() {
ContentResolver resolver = mContext.getContentResolver();
- BitmapDrawable favicon = BrowserDB.getFaviconForUrl(resolver, mPageUrl);
-
- return favicon;
+ return BrowserDB.getFaviconForUrl(resolver, mPageUrl);
}
// Runs in background thread
- private void saveFaviconToDb(BitmapDrawable favicon) {
+ private void saveFaviconToDb(Bitmap favicon) {
if (!mPersist) {
return;
}
@@ -298,9 +296,10 @@ public class Favicons {
}
// Runs in background thread
- private BitmapDrawable downloadFavicon(URL faviconUrl) {
+ private Bitmap downloadFavicon(URL faviconUrl) {
if (mFaviconUrl.startsWith("jar:jar:")) {
- return GeckoJarReader.getBitmapDrawable(mContext.getResources(), mFaviconUrl);
+ BitmapDrawable d = GeckoJarReader.getBitmapDrawable(mContext.getResources(), mFaviconUrl);
+ return d.getBitmap();
}
URI uri;
@@ -318,13 +317,13 @@ public class Favicons {
// skia decoder sometimes returns null; workaround is to use BufferedHttpEntity
// http://groups.google.com/group/android-developers/browse_thread/thread/171b8bf35dbbed96/c3ec5f45436ceec8?lnk=raot
- BitmapDrawable image = null;
+ Bitmap image = null;
try {
HttpGet request = new HttpGet(faviconUrl.toURI());
HttpEntity entity = getHttpClient().execute(request).getEntity();
BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity);
InputStream contentStream = bufferedEntity.getContent();
- image = (BitmapDrawable) Drawable.createFromStream(contentStream, "src");
+ image = BitmapFactory.decodeStream(contentStream);
} catch (Exception e) {
Log.e(LOGTAG, "Error reading favicon", e);
}
@@ -333,8 +332,8 @@ public class Favicons {
}
@Override
- protected BitmapDrawable doInBackground(Void... unused) {
- BitmapDrawable image = null;
+ protected Bitmap doInBackground(Void... unused) {
+ Bitmap image = null;
if (isCancelled())
return null;
@@ -382,7 +381,7 @@ public class Favicons {
}
@Override
- protected void onPostExecute(final BitmapDrawable image) {
+ protected void onPostExecute(final Bitmap image) {
mLoadTasks.remove(mId);
dispatchResult(mPageUrl, image, mListener);
}
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java
index dee8dc30be38..7acd6a8c03f1 100644
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -46,7 +46,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -2746,9 +2745,9 @@ abstract public class GeckoApp
if (tab != null) {
String url = tab.getURL();
String title = tab.getDisplayTitle();
- BitmapDrawable favicon = (BitmapDrawable)(tab.getFavicon());
+ Bitmap favicon = tab.getFavicon();
if (url != null && title != null) {
- GeckoAppShell.createShortcut(title, url, url, favicon == null ? null : favicon.getBitmap(), "");
+ GeckoAppShell.createShortcut(title, url, url, favicon == null ? null : favicon, "");
}
}
return true;
diff --git a/mobile/android/base/Tab.java b/mobile/android/base/Tab.java
index 98a5a623fd55..2fe2dd04fc1b 100644
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -41,7 +41,7 @@ public class Tab {
private long mLastUsed;
private String mUrl;
private String mTitle;
- private Drawable mFavicon;
+ private Bitmap mFavicon;
private String mFaviconUrl;
private int mFaviconSize;
private JSONObject mIdentityData;
@@ -147,7 +147,7 @@ public class Tab {
return mUrl;
}
- public Drawable getFavicon() {
+ public Bitmap getFavicon() {
return mFavicon;
}
@@ -325,7 +325,7 @@ public class Tab {
return mFaviconLoadId;
}
- public void updateFavicon(Drawable favicon) {
+ public void updateFavicon(Bitmap favicon) {
mFavicon = favicon;
}
diff --git a/mobile/android/base/awesomebar/AllPagesTab.java b/mobile/android/base/awesomebar/AllPagesTab.java
index 26eca1f0723b..63deae5c7dc5 100644
--- a/mobile/android/base/awesomebar/AllPagesTab.java
+++ b/mobile/android/base/awesomebar/AllPagesTab.java
@@ -22,7 +22,6 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -54,6 +53,7 @@ import android.widget.TabHost.TabContentFactory;
import android.widget.TextView;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -265,9 +265,19 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
if (keywordCol != -1)
keyword = mCursor.getString(keywordCol);
- return new ContextMenuSubject(id,
- mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL)),
- mCursor.getBlob(mCursor.getColumnIndexOrThrow(URLColumns.FAVICON)),
+ final String url = mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.URL));
+
+ Favicons favicons = GeckoApp.mAppContext.getFavicons();
+ Bitmap bitmap = favicons.getFaviconFromMemCache(url);
+ byte[] favicon = null;
+
+ if (bitmap != null) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+ favicon = stream.toByteArray();
+ }
+
+ return new ContextMenuSubject(id, url, favicon,
mCursor.getString(mCursor.getColumnIndexOrThrow(URLColumns.TITLE)),
keyword,
mCursor.getInt(mCursor.getColumnIndexOrThrow(Combined.DISPLAY)));
@@ -770,8 +780,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
if (favicon == null)
continue;
- Drawable faviconDrawable = new BitmapDrawable(getResources(), favicon);
- favicons.putFaviconInMemCache(url, faviconDrawable);
+ favicons.putFaviconInMemCache(url, favicon);
} while (c.moveToNext());
} finally {
if (c != null)
@@ -801,7 +810,7 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
private void displayFavicon(AwesomeEntryViewHolder viewHolder) {
final String url = viewHolder.urlView.getText().toString();
Favicons favicons = GeckoApp.mAppContext.getFavicons();
- viewHolder.faviconView.setImageDrawable(favicons.getFaviconFromMemCache(url));
+ viewHolder.faviconView.setImageBitmap(favicons.getFaviconFromMemCache(url));
}
private void updateFavicons() {
diff --git a/mobile/android/base/db/BrowserDB.java b/mobile/android/base/db/BrowserDB.java
index 93ea89a0e8b8..d862f9429ddb 100644
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -10,6 +10,7 @@ import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import java.util.List;
@@ -73,11 +74,11 @@ public class BrowserDB {
public void removeReadingListItemWithURL(ContentResolver cr, String uri);
- public BitmapDrawable getFaviconForUrl(ContentResolver cr, String uri);
+ public Bitmap getFaviconForUrl(ContentResolver cr, String uri);
public Cursor getFaviconsForUrls(ContentResolver cr, List urls);
- public void updateFaviconForUrl(ContentResolver cr, String uri, BitmapDrawable favicon);
+ public void updateFaviconForUrl(ContentResolver cr, String uri, Bitmap favicon);
public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
@@ -190,7 +191,7 @@ public class BrowserDB {
sDb.removeReadingListItemWithURL(cr, uri);
}
- public static BitmapDrawable getFaviconForUrl(ContentResolver cr, String uri) {
+ public static Bitmap getFaviconForUrl(ContentResolver cr, String uri) {
return sDb.getFaviconForUrl(cr, uri);
}
@@ -198,7 +199,7 @@ public class BrowserDB {
return sDb.getFaviconsForUrls(cr, urls);
}
- public static void updateFaviconForUrl(ContentResolver cr, String uri, BitmapDrawable favicon) {
+ public static void updateFaviconForUrl(ContentResolver cr, String uri, Bitmap favicon) {
sDb.updateFaviconForUrl(cr, uri, favicon);
}
diff --git a/mobile/android/base/db/LocalBrowserDB.java b/mobile/android/base/db/LocalBrowserDB.java
index 6b14966c9413..16b3380ac742 100644
--- a/mobile/android/base/db/LocalBrowserDB.java
+++ b/mobile/android/base/db/LocalBrowserDB.java
@@ -626,7 +626,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
new String[] { String.valueOf(id) });
}
- public BitmapDrawable getFaviconForUrl(ContentResolver cr, String uri) {
+ public Bitmap getFaviconForUrl(ContentResolver cr, String uri) {
Cursor c = cr.query(mImagesUriWithProfile,
new String[] { Images.FAVICON },
Images.URL + " = ?",
@@ -646,8 +646,7 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
if (b == null)
return null;
- Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
- return new BitmapDrawable(bitmap);
+ return BitmapFactory.decodeByteArray(b, 0, b.length);
}
public Cursor getFaviconsForUrls(ContentResolver cr, List urls) {
@@ -672,13 +671,9 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
}
public void updateFaviconForUrl(ContentResolver cr, String uri,
- BitmapDrawable favicon) {
- Bitmap bitmap = favicon.getBitmap();
- if (bitmap == null)
- return;
-
+ Bitmap favicon) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+ favicon.compress(Bitmap.CompressFormat.PNG, 100, stream);
ContentValues values = new ContentValues();
values.put(Images.FAVICON, stream.toByteArray());
diff --git a/parser/xml/public/nsISAXXMLReader.idl b/parser/xml/public/nsISAXXMLReader.idl
index 52d8fbf19106..e175cac24e28 100644
--- a/parser/xml/public/nsISAXXMLReader.idl
+++ b/parser/xml/public/nsISAXXMLReader.idl
@@ -79,7 +79,7 @@ interface nsISAXXMLReader : nsIStreamListener {
attribute nsISAXLexicalHandler lexicalHandler;
/**
- * Set the value of a feature flag. NOT CURRENTLY IMPLEMENTED.
+ * Set the value of a feature flag.
*
* The feature name is any fully-qualified URI. It is possible
* for an XMLReader to expose a feature value but to be unable to
@@ -93,11 +93,15 @@ interface nsISAXXMLReader : nsIStreamListener {
*
* @param name String flag for a parser feature.
* @param value Turn the feature on/off.
+ *
+ * @note This is currently supported only for
+ * http://xml.org/sax/features/namespace-prefixes . All other
+ * features will result in a NOT_IMPLEMENTED exception.
*/
void setFeature(in AString name, in boolean value);
/**
- * Look up the value of a feature flag. NOT CURRENTLY IMPLEMENTED.
+ * Look up the value of a feature flag.
*
* The feature name is any fully-qualified URI. It is
* possible for an XMLReader to recognize a feature name but
@@ -110,6 +114,10 @@ interface nsISAXXMLReader : nsIStreamListener {
* http://xml.org/sax/features/namespace-prefixes feature names.
*
* @param name String flag for a parser feature.
+ *
+ * @note This is currently supported only for
+ * http://xml.org/sax/features/namespace-prefixes . All other
+ * features will result in a NOT_IMPLEMENTED exception.
*/
boolean getFeature(in AString name);
diff --git a/parser/xml/src/nsSAXXMLReader.cpp b/parser/xml/src/nsSAXXMLReader.cpp
index 457728f55658..66c8da126574 100644
--- a/parser/xml/src/nsSAXXMLReader.cpp
+++ b/parser/xml/src/nsSAXXMLReader.cpp
@@ -52,7 +52,9 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSAXXMLReader)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISAXXMLReader)
NS_INTERFACE_MAP_END
-nsSAXXMLReader::nsSAXXMLReader() : mIsAsyncParse(false)
+nsSAXXMLReader::nsSAXXMLReader() :
+ mIsAsyncParse(false),
+ mEnableNamespacePrefixes(false)
{
}
@@ -101,7 +103,7 @@ nsSAXXMLReader::HandleStartElement(const PRUnichar *aName,
// XXX don't have attr type information
NS_NAMED_LITERAL_STRING(cdataType, "CDATA");
// could support xmlns reporting, it's a standard SAX feature
- if (!uri.EqualsLiteral(XMLNS_URI)) {
+ if (mEnableNamespacePrefixes || !uri.EqualsLiteral(XMLNS_URI)) {
NS_ASSERTION(aAtts[1], "null passed to handler");
atts->AddAttribute(uri, localName, qName, cdataType,
nsDependentString(aAtts[1]));
@@ -397,12 +399,20 @@ nsSAXXMLReader::SetErrorHandler(nsISAXErrorHandler *aErrorHandler)
NS_IMETHODIMP
nsSAXXMLReader::SetFeature(const nsAString &aName, bool aValue)
{
+ if (aName.EqualsLiteral("http://xml.org/sax/features/namespace-prefixes")) {
+ mEnableNamespacePrefixes = aValue;
+ return NS_OK;
+ }
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsSAXXMLReader::GetFeature(const nsAString &aName, bool *aResult)
{
+ if (aName.EqualsLiteral("http://xml.org/sax/features/namespace-prefixes")) {
+ *aResult = mEnableNamespacePrefixes;
+ return NS_OK;
+ }
return NS_ERROR_NOT_IMPLEMENTED;
}
diff --git a/parser/xml/src/nsSAXXMLReader.h b/parser/xml/src/nsSAXXMLReader.h
index 0472c2e52473..d6f1bb10b0eb 100644
--- a/parser/xml/src/nsSAXXMLReader.h
+++ b/parser/xml/src/nsSAXXMLReader.h
@@ -94,6 +94,9 @@ private:
nsString &aQName);
nsString mPublicId;
nsString mSystemId;
+
+ // Feature flags
+ bool mEnableNamespacePrefixes;
};
#endif // nsSAXXMLReader_h__
diff --git a/parser/xml/test/unit/test_namespace_support.js b/parser/xml/test/unit/test_namespace_support.js
new file mode 100644
index 000000000000..bcad61e912b6
--- /dev/null
+++ b/parser/xml/test/unit/test_namespace_support.js
@@ -0,0 +1,52 @@
+function noop() {}
+
+function run_test() {
+ var contentHandler = {
+ attrs: null,
+ reset: function() {
+ this.attrs = [];
+ },
+ startDocument: noop,
+ endDocument: noop,
+
+ startElement: function startElement(aNamespaceURI, aLocalName, aNodeName, aAttrs) {
+ for (var i = 0; i < aAttrs.length; i++)
+ this.attrs.push(aAttrs.getQName(i));
+ },
+
+ endElement: noop,
+ characters: noop,
+ processingInstruction: noop,
+ ignorableWhitespace: noop,
+ startPrefixMapping: noop,
+ endPrefixMapping: noop
+ };
+
+ const nsISAXXMLReader = Components.interfaces.nsISAXXMLReader;
+ const src = "";
+ const NS_PREFIX = "http://xml.org/sax/features/namespace-prefixes";
+
+ var saxReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"]
+ .createInstance(nsISAXXMLReader);
+ do_check_false(saxReader.getFeature(NS_PREFIX));
+ saxReader.contentHandler = contentHandler;
+ contentHandler.reset();
+ saxReader.parseFromString(src, "application/xml");
+ do_check_eq(contentHandler.attrs.length, 1);
+ do_check_eq(contentHandler.attrs[0], "y");
+
+ saxReader.setFeature(NS_PREFIX, true);
+ do_check_true(saxReader.getFeature(NS_PREFIX));
+ contentHandler.reset();
+ saxReader.parseFromString(src, "application/xml");
+ do_check_eq(contentHandler.attrs.length, 2);
+ do_check_eq(contentHandler.attrs[0], "xmlns:a");
+ do_check_eq(contentHandler.attrs[1], "y");
+
+ saxReader.setFeature(NS_PREFIX, false);
+ do_check_false(saxReader.getFeature(NS_PREFIX));
+ contentHandler.reset();
+ saxReader.parseFromString(src, "application/xml");
+ do_check_eq(contentHandler.attrs.length, 1);
+ do_check_eq(contentHandler.attrs[0], "y");
+}
diff --git a/parser/xml/test/unit/xpcshell.ini b/parser/xml/test/unit/xpcshell.ini
index 9b44aede56be..c9be720c8226 100644
--- a/parser/xml/test/unit/xpcshell.ini
+++ b/parser/xml/test/unit/xpcshell.ini
@@ -3,3 +3,4 @@ head =
tail =
[test_parser.js]
+[test_namespace_support.js]
diff --git a/testing/mochitest/b2g.json b/testing/mochitest/b2g.json
index e9ceb8fe23b0..7ff3c3f747ba 100644
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -1,5 +1,6 @@
{
"runtests": {
+ "dom/base": "",
"dom/tests/mochitest/dom-level0": "",
"dom/tests/mochitest/dom-level1-core": "",
"dom/tests/mochitest/dom-level2-core": "",
diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py
index 4afe3bd102f5..e8389f5ebb6f 100644
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -488,7 +488,7 @@ def main():
mochitest.cleanup(None, options)
retVal = mochitest.runTests(options)
except:
- print "TEST-UNEXPECTED-FAIL | %s | Exception caught while running tests." % sys.exc_info()[1]
+ print "Automation Error: Exception caught while running tests"
traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
diff --git a/testing/mochitest/runtestsremote.py b/testing/mochitest/runtestsremote.py
index 0aa06731dcc9..ae2eaf7a5c67 100644
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -7,6 +7,7 @@ import os
import time
import tempfile
import re
+import traceback
sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))))
@@ -498,7 +499,8 @@ def main():
retVal = mochitest.runTests(options)
mochitest.addLogData()
except:
- print "TEST-UNEXPECTED-FAIL | %s | Exception caught while running robocop tests." % sys.exc_info()[1]
+ print "Automation Error: Exception caught while running tests"
+ traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
try:
@@ -521,7 +523,8 @@ def main():
dm.recordLogcat()
retVal = mochitest.runTests(options)
except:
- print "TEST-UNEXPECTED-FAIL | %s | Exception caught while running tests." % sys.exc_info()[1]
+ print "Automation Error: Exception caught while running tests"
+ traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
try:
diff --git a/testing/xpcshell/runtestsb2g.py b/testing/xpcshell/runtestsb2g.py
index 3c7f4a824ac8..4bab4db3249a 100644
--- a/testing/xpcshell/runtestsb2g.py
+++ b/testing/xpcshell/runtestsb2g.py
@@ -154,7 +154,7 @@ def main():
try:
success = xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:], **options.__dict__)
except:
- print "TEST-UNEXPECTED-FAIL | %s | Exception caught while running tests." % sys.exc_info()[1]
+ print "Automation Error: Exception caught while running tests"
traceback.print_exc()
sys.exit(1)
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 423166e016c5..20129c501b66 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -103,6 +103,9 @@ using mozilla::scache::StartupCache;
#include "nsIWinAppHelper.h"
#include
#include "cairo/cairo-features.h"
+#ifdef MOZ_METRO
+#include
+#endif
#ifndef PROCESS_DEP_ENABLE
#define PROCESS_DEP_ENABLE 0x1
@@ -3958,13 +3961,149 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
return NS_FAILED(rv) ? 1 : 0;
}
+#if defined(MOZ_METRO) && defined(XP_WIN)
+extern bool XRE_MetroCoreApplicationRun();
+static XREMain* xreMainPtr;
+
+// must be called by the thread we want as the main thread
+nsresult
+XRE_metroStartup()
+{
+ nsresult rv;
+
+ bool exit = false;
+ if (xreMainPtr->XRE_mainStartup(&exit) != 0 || exit)
+ return NS_ERROR_FAILURE;
+
+ // Start the real application
+ xreMainPtr->mScopedXPCom = new ScopedXPCOMStartup();
+ if (!xreMainPtr->mScopedXPCom)
+ return NS_ERROR_FAILURE;
+
+ rv = xreMainPtr->mScopedXPCom->Initialize();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = xreMainPtr->XRE_mainRun();
+ NS_ENSURE_SUCCESS(rv, rv);
+ return NS_OK;
+}
+
+void
+XRE_metroShutdown()
+{
+ delete xreMainPtr->mScopedXPCom;
+ xreMainPtr->mScopedXPCom = nullptr;
+
+#ifdef MOZ_INSTRUMENT_EVENT_LOOP
+ mozilla::ShutdownEventTracing();
+#endif
+
+ // unlock the profile after ScopedXPCOMStartup object (xpcom)
+ // has gone out of scope. see bug #386739 for more details
+ xreMainPtr->mProfileLock->Unlock();
+ gProfileLock = nullptr;
+
+#ifdef MOZ_CRASHREPORTER
+ if (xreMainPtr->mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER)
+ CrashReporter::UnsetExceptionHandler();
+#endif
+
+ XRE_DeinitCommandLine();
+}
+
+class WinRTInitWrapper
+{
+public:
+ WinRTInitWrapper() {
+ mResult = ::RoInitialize(RO_INIT_MULTITHREADED);
+ }
+ ~WinRTInitWrapper() {
+ if (SUCCEEDED(mResult)) {
+ ::RoUninitialize();
+ }
+ }
+ HRESULT mResult;
+};
+
+int
+XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
+{
+ SAMPLER_INIT();
+ SAMPLE_LABEL("Startup", "XRE_Main");
+
+ nsresult rv = NS_OK;
+
+ xreMainPtr = new XREMain();
+ if (!xreMainPtr) {
+ return 1;
+ }
+
+ // Inits Winrt and COM underneath it.
+ WinRTInitWrapper wrap;
+
+ gArgc = argc;
+ gArgv = argv;
+
+ NS_ENSURE_TRUE(aAppData, 2);
+
+ xreMainPtr->mAppData = new ScopedAppData(aAppData);
+ if (!xreMainPtr->mAppData)
+ return 1;
+ // used throughout this file
+ gAppData = xreMainPtr->mAppData;
+
+ ScopedLogging log;
+
+ // init
+ bool exit = false;
+ if (xreMainPtr->XRE_mainInit(aAppData, &exit) != 0 || exit)
+ return 1;
+
+ // Located in widget, will call back into XRE_metroStartup and
+ // XRE_metroShutdown above.
+ if (!XRE_MetroCoreApplicationRun()) {
+ return 1;
+ }
+
+ // XRE_metroShutdown should have already been called on the worker
+ // thread that called XRE_metroStartup.
+ NS_ASSERTION(!xreMainPtr->mScopedXPCom,
+ "XPCOM Shutdown hasn't occured, and we are exiting.");
+ return 0;
+}
+
+void SetWindowsEnvironment(WindowsEnvironmentType aEnvID);
+#endif // MOZ_METRO || !defined(XP_WIN)
+
int
XRE_main(int argc, char* argv[], const nsXREAppData* aAppData, uint32_t aFlags)
{
+#if !defined(MOZ_METRO) || !defined(XP_WIN)
XREMain main;
int result = main.XRE_main(argc, argv, aAppData);
mozilla::RecordShutdownEndTimeStamp();
return result;
+#else
+ if (aFlags == XRE_MAIN_FLAG_USE_METRO) {
+ SetWindowsEnvironment(WindowsEnvironmentType_Metro);
+ }
+
+ // Desktop
+ if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
+ XREMain main;
+ int result = main.XRE_main(argc, argv, aAppData);
+ mozilla::RecordShutdownEndTimeStamp();
+ return result;
+ }
+
+ // Metro
+ NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro,
+ "Unknown Windows environment");
+
+ int result = XRE_mainMetro(argc, argv, aAppData);
+ mozilla::RecordShutdownEndTimeStamp();
+ return result;
+#endif // MOZ_METRO || !defined(XP_WIN)
}
nsresult