Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-11-05 15:23:36 +00:00
commit a5572ca7ff
37 changed files with 882 additions and 174 deletions

View File

@ -122,7 +122,7 @@
<content>
<xul:hbox align="end" pack="end" anonid="innerbox" class="chatbar-innerbox" mousethrough="always" flex="1">
<xul:toolbarbutton anonid="nub" class="chatbar-button" type="menu" collapsed="true" mousethrough="never">
<xul:menupopup anonid="nubMenu" oncommand="document.getBindingParent(this).swapChat(event)"/>
<xul:menupopup anonid="nubMenu" oncommand="document.getBindingParent(this).showChat(event.target.chat)"/>
</xul:toolbarbutton>
<xul:spacer flex="1" anonid="spacer" class="chatbar-overflow-spacer"/>
<children/>
@ -130,6 +130,12 @@
</content>
<implementation implements="nsIDOMEventListener">
<constructor>
// to avoid reflows we cache the values for various widths.
this.cachedWidthOpen = 0;
this.cachedWidthMinimized = 0;
this.cachedWidthNub = 0;
</constructor>
<field name="innerbox" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "innerbox");
@ -143,22 +149,27 @@
document.getAnonymousElementByAttribute(this, "anonid", "nub");
</field>
<property name="emptyWidth">
<getter>
return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
</getter>
</property>
<property name="selectedChat">
<getter><![CDATA[
return this._selectedChat;
]]></getter>
<setter><![CDATA[
if (this._selectedChat)
this._selectedChat.removeAttribute("selected");
this._selectedChat = val;
// this is pretty horrible, but we:
// * want to avoid doing touching 'selected' attribute when the
// specified chat is already selected.
// * remove 'activity' attribute on newly selected tab *even if*
// newly selected is already selected.
// * need to handle either current or new being null.
if (this._selectedChat != val) {
if (this._selectedChat) {
this._selectedChat.removeAttribute("selected");
}
this._selectedChat = val;
if (val) {
this._selectedChat.setAttribute("selected", "true");
}
}
if (val) {
this._selectedChat.setAttribute("selected", "true");
this._selectedChat.removeAttribute("activity");
}
]]></setter>
@ -167,55 +178,48 @@
<field name="menuitemMap">new WeakMap()</field>
<field name="chatboxForURL">new Map();</field>
<property name="firstCollapsedChild">
<property name="hasCollapsedChildren">
<getter><![CDATA[
return !!this.querySelector("[collapsed]");
]]></getter>
</property>
<property name="collapsedChildren">
<getter><![CDATA[
// A generator yielding all collapsed chatboxes, in the order in
// which they should be restored.
let child = this.lastChild;
while (child && !child.collapsed) {
while (child) {
if (child.collapsed)
yield child;
child = child.previousSibling;
}
return child;
]]></getter>
</property>
<property name="firstVisibleChild">
<property name="visibleChildren">
<getter><![CDATA[
// A generator yielding all non-collapsed chatboxes.
let child = this.firstChild;
while (child && child.collapsed) {
while (child) {
if (!child.collapsed)
yield child;
child = child.nextSibling;
}
return child;
]]></getter>
</property>
<property name="firstRemovableChild">
<property name="collapsibleChildren">
<getter><![CDATA[
let child = this.firstChild;
// find the first visible non-focused chatbox, always keep one visible if we
// have enough width to do so.
while (child &&
(child.collapsed || child == this.selectedChat)) {
child = child.nextSibling;
}
if (!child && this.selectedChat) {
child = this.selectedChat;
}
return child;
// A generator yielding all children which are able to be collapsed
// in the order in which they should be collapsed.
// (currently this is all visible ones other than the selected one.)
for (let child of this.visibleChildren)
if (child != this.selectedChat)
yield child;
]]></getter>
</property>
<method name="resize">
<body><![CDATA[
let child = this.firstCollapsedChild;
if (child && this.emptyWidth > child.viewWidth) {
this.showChat(child);
}
if (!this.firstCollapsedChild) {
window.removeEventListener("resize", this);
this.menupopup.parentNode.collapsed = true;
}
]]></body>
</method>
<method name="updateTitlebar">
<parameter name="aChatbox"/>
<body><![CDATA[
@ -231,32 +235,46 @@
]]></body>
</method>
<method name="handleEvent">
<parameter name="aEvent"/>
<method name="calcTotalWidthOf">
<parameter name="aElement"/>
<body><![CDATA[
if (aEvent.type == "resize") {
this.resize();
}
let cs = document.defaultView.getComputedStyle(aElement);
let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight);
return aElement.getBoundingClientRect().width + margins;
]]></body>
</method>
<method name="swapChat">
<parameter name="aEvent"/>
<method name="getTotalChildWidth">
<parameter name="aChatbox"/>
<body><![CDATA[
let menuitem = aEvent.target;
let newChat = menuitem.chat;
let oldChat = this.firstVisibleChild;
if (oldChat)
this.collapseChat(oldChat);
if (newChat)
this.showChat(newChat);
// gets the width of a child, using/setting the cached value for
// children of this type.
// DOES NOT take collapsed into account - ie, this is the width
// of a child assuming it is *not* collapsed. (collapsed chats
// have a width of zero as they are not shown).
if (aChatbox.minimized) {
if (!this.cachedWidthMinimized) {
if (aChatbox.collapsed)
throw new Error("can't calculate size of collapsed chat!");
this.cachedWidthMinimized = this.calcTotalWidthOf(aChatbox);
}
return this.cachedWidthMinimized;
}
if (!this.cachedWidthOpen) {
if (aChatbox.collapsed)
throw new Error("can't calculate size of collapsed chat!");
this.cachedWidthOpen = this.calcTotalWidthOf(aChatbox);
}
return this.cachedWidthOpen;
]]></body>
</method>
<method name="collapseChat">
<parameter name="aChatbox"/>
<body><![CDATA[
aChatbox.viewWidth = aChatbox.getBoundingClientRect().width;
// we ensure that the cached width for a child of this type is
// up-to-date so we can use it when resizing.
this.getTotalChildWidth(aChatbox);
aChatbox.collapsed = true;
aChatbox.isActive = false;
let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
@ -266,13 +284,31 @@
menu.chat = aChatbox;
this.menuitemMap.set(aChatbox, menu);
this.menupopup.appendChild(menu);
this.menupopup.parentNode.collapsed = false;
this.nub.collapsed = false;
]]></body>
</method>
<method name="showChat">
<parameter name="aChatbox"/>
<body><![CDATA[
if (aChatbox.minimized)
aChatbox.minimized = false;
if (this.selectedChat != aChatbox)
this.selectedChat = aChatbox;
if (!aChatbox.collapsed)
return; // already showing - no more to do.
this._showChat(aChatbox);
// showing a collapsed chat might mean another needs to be collapsed
// to make room...
this.resize();
]]></body>
</method>
<method name="_showChat">
<parameter name="aChatbox"/>
<body><![CDATA[
// the actual implementation - doesn't check for overflow, assumes
// collapsed, etc.
let menuitem = this.menuitemMap.get(aChatbox);
this.menuitemMap.delete(aChatbox);
this.menupopup.removeChild(menuitem);
@ -282,13 +318,28 @@
</method>
<method name="remove">
<parameter name="aChatbox"/>
<body><![CDATA[
this._remove(aChatbox);
// The removal of a chat may mean a collapsed one can spring up,
// or that the popup should be hidden.
this.resize();
]]></body>
</method>
<method name="_remove">
<parameter name="aChatbox"/>
<body><![CDATA[
if (this.selectedChat == aChatbox) {
this.selectedChat = aChatbox.previousSibling ? aChatbox.previousSibling : aChatbox.nextSibling
}
this.removeChild(aChatbox);
this.resize();
// child might have been collapsed.
let menuitem = this.menuitemMap.get(aChatbox);
if (menuitem) {
this.menuitemMap.delete(aChatbox);
this.menupopup.removeChild(menuitem);
}
this.chatboxForURL.delete(aChatbox.getAttribute('src'));
]]></body>
</method>
@ -296,9 +347,10 @@
<method name="removeAll">
<body><![CDATA[
while (this.firstChild) {
this.removeChild(this.firstChild);
this._remove(this.firstChild);
}
this.chatboxForURL = new Map();
// and the nub/popup must also die.
this.nub.collapsed = true;
]]></body>
</method>
@ -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();
]]></body>
</method>
<method name="resize">
<body><![CDATA[
// Checks the current size against the collapsed state of children
// and collapses or expands as necessary such that as many as possible
// are shown.
// So 2 basic strategies:
// * Collapse/Expand one at a time until we can't collapse/expand any
// more - but this is one reflow per change.
// * Calculate the dimensions ourself and choose how many to collapse
// or expand based on this, then do them all in one go. This is one
// reflow regardless of how many we change.
// So we go the more complicated but more efficient second option...
let availWidth = this.getBoundingClientRect().width;
let currentWidth = 0;
if (!this.nub.collapsed) { // the nub is visible.
if (!this.cachedWidthNub)
this.cachedWidthNub = this.calcTotalWidthOf(this.nub);
currentWidth += this.cachedWidthNub;
}
for (let child of this.visibleChildren) {
currentWidth += this.getTotalChildWidth(child);
}
if (currentWidth > 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!
]]></body>
</method>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
if (aEvent.type == "resize") {
this.resize();
}
]]></body>
</method>
@ -338,18 +455,11 @@
<handler event="popupshown"><![CDATA[
this.nub.removeAttribute("activity");
]]></handler>
<handler event="overflow"><![CDATA[
// make sure we're not getting an overflow from content
if (event.originalTarget != this.innerbox)
return;
let hasHidden = this.firstCollapsedChild;
let child = this.firstRemovableChild;
if (child)
this.collapseChat(child);
if (!hasHidden) {
window.addEventListener("resize", this);
}
<handler event="load"><![CDATA[
window.addEventListener("resize", this);
]]></handler>
<handler event="unload"><![CDATA[
window.removeEventListener("resize", this);
]]></handler>
</handlers>
</binding>

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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<nsIPowerManagerService> 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;
}

View File

@ -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 <nsIIdleService> mIdleService;
nsCOMPtr <nsIDOMMozWakeLock> mWakeLock;
static bool sIdleObserversAPIFuzzTimeDisabled;
friend class HashchangeCallback;

View File

@ -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

View File

@ -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<GlobalNameMapEntry*>(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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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<RefLayer*>(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 {

View File

@ -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)

View File

@ -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:

View File

@ -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() {

View File

@ -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)

View File

@ -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);
}

View File

@ -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<Long,LoadFaviconTask> mLoadTasks;
private long mNextFaviconLoadId;
private LruCache<String, Drawable> mFaviconsCache;
private LruCache<String, Bitmap> 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<String, Drawable>(1024 * 1024) {
mFaviconsCache = new LruCache<String, Bitmap>(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<Void, Void, BitmapDrawable> {
private class LoadFaviconTask extends AsyncTask<Void, Void, Bitmap> {
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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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() {

View File

@ -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<String> 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);
}

View File

@ -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<String> 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());

View File

@ -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);

View File

@ -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;
}

View File

@ -94,6 +94,9 @@ private:
nsString &aQName);
nsString mPublicId;
nsString mSystemId;
// Feature flags
bool mEnableNamespacePrefixes;
};
#endif // nsSAXXMLReader_h__

View File

@ -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 = "<a:x xmlns:a='foo' y='bar'/>";
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");
}

View File

@ -3,3 +3,4 @@ head =
tail =
[test_parser.js]
[test_namespace_support.js]

View File

@ -1,5 +1,6 @@
{
"runtests": {
"dom/base": "",
"dom/tests/mochitest/dom-level0": "",
"dom/tests/mochitest/dom-level1-core": "",
"dom/tests/mochitest/dom-level2-core": "",

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -103,6 +103,9 @@ using mozilla::scache::StartupCache;
#include "nsIWinAppHelper.h"
#include <windows.h>
#include "cairo/cairo-features.h"
#ifdef MOZ_METRO
#include <roapi.h>
#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