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