merge fx-team to mozilla-inbound a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-12-23 16:04:26 +01:00
commit 405ad2ed16
139 changed files with 1653 additions and 1195 deletions

3
.gitignore vendored
View File

@ -67,3 +67,6 @@ GPATH
# Git clone directory for updating web-platform-tests
testing/web-platform/sync/
# Android Gradle artifacts.
mobile/android/gradle/.gradle

View File

@ -93,3 +93,6 @@ GPATH
# including the following three lines
^browser/components/loop/standalone/content/legal/styles/.*\.css$
^browser/components/loop/standalone/content/legal/terms/en_US\.html$
# Android Gradle artifacts.
^mobile/android/gradle/.gradle

View File

@ -479,11 +479,9 @@ SocialShare = {
},
get iframe() {
// first element is our menu vbox.
if (this.panel.childElementCount == 1)
return null;
else
return this.panel.lastChild;
// panel.firstChild is our toolbar hbox, panel.lastChild is the iframe
// container hbox used for an interstitial "loading" graphic
return this.panel.lastChild.firstChild;
},
uninit: function () {
@ -505,7 +503,7 @@ SocialShare = {
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("disableglobalhistory", "true");
iframe.setAttribute("flex", "1");
panel.appendChild(iframe);
panel.lastChild.appendChild(iframe);
iframe.addEventListener("load", function _firstload() {
iframe.removeEventListener("load", _firstload, true);
iframe.messageManager.loadFrameScript("chrome://browser/content/content.js", true);
@ -537,13 +535,13 @@ SocialShare = {
// remove everything before the add-share-provider button (which should also
// be lastChild if any share providers were added)
let addButton = document.getElementById("add-share-provider");
while (hbox.firstChild != addButton) {
hbox.removeChild(hbox.firstChild);
while (hbox.lastChild != addButton) {
hbox.removeChild(hbox.lastChild);
}
let selectedProvider = this.getSelectedProvider();
for (let provider of providers) {
let button = document.createElement("toolbarbutton");
button.setAttribute("class", "toolbarbutton share-provider-button");
button.setAttribute("class", "toolbarbutton-1 share-provider-button");
button.setAttribute("type", "radio");
button.setAttribute("group", "share-providers");
button.setAttribute("image", provider.iconURL);
@ -554,7 +552,7 @@ SocialShare = {
if (provider == selectedProvider) {
this.defaultButton = button;
}
hbox.insertBefore(button, addButton);
hbox.appendChild(button);
}
if (!this.defaultButton) {
this.defaultButton = addButton;
@ -577,7 +575,7 @@ SocialShare = {
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(0);
},
onShowing: function() {
this.anchor.setAttribute("open", "true");
this.iframe.addEventListener("click", this._onclick, true);
@ -682,48 +680,40 @@ SocialShare = {
let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
this._dynamicResizer.stop();
let size = provider.getPageSize("share");
if (size) {
this._dynamicResizer.stop();
// let the css on the share panel define width, but height
// calculations dont work on all sites, so we allow that to be
// defined.
delete size.width;
}
// if we've already loaded this provider/page share endpoint, we don't want
// to add another load event listener.
let reload = true;
let endpointMatch = shareEndpoint == iframe.getAttribute("src");
let docLoaded = iframe.contentDocument && iframe.contentDocument.readyState == "complete";
if (endpointMatch && docLoaded) {
reload = shareEndpoint != iframe.contentDocument.location.spec;
}
if (!reload) {
if (!size)
this._dynamicResizer.start(this.panel, iframe);
if (endpointMatch) {
this._dynamicResizer.start(iframe.parentNode, iframe, size);
iframe.docShell.isActive = true;
iframe.docShell.isAppTab = true;
let evt = iframe.contentDocument.createEvent("CustomEvent");
evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
iframe.contentDocument.documentElement.dispatchEvent(evt);
} else {
iframe.parentNode.setAttribute("loading", "true");
// first time load, wait for load and dispatch after load
iframe.addEventListener("load", function panelBrowserOnload(e) {
iframe.removeEventListener("load", panelBrowserOnload, true);
iframe.docShell.isActive = true;
iframe.docShell.isAppTab = true;
iframe.parentNode.removeAttribute("loading");
// to support standard share endpoints mimick window.open by setting
// window.opener, some share endpoints rely on w.opener to know they
// should close the window when done.
iframe.contentWindow.opener = iframe.contentWindow;
setTimeout(function() {
if (size) {
let panel = SocialShare.panel;
let {width, height} = size;
width += panel.boxObject.width - iframe.boxObject.width;
height += panel.boxObject.height - iframe.boxObject.height;
panel.sizeTo(width, height);
} else {
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
}
}, 0);
SocialShare._dynamicResizer.start(iframe.parentNode, iframe, size);
let evt = iframe.contentDocument.createEvent("CustomEvent");
evt.initCustomEvent("OpenGraphData", true, true, JSON.stringify(pageData));
iframe.contentDocument.documentElement.dispatchEvent(evt);
@ -747,9 +737,18 @@ SocialShare = {
showDirectory: function() {
this._createFrame();
let iframe = this.iframe;
if (iframe.getAttribute("src") == "about:providerdirectory")
return;
iframe.removeAttribute("origin");
iframe.parentNode.setAttribute("loading", "true");
iframe.addEventListener("DOMContentLoaded", function _dcl(e) {
iframe.removeEventListener("DOMContentLoaded", _dcl, true);
iframe.parentNode.removeAttribute("loading");
}, true);
iframe.addEventListener("load", function panelBrowserOnload(e) {
iframe.removeEventListener("load", panelBrowserOnload, true);
hookWindowCloseForPanelClose(iframe.contentWindow);
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);

View File

@ -287,17 +287,22 @@
<panel id="social-share-panel"
class="social-panel"
type="arrow"
orient="horizontal"
orient="vertical"
onpopupshowing="SocialShare.onShowing()"
onpopuphidden="SocialShare.onHidden()"
hidden="true">
<vbox class="social-share-toolbar">
<arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1">
<hbox class="social-share-toolbar">
<toolbarbutton id="manage-share-providers" class="toolbarbutton share-provider-button"
tooltiptext="&social.addons.label;"
oncommand="BrowserOpenAddonsMgr('addons://list/service');
this.parentNode.parentNode.hidePopup();"/>
<arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
<toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
group="share-providers" tooltiptext="&findShareServices.label;"
oncommand="SocialShare.showDirectory()"/>
</arrowscrollbox>
</vbox>
</hbox>
<hbox id="share-container" flex="1"/>
</panel>
<panel id="social-notification-panel"

View File

@ -14,6 +14,12 @@ function test() {
};
runSocialTestWithProvider(manifest, function (finishcb) {
SocialSidebar.show();
// disable transitions for the test
let panel = document.getElementById("social-flyout-panel");
registerCleanupFunction(function () {
panel.removeAttribute("animate");
});
panel.setAttribute("animate", "false");
runSocialTests(tests, undefined, undefined, finishcb);
});
}
@ -21,8 +27,7 @@ function test() {
var tests = {
testOpenCloseFlyout: function(next) {
let panel = document.getElementById("social-flyout-panel");
panel.addEventListener("popupshowing", function onShowing() {
panel.removeEventListener("popupshowing", onShowing);
ensureEventFired(panel, "popupshown").then(() => {
is(panel.firstChild.contentDocument.readyState, "complete", "panel is loaded prior to showing");
});
let port = SocialSidebar.provider.getWorkerPort();
@ -75,8 +80,7 @@ var tests = {
is(cs.height, "400px", "should be 400px high");
is(iframe.boxObject.height, 400, "iframe should now be 400px high");
iframe.contentWindow.addEventListener("resize", function _doneHandler() {
iframe.contentWindow.removeEventListener("resize", _doneHandler, false);
ensureEventFired(iframe.contentWindow, "resize").then(() => {
cs = iframe.contentWindow.getComputedStyle(body);
is(cs.width, "500px", "should now be 500px wide");
@ -86,7 +90,7 @@ var tests = {
panel.hidePopup();
port.close();
next();
}, false);
});
SocialFlyout.dispatchPanelEvent("socialTest-MakeWider");
break;
}
@ -117,13 +121,12 @@ var tests = {
if (e.data.result != "shown")
return;
let iframe = panel.firstChild;
iframe.contentDocument.addEventListener("SocialTest-DoneCloseSelf", function _doneHandler() {
iframe.contentDocument.removeEventListener("SocialTest-DoneCloseSelf", _doneHandler, false);
ensureEventFired(iframe.contentDocument, "SocialTest-DoneCloseSelf").then(() => {
port.close();
is(panel.state, "closed", "flyout should have closed itself");
Services.prefs.setBoolPref(ALLOW_SCRIPTS_TO_CLOSE_PREF, oldAllowScriptsToClose);
next();
}, false);
});
is(panel.state, "open", "flyout should be open");
SocialFlyout.dispatchPanelEvent("socialTest-CloseSelf");
break;

View File

@ -31,7 +31,7 @@
</head>
<body style="width: 400px; height: 400px; margin: 0; overflow: hidden;" onload="pingWorker();">
<p>This is a test social flyout panel.</p>
<a id="traversal" href="http://mochi.test">test link</a>
<a id="traversal" href="https://test.example.com">test link</a>
</body>
</html>

View File

@ -1000,6 +1000,32 @@
class="search-setting-button search-panel-header"
label="&changeSearchSettings.button;"/>
</content>
<implementation>
<method name="updateHeader">
<body><![CDATA[
let currentEngine = Services.search.currentEngine;
let uri = currentEngine.iconURI;
if (uri) {
uri = uri.spec;
this.setAttribute("src", PlacesUtils.getImageURLForResolution(window, uri));
}
else {
// If the default has just been changed to a provider without icon,
// avoid showing the icon of the previous default provider.
this.removeAttribute("src");
}
const kBundleURI = "chrome://browser/locale/search.properties";
let bundle = Services.strings.createBundle(kBundleURI);
let headerText = bundle.formatStringFromName("searchHeader",
[currentEngine.name], 1);
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine-name")
.setAttribute("value", headerText);
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine")
.engine = currentEngine;
]]></body>
</method>
</implementation>
<handlers>
<handler event="popupshowing"><![CDATA[
// First handle deciding if we are showing the reduced version of the
@ -1022,26 +1048,7 @@
}
// Show the current default engine in the top header of the panel.
let currentEngine = Services.search.currentEngine;
let uri = currentEngine.iconURI;
if (uri) {
uri = uri.spec;
this.setAttribute("src", PlacesUtils.getImageURLForResolution(window, uri));
}
else {
// If the default has just been changed to a provider without icon,
// avoid showing the icon of the previous default provider.
this.removeAttribute("src");
}
const kBundleURI = "chrome://browser/locale/search.properties";
let bundle = Services.strings.createBundle(kBundleURI);
let headerText = bundle.formatStringFromName("searchHeader",
[currentEngine.name], 1);
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine-name")
.setAttribute("value", headerText);
document.getAnonymousElementByAttribute(this, "anonid", "searchbar-engine")
.engine = currentEngine;
this.updateHeader();
// Update the 'Search for <keywords> with:" header.
let headerSearchText =
@ -1074,6 +1081,8 @@
let addEngines = gBrowser.selectedBrowser.engines;
if (addEngines && addEngines.length > 0) {
const kBundleURI = "chrome://browser/locale/search.properties";
let bundle = Services.strings.createBundle(kBundleURI);
for (let engine of addEngines) {
let button = document.createElementNS(kXULNS, "button");
let label = bundle.formatStringFromName("cmd_addFoundEngine",
@ -1109,8 +1118,9 @@
hiddenList = [];
}
let currentEngineName = Services.search.currentEngine.name;
let engines = Services.search.getVisibleEngines()
.filter(e => e.name != currentEngine.name &&
.filter(e => e.name != currentEngineName &&
hiddenList.indexOf(e.name) == -1);
let header = document.getAnonymousElementByAttribute(this, "anonid",

View File

@ -784,6 +784,22 @@ let MozLoopServiceInternal = {
}, pc.id);
},
getChatWindowID: function(conversationWindowData) {
// Try getting a window ID that can (re-)identify this conversation, or resort
// to a globally unique one as a last resort.
// XXX We can clean this up once rooms and direct contact calling are the only
// two modes left.
let windowId = ("contact" in conversationWindowData) ?
conversationWindowData.contact._guid || gLastWindowId++ :
conversationWindowData.roomToken || conversationWindowData.callId ||
gLastWindowId++;
return windowId.toString();
},
getChatURL: function(chatWindowId) {
return "about:loopconversation#" + chatWindowId;
},
/**
* Opens the chat window
*
@ -794,20 +810,11 @@ let MozLoopServiceInternal = {
openChatWindow: function(conversationWindowData) {
// So I guess the origin is the loop server!?
let origin = this.loopServerUri;
// Try getting a window ID that can (re-)identify this conversation, or resort
// to a globally unique one as a last resort.
// XXX We can clean this up once rooms and direct contact calling are the only
// two modes left.
let windowId = ("contact" in conversationWindowData) ?
conversationWindowData.contact._guid || gLastWindowId++ :
conversationWindowData.roomToken || conversationWindowData.callId ||
gLastWindowId++;
// Store the id as a string, as that's what we use elsewhere.
windowId = windowId.toString();
let windowId = this.getChatWindowID(conversationWindowData);
gConversationWindowData.set(windowId, conversationWindowData);
let url = "about:loopconversation#" + windowId;
let url = this.getChatURL(windowId);
let callback = chatbox => {
// We need to use DOMContentLoaded as otherwise the injection will happen
@ -1099,36 +1106,7 @@ this.MozLoopService = {
}
});
// Resume the tour (re-opening the tab, if necessary) if someone else joins
// a room of ours and it's currently open.
LoopRooms.on("joined", (e, room, participant) => {
let isOwnerInRoom = false;
let isOtherInRoom = false;
if (!this.getLoopPref("gettingStarted.resumeOnFirstJoin")) {
return;
}
if (!room.participants) {
return;
}
// The particpant that joined isn't necessarily included in room.participants (depending on
// when the broadcast happens) so concatenate.
for (let participant of room.participants.concat(participant)) {
if (participant.owner) {
isOwnerInRoom = true;
} else {
isOtherInRoom = true;
}
}
if (!isOwnerInRoom || !isOtherInRoom) {
return;
}
this.resumeTour("open");
});
LoopRooms.on("joined", this.maybeResumeTourOnRoomJoined.bind(this));
// If expiresTime is not in the future and the user hasn't
// previously authenticated then skip registration.
@ -1144,6 +1122,49 @@ this.MozLoopService = {
return deferredInitialization.promise;
}),
/**
* Maybe resume the tour (re-opening the tab, if necessary) if someone else joins
* a room of ours and it's currently open.
*/
maybeResumeTourOnRoomJoined: function(e, room, participant) {
let isOwnerInRoom = false;
let isOtherInRoom = false;
if (!this.getLoopPref("gettingStarted.resumeOnFirstJoin")) {
return;
}
if (!room.participants) {
return;
}
// The particpant that joined isn't necessarily included in room.participants (depending on
// when the broadcast happens) so concatenate.
for (let participant of room.participants.concat(participant)) {
if (participant.owner) {
isOwnerInRoom = true;
} else {
isOtherInRoom = true;
}
}
if (!isOwnerInRoom || !isOtherInRoom) {
return;
}
// Check that the room chatbox is still actually open using its URL
let chatboxesForRoom = [...Chat.chatboxes].filter(chatbox => {
return chatbox.src == MozLoopServiceInternal.getChatURL(room.roomToken);
});
if (!chatboxesForRoom.length) {
log.warn("Tried to resume the tour from a join when the chatbox was closed", room);
return;
}
this.resumeTour("open");
},
/**
* The core of the initialization work that happens once the browser is ready
* (after a timer when called during startup).

View File

@ -467,6 +467,9 @@
aEvent.preventDefault();
aEvent.stopPropagation();
if (this.hasAttribute("oneoffui"))
this.openSuggestionsPanel();
]]></body>
</method>
@ -647,10 +650,9 @@
<field name="_ignoreFocus">false</field>
<method name="selectEngine">
<method name="rebuildPopup">
<body><![CDATA[
// Override this method to avoid accidentally changing the default
// engine using the keyboard shortcuts of the old UI.
this._textbox.popup.updateHeader();
]]></body>
</method>
@ -914,7 +916,11 @@
<![CDATA[
// Don't open search popup if history popup is open
if (!this.popupOpen) {
document.getBindingParent(this).searchButton.open = true;
let searchBox = document.getBindingParent(this);
if (searchBox.hasAttribute("oneoffui"))
searchBox.openSuggestionsPanel();
else
searchBox.searchButton.open = true;
return false;
}
return true;
@ -980,8 +986,54 @@
if (!list)
return;
// accel + up/down changes the default engine and shouldn't affect
// the selection on the one-off buttons.
#ifdef XP_MACOSX
if (aEvent.metaKey)
#else
if (aEvent.ctrlKey)
#endif
return;
let selectedButton = this.getSelectedOneOff();
// Alt + up/down is very similar to (shift +) tab but differs in that
// it loops through the list, whereas tab will move the focus out.
if (aEvent.altKey &&
(aEvent.keyCode == KeyEvent.DOM_VK_DOWN ||
aEvent.keyCode == KeyEvent.DOM_VK_UP)) {
let forward = aEvent.keyCode == KeyEvent.DOM_VK_DOWN;
if (selectedButton) {
// cycle though the list of one-off buttons.
selectedButton.removeAttribute("selected");
if (forward)
selectedButton = selectedButton.nextSibling;
else
selectedButton = selectedButton.previousSibling;
// Avoid selecting dummy buttons.
if (selectedButton && selectedButton.classList.contains("dummy"))
selectedButton = null;
}
else {
// If no selection, select the first or last one-off button.
if (forward) {
selectedButton = list.firstChild;
}
else {
selectedButton = list.lastChild;
while (selectedButton.classList.contains("dummy"))
selectedButton = selectedButton.previousSibling;
}
}
if (selectedButton)
selectedButton.setAttribute("selected", "true");
aEvent.preventDefault();
aEvent.stopPropagation();
return;
}
// If the last suggestion is selected, DOWN selects the first one-off.
if (aEvent.keyCode == KeyEvent.DOM_VK_DOWN &&
popup.selectedIndex + 1 == popup.view.rowCount) {

View File

@ -71,7 +71,7 @@ function CheckLockState() {
let sYes = Strings.GetStringFromName("runtimedetails_checkyes");
let sNo = Strings.GetStringFromName("runtimedetails_checkno");
let sUnknown = Strings.GetStringFromName("runtimedetails_checkunkown");
let sUnknown = Strings.GetStringFromName("runtimedetails_checkunknown");
let sNotUSB = Strings.GetStringFromName("runtimedetails_notUSBDevice");
flipCertPerfButton.setAttribute("disabled", "true");

View File

@ -65,7 +65,7 @@ addons_status_installing=installing
runtimedetails_checkno=no
runtimedetails_checkyes=yes
runtimedetails_checkunkown=unknown
runtimedetails_checkunknown=unknown (requires ADB Helper 0.4.0 or later)
runtimedetails_notUSBDevice=Not a USB device
# Validation status

View File

@ -50,6 +50,38 @@ function getChromeWindow(contentWin) {
*/
let Chat = {
/**
* Iterator of <chatbox> elements from this module in all windows.
*/
get chatboxes() {
return function*() {
let winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
let win = winEnum.getNext();
let chatbar = win.document.getElementById("pinnedchats");
if (!chatbar)
continue;
// Make a new array instead of the live NodeList so this iterator can be
// used for closing/deleting.
let chatboxes = [c for (c of chatbar.children)];
for (let chatbox of chatboxes) {
yield chatbox;
}
}
// include standalone chat windows
winEnum = Services.wm.getEnumerator("Social:Chat");
while (winEnum.hasMoreElements()) {
let win = winEnum.getNext();
if (win.closed)
continue;
yield win.document.getElementById("chatter");
}
}();
},
/**
* Open a new chatbox.
*
@ -108,26 +140,11 @@ let Chat = {
* The origin from which all chats should be closed.
*/
closeAll: function(origin) {
// close all attached chat windows
let winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
let win = winEnum.getNext();
let chatbar = win.document.getElementById("pinnedchats");
if (!chatbar)
for (let chatbox of this.chatboxes) {
if (chatbox.content.getAttribute("origin") != origin) {
continue;
let chats = [c for (c of chatbar.children) if (c.content.getAttribute("origin") == origin)];
[c.close() for (c of chats)];
}
// close all standalone chat windows
winEnum = Services.wm.getEnumerator("Social:Chat");
while (winEnum.hasMoreElements()) {
let win = winEnum.getNext();
if (win.closed)
continue;
let chatOrigin = win.document.getElementById("chatter").content.getAttribute("origin");
if (origin == chatOrigin)
win.close();
}
chatbox.close();
}
},

View File

@ -400,7 +400,7 @@ SocialErrorListener.prototype = {
};
function sizeSocialPanelToContent(panel, iframe) {
function sizeSocialPanelToContent(panel, iframe, requestedSize) {
let doc = iframe.contentDocument;
if (!doc || !doc.body) {
return;
@ -408,14 +408,15 @@ function sizeSocialPanelToContent(panel, iframe) {
// We need an element to use for sizing our panel. See if the body defines
// an id for that element, otherwise use the body itself.
let body = doc.body;
let docEl = doc.documentElement;
let bodyId = body.getAttribute("contentid");
if (bodyId) {
body = doc.getElementById(bodyId) || doc.body;
}
// offsetHeight/Width don't include margins, so account for that.
let cs = doc.defaultView.getComputedStyle(body);
let width = PANEL_MIN_WIDTH;
let height = PANEL_MIN_HEIGHT;
let width = Math.max(PANEL_MIN_WIDTH, docEl.offsetWidth);
let height = Math.max(PANEL_MIN_HEIGHT, docEl.offsetHeight);
// if the panel is preloaded prior to being shown, cs will be null. in that
// case use the minimum size for the panel until it is shown.
if (cs) {
@ -425,19 +426,33 @@ function sizeSocialPanelToContent(panel, iframe) {
width = Math.max(computedWidth, width);
}
// only add the extra space if the iframe has been loaded
// if our scrollHeight is still larger than the iframe, the css calculations
// above did not work for this site, increase the height. This can happen if
// the site increases its height for additional UI.
if (docEl.scrollHeight > iframe.boxObject.height)
height = docEl.scrollHeight;
// if a size was defined in the manifest use it as a minimum
if (requestedSize) {
if (requestedSize.height)
height = Math.max(height, requestedSize.height);
if (requestedSize.width)
width = Math.max(width, requestedSize.width);
}
// add the extra space used by the panel (toolbar, borders, etc) if the iframe
// has been loaded
if (iframe.boxObject.width && iframe.boxObject.height) {
// add extra space the panel needs if any
width += panel.boxObject.width - iframe.boxObject.width;
height += panel.boxObject.height - iframe.boxObject.height;
}
// when size is computed, we want to be sure changes are "significant" since
// some sites will resize when the iframe is resized by a small amount, making
// the panel slowly shrink to some minimum.
if (Math.abs(panel.boxObject.width - width) > 2 || Math.abs(panel.boxObject.height - height) > 2) {
panel.sizeTo(width, height);
}
// using panel.sizeTo will ignore css transitions, set size via style
if (Math.abs(panel.boxObject.width - width) >= 2)
panel.style.width = width + "px";
if (Math.abs(panel.boxObject.height - height) >= 2)
panel.style.height = height + "px";
}
function DynamicResizeWatcher() {
@ -445,18 +460,18 @@ function DynamicResizeWatcher() {
}
DynamicResizeWatcher.prototype = {
start: function DynamicResizeWatcher_start(panel, iframe) {
start: function DynamicResizeWatcher_start(panel, iframe, requestedSize) {
this.stop(); // just in case...
let doc = iframe.contentDocument;
this._mutationObserver = new iframe.contentWindow.MutationObserver(function(mutations) {
sizeSocialPanelToContent(panel, iframe);
this._mutationObserver = new iframe.contentWindow.MutationObserver((mutations) => {
sizeSocialPanelToContent(panel, iframe, requestedSize);
});
// Observe anything that causes the size to change.
let config = {attributes: true, characterData: true, childList: true, subtree: true};
this._mutationObserver.observe(doc, config);
// and since this may be setup after the load event has fired we do an
// initial resize now.
sizeSocialPanelToContent(panel, iframe);
sizeSocialPanelToContent(panel, iframe, requestedSize);
},
stop: function DynamicResizeWatcher_stop() {
if (this._mutationObserver) {

View File

@ -1609,46 +1609,47 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
/* social share panel */
.social-share-frame {
background: linear-gradient(to bottom, rgba(242,242,242,.99), rgba(242,242,242,.95));
border-left: 1px solid #f8f8f8;
width: 330px;
border-top: 1px solid #f8f8f8;
width: 756px;
height: 150px;
/* we resize our panels dynamically, make it look nice */
transition: height 100ms ease-out, width 100ms ease-out;
}
#share-container {
min-width: 756px;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
.social-share-toolbar {
border-right: 1px solid #dedede;
background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95));
border-bottom: 1px solid #dedede;
padding: 2px;
}
#social-share-provider-buttons {
border-right: 1px solid #fbfbfb;
padding: 6px;
}
#social-share-provider-buttons > .share-provider-button {
padding: 6px;
padding: 0;
margin: 0;
border: none;
border-radius: 2px;
}
#social-share-provider-buttons > .share-provider-button[checked],
#social-share-provider-buttons > .share-provider-button:active {
.share-provider-button {
padding: 5px;
border: 1px solid #b5b5b8;
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2);
margin: 2px;
}
#social-share-provider-buttons > .share-provider-button[checked] {
background: linear-gradient(to bottom, #d9d9d9, #e3e3e3);
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
.share-provider-button > .toolbarbutton-text {
display: none;
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;

View File

@ -2514,46 +2514,55 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
/* social share panel */
.social-share-frame {
background: linear-gradient(to bottom, rgba(242,242,242,.99), rgba(242,242,242,.95));
border-left: 1px solid #f8f8f8;
width: 330px;
border-top: 1px solid #f8f8f8;
min-width: 756px;
height: 150px;
/* we resize our panels dynamically, make it look nice */
transition: height 100ms ease-out, width 100ms ease-out;
}
#share-container {
min-width: 756px;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
#manage-share-providers,
#social-sidebar-button:hover,
#social-sidebar-button:hover:active {
-moz-image-region: rect(18px, 468px, 36px, 450px);
}
.social-share-toolbar {
border-right: 1px solid #dedede;
background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95));
border-bottom: 1px solid #dedede;
padding: 2px;
}
#social-share-provider-buttons {
border-right: 1px solid #fbfbfb;
padding: 6px;
}
#social-share-provider-buttons > .share-provider-button {
padding: 6px;
padding: 0;
margin: 0;
border: none;
border-radius: 2px;
}
#social-share-provider-buttons > .share-provider-button[checked],
#social-share-provider-buttons > .share-provider-button:active {
.share-provider-button {
padding: 5px;
border: 1px solid #b5b5b8;
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2);
margin: 2px;
}
#social-share-provider-buttons > .share-provider-button[checked] {
background: linear-gradient(to bottom, #d9d9d9, #e3e3e3);
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
.share-provider-button > .toolbarbutton-text {
display: none;
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
@ -4500,44 +4509,27 @@ menulist.translate-infobar-element > .menulist-dropmarker {
}
#social-share-panel {
max-height: 600px;
min-height: 100px;
max-width: 800px;
min-width: 300px;
transition: height .3s ease-in-out, width .3s ease-in-out;
}
.social-share-frame:-moz-locale-dir(ltr) {
#share-container,
.social-share-frame {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
.social-share-frame:-moz-locale-dir(rtl) {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
#social-share-panel > .social-share-toolbar:-moz-locale-dir(ltr) {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
}
#social-share-panel > .social-share-toolbar:-moz-locale-dir(rtl) {
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
#social-share-provider-buttons:-moz-locale-dir(ltr) {
#social-share-panel > .social-share-toolbar {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
border-top-right-radius: inherit;
}
#social-share-provider-buttons:-moz-locale-dir(rtl) {
#social-share-provider-buttons {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
/* === end of social toolbar provider menu === */

View File

@ -702,6 +702,7 @@ panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
.share-provider-button,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton {
-moz-appearance: none;
padding: 0 6px;
@ -714,6 +715,7 @@ panelview .toolbarbutton-1,
panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.share-provider-button,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton {
border-width: 1px;
}
@ -786,6 +788,7 @@ panelview .toolbarbutton-1@buttonStateHover@,
toolbarbutton.subviewbutton@buttonStateHover@,
menu.subviewbutton@menuStateHover@,
menuitem.subviewbutton@menuStateHover@,
.share-provider-button@buttonStateHover@,
.widget-overflow-list .toolbarbutton-1@buttonStateHover@,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton@buttonStateHover@ {
background-color: hsla(210,4%,10%,.08);
@ -800,6 +803,7 @@ panelview .toolbarbutton-1:-moz-any(@buttonStateActive@,[checked=true]),
toolbarbutton.subviewbutton@buttonStateActive@,
menu.subviewbutton@menuStateActive@,
menuitem.subviewbutton@menuStateActive@,
.share-provider-button:-moz-any(@buttonStateActive@,[checked=true]),
.widget-overflow-list .toolbarbutton-1@buttonStateActive@,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton@buttonStateActive@ {
background-color: hsla(210,4%,10%,.12);

View File

@ -8,21 +8,24 @@
padding: 3px;
}
#manage-share-providers,
#social-sidebar-button {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 468px, 18px, 450px);
}
#social-sidebar-button {
-moz-appearance: none;
list-style-image: url(chrome://browser/skin/social/gear_default.png);
border: none;
padding: 0;
margin: 2px;
}
#manage-share-providers > .toolbarbutton-icon,
#social-sidebar-button > .toolbarbutton-icon {
min-height: 16px;
min-width: 16px;
}
#social-sidebar-button:hover,
#social-sidebar-button:hover:active {
list-style-image: url(chrome://browser/skin/social/gear_clicked.png);
min-height: 18px;
min-width: 18px;
}
#social-sidebar-button > .toolbarbutton-menu-dropmarker {
display: none;
}

View File

@ -1573,46 +1573,46 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
/* social share panel */
#social-share-panel > iframe {
background: linear-gradient(to bottom, #f0f4f7, #fafbfc);
width: 300px;
.social-share-frame {
min-width: 756px;
height: 150px;
}
#share-container {
min-width: 756px;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
.social-share-toolbar {
border-right: 1px solid #e2e5e8;
background: linear-gradient(to bottom, #ffffff, #f5f7fa);
border-bottom: 1px solid #e2e5e8;
padding: 2px;
}
#social-share-provider-buttons {
padding: 6px;
padding: 0;
margin: 0;
}
#social-share-provider-buttons > .share-provider-button {
-moz-appearance: none;
.share-provider-button {
padding: 5px;
margin: 1px;
border: none;
background: none;
border-radius: 2px;
margin: 2px;
}
#social-share-provider-buttons > .share-provider-button[checked="true"]:not([disabled="true"]),
#social-share-provider-buttons > .share-provider-button:hover,
#social-share-provider-buttons > .share-provider-button:active {
padding: 4px;
border: 1px solid #aeb8c1;
box-shadow: inset 1px 1px 1px rgba(10, 31, 51, 0.1);
}
#social-share-provider-buttons > .share-provider-button[checked="true"]:not([disabled="true"]) {
background: linear-gradient(to bottom, rgba(230,232,234,.65), #d2d5d9);
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-text {
.share-provider-button > .toolbarbutton-text {
display: none;
}
#social-share-provider-buttons > .share-provider-button > .toolbarbutton-icon {
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
@ -1632,52 +1632,26 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
}
#social-share-panel {
max-height: 600px;
min-height: 100px;
max-width: 800px;
min-width: 300px;
min-width: 766px;
}
#share-container,
.social-share-frame {
background: linear-gradient(to bottom, #f0f4f7, #fafbfc);
width: 330px;
height: 150px;
/* we resize our panels dynamically, make it look nice */
transition: height 100ms ease-out, width 100ms ease-out;
}
.social-share-frame:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
.social-share-frame:-moz-locale-dir(rtl) {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
#social-share-panel > .social-share-toolbar:-moz-locale-dir(ltr) {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
}
#social-share-panel > .social-share-toolbar:-moz-locale-dir(rtl) {
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
#social-share-provider-buttons:-moz-locale-dir(ltr) {
#social-share-panel > .social-share-toolbar {
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
border-top-right-radius: inherit;
}
#social-share-provider-buttons:-moz-locale-dir(rtl) {
#social-share-provider-buttons {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
border-bottom-right-radius: inherit;
}
/* social recommending panel */

View File

@ -686,6 +686,8 @@ browser.jar:
skin/classic/aero/browser/tabbrowser/tab-background-end@2x.png (tabbrowser/tab-background-end@2x.png)
skin/classic/aero/browser/tabbrowser/tab-overflow-indicator.png (../shared/tabbrowser/tab-overflow-indicator.png)
skin/classic/aero/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
# Makefile.in with a non-default marker of "%" and the result of that gets packaged.
skin/classic/aero/browser/tabbrowser/tab-selected-end.svg (tab-selected-end-aero.svg)

View File

@ -36,6 +36,11 @@ support-files =
print_postdata.sjs
test-form_sjis.html
timelineMarkers-04.html
browser_timelineMarkers-frame-02.js
browser_timelineMarkers-frame-03.js
browser_timelineMarkers-frame-04.js
head.js
frame-head.js
[browser_bug134911.js]
skip-if = e10s # Bug ?????? - BrowserSetForcedCharacterSet() in browser.js references docShell
@ -98,8 +103,5 @@ skip-if = e10s
[browser_search_notification.js]
[browser_timelineMarkers-01.js]
[browser_timelineMarkers-02.js]
skip-if = e10s
[browser_timelineMarkers-03.js]
skip-if = e10s
[browser_timelineMarkers-04.js]
skip-if = e10s

View File

@ -3,9 +3,6 @@
"use strict";
// Test that the docShell profile timeline API returns the right markers when
// restyles, reflows and paints occur
let URL = '<!DOCTYPE html><style>' +
'body {margin:0; padding: 0;} ' +
'div {width:100px;height:100px;background:red;} ' +
@ -13,157 +10,6 @@ let URL = '<!DOCTYPE html><style>' +
'.change-color {width:50px;height:50px;background:yellow;} ' +
'.add-class {}' +
'</style><div></div>';
URL = "data:text/html;charset=utf8," + encodeURIComponent(URL);
let TESTS = [{
desc: "Changing the width of the test element",
searchFor: "Paint",
setup: function(div) {
div.setAttribute("class", "resize-change-color");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
console.log(markers);
info(JSON.stringify(markers.filter(m => m.name == "Paint")));
ok(markers.some(m => m.name == "Reflow"), "markers includes Reflow");
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
for (let marker of markers.filter(m => m.name == "Paint")) {
// This change should generate at least one rectangle.
ok(marker.rectangles.length >= 1, "marker has one rectangle");
// One of the rectangles should contain the div.
ok(marker.rectangles.some(r => rectangleContains(r, 0, 0, 100, 100)));
}
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "Changing the test element's background color",
searchFor: "Paint",
setup: function(div) {
div.setAttribute("class", "change-color");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
ok(!markers.some(m => m.name == "Reflow"), "markers doesn't include Reflow");
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
for (let marker of markers.filter(m => m.name == "Paint")) {
// This change should generate at least one rectangle.
ok(marker.rectangles.length >= 1, "marker has one rectangle");
// One of the rectangles should contain the div.
ok(marker.rectangles.some(r => rectangleContains(r, 0, 0, 50, 50)));
}
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "Changing the test element's classname",
searchFor: "Paint",
setup: function(div) {
div.setAttribute("class", "change-color add-class");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
ok(!markers.some(m => m.name == "Reflow"), "markers doesn't include Reflow");
ok(!markers.some(m => m.name == "Paint"), "markers doesn't include Paint");
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "sync console.time/timeEnd",
searchFor: "ConsoleTime",
setup: function(div, docShell) {
content.console.time("FOOBAR");
content.console.timeEnd("FOOBAR");
let markers = docShell.popProfileTimelineMarkers();
is(markers.length, 1, "Got one marker");
is(markers[0].name, "ConsoleTime", "Got ConsoleTime marker");
is(markers[0].causeName, "FOOBAR", "Got ConsoleTime FOOBAR detail");
content.console.time("FOO");
content.setTimeout(() => {
content.console.time("BAR");
content.setTimeout(() => {
content.console.timeEnd("FOO");
content.console.timeEnd("BAR");
}, 100);
}, 100);
},
check: function(markers) {
is(markers.length, 2, "Got 2 markers");
is(markers[0].name, "ConsoleTime", "Got first ConsoleTime marker");
is(markers[0].causeName, "FOO", "Got ConsoleTime FOO detail");
is(markers[1].name, "ConsoleTime", "Got second ConsoleTime marker");
is(markers[1].causeName, "BAR", "Got ConsoleTime BAR detail");
}
}];
let test = Task.async(function*() {
waitForExplicitFinish();
yield openUrl("data:text/html;charset=utf8," + encodeURIComponent(URL));
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let div = content.document.querySelector("div");
info("Start recording");
docShell.recordProfileTimelineMarkers = true;
for (let {desc, searchFor, setup, check} of TESTS) {
info("Running test: " + desc);
info("Flushing the previous markers if any");
docShell.popProfileTimelineMarkers();
info("Running the test setup function");
let onMarkers = waitForMarkers(docShell, searchFor);
setup(div, docShell);
info("Waiting for new markers on the docShell");
let markers = yield onMarkers;
info("Running the test check function");
check(markers);
}
info("Stop recording");
docShell.recordProfileTimelineMarkers = false;
gBrowser.removeCurrentTab();
finish();
});
function openUrl(url) {
return new Promise(function(resolve, reject) {
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
resolve(tab);
}, true);
});
}
function waitForMarkers(docshell, searchFor) {
return new Promise(function(resolve, reject) {
let waitIterationCount = 0;
let maxWaitIterationCount = 10; // Wait for 2sec maximum
let markers = [];
let interval = setInterval(() => {
let newMarkers = docshell.popProfileTimelineMarkers();
markers = [...markers, ...newMarkers];
if (newMarkers.some(m => m.name == searchFor) ||
waitIterationCount > maxWaitIterationCount) {
clearInterval(interval);
resolve(markers);
}
waitIterationCount++;
}, 200);
});
}
function rectangleContains(rect, x, y, width, height) {
return rect.x <= x && rect.y <= y && rect.width >= width &&
rect.height >= height;
}
let test = makeTimelineTest("browser_timelineMarkers-frame-02.js", URL);

View File

@ -3,139 +3,6 @@
"use strict";
// Test that the docShell profile timeline API returns the right
// markers for DOM events.
let URL = "data:text/html;charset=utf-8,<p>Test page</p>";
let TESTS = [{
desc: "Event dispatch with single handler",
setup: function() {
content.document.body.addEventListener("dog",
function(e) { console.log("hi"); },
true);
content.document.body.dispatchEvent(new Event("dog"));
},
check: function(markers) {
is(markers.length, 1, "Got 1 marker");
is(markers[0].type, "dog", "Got dog event name");
is(markers[0].eventPhase, 2, "Got phase 2");
}
}, {
desc: "Event dispatch with a second handler",
setup: function() {
content.document.body.addEventListener("dog",
function(e) { console.log("hi"); },
false);
content.document.body.dispatchEvent(new Event("dog"));
},
check: function(markers) {
is(markers.length, 2, "Got 2 markers");
}
}, {
desc: "Event targeted at child",
setup: function() {
let child = content.document.body.firstElementChild;
child.addEventListener("dog", function(e) { });
child.dispatchEvent(new Event("dog"));
},
check: function(markers) {
is(markers.length, 2, "Got 2 markers");
is(markers[0].eventPhase, 1, "Got phase 1 marker");
is(markers[1].eventPhase, 2, "Got phase 2 marker");
}
}, {
desc: "Event dispatch on a new document",
setup: function() {
let doc = content.document.implementation.createHTMLDocument("doc");
let p = doc.createElement("p");
p.innerHTML = "inside";
doc.body.appendChild(p);
p.addEventListener("zebra", function(e) {console.log("hi");});
p.dispatchEvent(new Event("zebra"));
},
check: function(markers) {
is(markers.length, 1, "Got 1 marker");
}
}, {
desc: "Event dispatch on window",
setup: function() {
let doc = content.window.addEventListener("aardvark", function(e) {
console.log("I like ants!");
});
content.window.dispatchEvent(new Event("aardvark"));
},
check: function(markers) {
is(markers.length, 1, "Got 1 marker");
}
}];
let test = Task.async(function*() {
waitForExplicitFinish();
yield openUrl("data:text/html;charset=utf-8,<p>Test page</p>");
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
info("Start recording");
docShell.recordProfileTimelineMarkers = true;
for (let {desc, setup, check} of TESTS) {
info("Running test: " + desc);
info("Flushing the previous markers if any");
docShell.popProfileTimelineMarkers();
info("Running the test setup function");
let onMarkers = waitForMarkers(docShell);
setup();
info("Waiting for new markers on the docShell");
let markers = yield onMarkers;
info("Running the test check function");
check(markers.filter(m => m.name == "DOMEvent"));
}
info("Stop recording");
docShell.recordProfileTimelineMarkers = false;
gBrowser.removeCurrentTab();
finish();
});
function openUrl(url) {
return new Promise(function(resolve, reject) {
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
resolve(tab);
}, true);
});
}
function waitForMarkers(docshell) {
return new Promise(function(resolve, reject) {
let waitIterationCount = 0;
let maxWaitIterationCount = 10; // Wait for 2sec maximum
let interval = setInterval(() => {
let markers = docshell.popProfileTimelineMarkers();
if (markers.length > 0) {
clearInterval(interval);
resolve(markers);
}
if (waitIterationCount > maxWaitIterationCount) {
clearInterval(interval);
resolve([]);
}
waitIterationCount++;
}, 200);
});
}
let test = makeTimelineTest("browser_timelineMarkers-frame-03.js", URL);

View File

@ -3,91 +3,6 @@
"use strict";
// Test that the docShell profile timeline API returns the right
// markers for XMLHttpRequest events.
const URL = "http://mochi.test:8888/browser/docshell/test/browser/timelineMarkers-04.html";
let TESTS = [{
desc: "Event dispatch from XMLHttpRequest",
setup: function() {
content.dispatchEvent(new Event("dog"));
},
check: function(markers) {
// One subtlety here is that we have five events: the event we
// inject in "setup", plus the four state transition events. The
// first state transition is reported synchronously and so should
// show up as a nested marker.
is(markers.length, 5, "Got 5 markers");
}
}];
let test = Task.async(function*() {
waitForExplicitFinish();
const testDir = "http://mochi.test:8888/browser/docshell/test/browser/";
const testName = "timelineMarkers-04.html";
yield openUrl(testDir + testName);
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
info("Start recording");
docShell.recordProfileTimelineMarkers = true;
for (let {desc, setup, check} of TESTS) {
info("Running test: " + desc);
info("Flushing the previous markers if any");
docShell.popProfileTimelineMarkers();
info("Running the test setup function");
let onMarkers = waitForDOMMarkers(docShell, 5);
setup();
info("Waiting for new markers on the docShell");
let markers = yield onMarkers;
info("Running the test check function");
check(markers);
}
info("Stop recording");
docShell.recordProfileTimelineMarkers = false;
gBrowser.removeCurrentTab();
finish();
});
function openUrl(url) {
return new Promise(function(resolve, reject) {
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
resolve(tab);
}, true);
});
}
function waitForDOMMarkers(docshell, numExpected) {
return new Promise(function(resolve, reject) {
let waitIterationCount = 0;
let maxWaitIterationCount = 10; // Wait for 2sec maximum
let markers = [];
let interval = setInterval(() => {
let newMarkers = docshell.popProfileTimelineMarkers();
markers = [...markers, ...newMarkers.filter(m => m.name == "DOMEvent")];
if (markers.length >= numExpected
|| waitIterationCount > maxWaitIterationCount) {
clearInterval(interval);
resolve(markers);
}
waitIterationCount++;
}, 200);
});
}
let test = makeTimelineTest("browser_timelineMarkers-frame-04.js", URL);

View File

@ -0,0 +1,95 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the docShell profile timeline API returns the right markers when
// restyles, reflows and paints occur
function rectangleContains(rect, x, y, width, height) {
return rect.x <= x && rect.y <= y && rect.width >= width &&
rect.height >= height;
}
let TESTS = [{
desc: "Changing the width of the test element",
searchFor: "Paint",
setup: function(docShell) {
let div = content.document.querySelector("div");
div.setAttribute("class", "resize-change-color");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
console.log(markers);
info(JSON.stringify(markers.filter(m => m.name == "Paint")));
ok(markers.some(m => m.name == "Reflow"), "markers includes Reflow");
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
for (let marker of markers.filter(m => m.name == "Paint")) {
// This change should generate at least one rectangle.
ok(marker.rectangles.length >= 1, "marker has one rectangle");
// One of the rectangles should contain the div.
ok(marker.rectangles.some(r => rectangleContains(r, 0, 0, 100, 100)));
}
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "Changing the test element's background color",
searchFor: "Paint",
setup: function(docShell) {
let div = content.document.querySelector("div");
div.setAttribute("class", "change-color");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
ok(!markers.some(m => m.name == "Reflow"), "markers doesn't include Reflow");
ok(markers.some(m => m.name == "Paint"), "markers includes Paint");
for (let marker of markers.filter(m => m.name == "Paint")) {
// This change should generate at least one rectangle.
ok(marker.rectangles.length >= 1, "marker has one rectangle");
// One of the rectangles should contain the div.
ok(marker.rectangles.some(r => rectangleContains(r, 0, 0, 50, 50)));
}
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "Changing the test element's classname",
searchFor: "Paint",
setup: function(docShell) {
let div = content.document.querySelector("div");
div.setAttribute("class", "change-color add-class");
},
check: function(markers) {
ok(markers.length > 0, "markers were returned");
ok(!markers.some(m => m.name == "Reflow"), "markers doesn't include Reflow");
ok(!markers.some(m => m.name == "Paint"), "markers doesn't include Paint");
ok(markers.some(m => m.name == "Styles"), "markers includes Restyle");
}
}, {
desc: "sync console.time/timeEnd",
searchFor: "ConsoleTime",
setup: function(docShell) {
content.console.time("FOOBAR");
content.console.timeEnd("FOOBAR");
let markers = docShell.popProfileTimelineMarkers();
is(markers.length, 1, "Got one marker");
is(markers[0].name, "ConsoleTime", "Got ConsoleTime marker");
is(markers[0].causeName, "FOOBAR", "Got ConsoleTime FOOBAR detail");
content.console.time("FOO");
content.setTimeout(() => {
content.console.time("BAR");
content.setTimeout(() => {
content.console.timeEnd("FOO");
content.console.timeEnd("BAR");
}, 100);
}, 100);
},
check: function(markers) {
is(markers.length, 2, "Got 2 markers");
is(markers[0].name, "ConsoleTime", "Got first ConsoleTime marker");
is(markers[0].causeName, "FOO", "Got ConsoleTime FOO detail");
is(markers[1].name, "ConsoleTime", "Got second ConsoleTime marker");
is(markers[1].causeName, "BAR", "Got ConsoleTime BAR detail");
}
}];
timelineContentTest(TESTS);

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the docShell profile timeline API returns the right
// markers for DOM events.
let TESTS = [{
desc: "Event dispatch with single handler",
searchFor: 'DOMEvent',
setup: function(docShell) {
content.document.body.addEventListener("dog",
function(e) { console.log("hi"); },
true);
content.document.body.dispatchEvent(new content.Event("dog"));
},
check: function(markers) {
markers = markers.filter(m => m.name == 'DOMEvent');
is(markers.length, 1, "Got 1 marker");
is(markers[0].type, "dog", "Got dog event name");
is(markers[0].eventPhase, 2, "Got phase 2");
}
}, {
desc: "Event dispatch with a second handler",
searchFor: function(markers) {
return markers.filter(m => m.name == 'DOMEvent').length >= 2;
},
setup: function(docShell) {
content.document.body.addEventListener("dog",
function(e) { console.log("hi"); },
false);
content.document.body.dispatchEvent(new content.Event("dog"));
},
check: function(markers) {
markers = markers.filter(m => m.name == 'DOMEvent');
is(markers.length, 2, "Got 2 markers");
}
}, {
desc: "Event targeted at child",
searchFor: function(markers) {
return markers.filter(m => m.name == 'DOMEvent').length >= 2;
},
setup: function(docShell) {
let child = content.document.body.firstElementChild;
child.addEventListener("dog", function(e) { });
child.dispatchEvent(new content.Event("dog"));
},
check: function(markers) {
markers = markers.filter(m => m.name == 'DOMEvent');
is(markers.length, 2, "Got 2 markers");
is(markers[0].eventPhase, 1, "Got phase 1 marker");
is(markers[1].eventPhase, 2, "Got phase 2 marker");
}
}, {
desc: "Event dispatch on a new document",
searchFor: function(markers) {
return markers.filter(m => m.name == 'DOMEvent').length >= 2;
},
setup: function(docShell) {
let doc = content.document.implementation.createHTMLDocument("doc");
let p = doc.createElement("p");
p.innerHTML = "inside";
doc.body.appendChild(p);
p.addEventListener("zebra", function(e) {console.log("hi");});
p.dispatchEvent(new content.Event("zebra"));
},
check: function(markers) {
markers = markers.filter(m => m.name == 'DOMEvent');
is(markers.length, 1, "Got 1 marker");
}
}, {
desc: "Event dispatch on window",
searchFor: function(markers) {
return markers.filter(m => m.name == 'DOMEvent').length >= 2;
},
setup: function(docShell) {
let doc = content.window.addEventListener("aardvark", function(e) {
console.log("I like ants!");
});
content.window.dispatchEvent(new content.Event("aardvark"));
},
check: function(markers) {
markers = markers.filter(m => m.name == 'DOMEvent');
is(markers.length, 1, "Got 1 marker");
}
}];
timelineContentTest(TESTS);

View File

@ -0,0 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the docShell profile timeline API returns the right
// markers for XMLHttpRequest events.
let TESTS = [{
desc: "Event dispatch from XMLHttpRequest",
searchFor: function(markers) {
return markers.filter(m => m.name == "DOMEvent").length >= 5;
},
setup: function(docShell) {
content.dispatchEvent(new content.Event("dog"));
},
check: function(markers) {
markers = markers.filter(m => m.name == "DOMEvent");
// One subtlety here is that we have five events: the event we
// inject in "setup", plus the four state transition events. The
// first state transition is reported synchronously and so should
// show up as a nested marker.
is(markers.length, 5, "Got 5 markers");
}
}];
timelineContentTest(TESTS);

View File

@ -0,0 +1,105 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Functions that are automatically loaded as frame scripts for
// timeline tests.
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
let { Promise } = Cu.import('resource://gre/modules/Promise.jsm', {});
// Functions that look like mochitest functions but forward to the
// browser process.
this.ok = function(value, message) {
sendAsyncMessage("browser:test:ok", {
value: !!value,
message: message});
}
this.is = function(v1, v2, message) {
ok(v1 == v2, message);
}
this.info = function(message) {
sendAsyncMessage("browser:test:info", {message: message});
}
this.finish = function() {
sendAsyncMessage("browser:test:finish");
}
/* Start a task that runs some timeline tests in the ordinary way.
*
* @param array tests
* The tests to run. This is an array where each element
* is of the form { desc, searchFor, setup, check }.
*
* desc is the test description, a string.
* searchFor is a string or a function
* If a string, then when a marker with this name is
* found, marker-reading is stopped.
* If a function, then the accumulated marker array is
* passed to it, and marker reading stops when it returns
* true.
* setup is a function that takes the docshell as an argument.
* It should start the test.
* check is a function that takes an array of markers
* as an argument and checks the results of the test.
*/
this.timelineContentTest = function(tests) {
Task.spawn(function*() {
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
info("Start recording");
docShell.recordProfileTimelineMarkers = true;
for (let {desc, searchFor, setup, check} of tests) {
info("Running test: " + desc);
info("Flushing the previous markers if any");
docShell.popProfileTimelineMarkers();
info("Running the test setup function");
let onMarkers = timelineWaitForMarkers(docShell, searchFor);
setup(docShell);
info("Waiting for new markers on the docShell");
let markers = yield onMarkers;
info("Running the test check function");
check(markers);
}
info("Stop recording");
docShell.recordProfileTimelineMarkers = false;
finish();
});
}
function timelineWaitForMarkers(docshell, searchFor) {
if (typeof(searchFor) == "string") {
let f = function (markers) {
return markers.some(m => m.name == searchFor);
};
searchFor = f;
}
return new Promise(function(resolve, reject) {
let waitIterationCount = 0;
let maxWaitIterationCount = 10; // Wait for 2sec maximum
let markers = [];
let interval = content.setInterval(() => {
let newMarkers = docshell.popProfileTimelineMarkers();
markers = [...markers, ...newMarkers];
if (searchFor(markers) || waitIterationCount > maxWaitIterationCount) {
content.clearInterval(interval);
resolve(markers);
}
waitIterationCount++;
}, 200);
});
}

View File

@ -0,0 +1,53 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* Helper function for timeline tests. Returns an async task that is
* suitable for use as a particular timeline test.
* @param string frameScriptName
* Base name of the frame script file.
* @param string url
* URL to load.
*/
function makeTimelineTest(frameScriptName, url) {
info("in timelineTest");
return Task.async(function*() {
info("in in timelineTest");
waitForExplicitFinish();
yield timelineTestOpenUrl(url);
const here = "chrome://mochitests/content/browser/docshell/test/browser/";
let mm = gBrowser.selectedBrowser.messageManager;
mm.loadFrameScript(here + "frame-head.js", false);
mm.loadFrameScript(here + frameScriptName, false);
// Set up some listeners so that timeline tests running in the
// content process can forward their results to the main process.
mm.addMessageListener("browser:test:ok", function(message) {
ok(message.data.value, message.data.message);
});
mm.addMessageListener("browser:test:info", function(message) {
info(message.data.message);
});
mm.addMessageListener("browser:test:finish", function(ignore) {
finish();
gBrowser.removeCurrentTab();
});
});
}
/* Open a URL for a timeline test. */
function timelineTestOpenUrl(url) {
return new Promise(function(resolve, reject) {
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
resolve(tab);
}, true);
});
}

View File

@ -30,6 +30,8 @@ if CONFIG['MOZ_JEMALLOC3']:
GENERATED_INCLUDES += ['../jemalloc/src/include']
if CONFIG['_MSC_VER']:
LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat']
if not CONFIG['HAVE_INTTYPES_H']:
LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat/C99']
if CONFIG['MOZ_REPLACE_MALLOC']:
SOURCES += [

View File

@ -0,0 +1,35 @@
From 9c6a8d3b0cc14fd26b119ad08f190e537771464f Mon Sep 17 00:00:00 2001
From: Guilherme Goncalves <guilherme.p.gonc@gmail.com>
Date: Wed, 17 Dec 2014 14:46:35 -0200
Subject: [PATCH] Move variable declaration to the top its block for MSVC
compatibility.
---
src/arena.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/arena.c b/src/arena.c
index bf78995..1eb4000 100644
--- a/src/arena.c
+++ b/src/arena.c
@@ -2022,6 +2022,7 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
* following run, then merge the first part with the existing
* allocation.
*/
+ arena_run_t *run;
size_t flag_dirty, splitsize, usize;
usize = s2u(size + extra);
@@ -2030,8 +2031,7 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
assert(usize >= usize_min);
splitsize = usize - oldsize;
- arena_run_t *run = &arena_miscelm_get(chunk,
- pageind+npages)->run;
+ run = &arena_miscelm_get(chunk, pageind+npages)->run;
arena_run_split_large(arena, run, splitsize, zero);
size = oldsize + splitsize;
--
2.1.3

View File

@ -0,0 +1,30 @@
From 4dd4193c59ff3f77e4ab36214ec63425ca834323 Mon Sep 17 00:00:00 2001
From: Guilherme Goncalves <guilherme.p.gonc@gmail.com>
Date: Thu, 18 Dec 2014 15:01:21 +0900
Subject: [PATCH] Add a isblank definition for MSVC < 2013
---
include/jemalloc/internal/jemalloc_internal_decls.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h
index fb2effb..65f2e4b 100644
--- a/include/jemalloc/internal/jemalloc_internal_decls.h
+++ b/include/jemalloc/internal/jemalloc_internal_decls.h
@@ -52,6 +52,13 @@ typedef intptr_t ssize_t;
# define __func__ __FUNCTION__
/* Disable warnings about deprecated system functions. */
# pragma warning(disable: 4996)
+#if _MSC_VER < 1800
+static int
+isblank(int c)
+{
+ return (c == '\t' || c == ' ');
+}
+#endif
#else
# include <unistd.h>
#endif
--
2.1.3

View File

@ -52,6 +52,13 @@ typedef intptr_t ssize_t;
# define __func__ __FUNCTION__
/* Disable warnings about deprecated system functions. */
# pragma warning(disable: 4996)
#if _MSC_VER < 1800
static int
isblank(int c)
{
return (c == '\t' || c == ' ');
}
#endif
#else
# include <unistd.h>
#endif

View File

@ -2022,6 +2022,7 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
* following run, then merge the first part with the existing
* allocation.
*/
arena_run_t *run;
size_t flag_dirty, splitsize, usize;
usize = s2u(size + extra);
@ -2030,8 +2031,7 @@ arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
assert(usize >= usize_min);
splitsize = usize - oldsize;
arena_run_t *run = &arena_miscelm_get(chunk,
pageind+npages)->run;
run = &arena_miscelm_get(chunk, pageind+npages)->run;
arena_run_split_large(arena, run, splitsize, zero);
size = oldsize + splitsize;

View File

@ -15,6 +15,8 @@ git describe --long --abbrev=40 > VERSION
rm -rf .git .gitignore .gitattributes autom4te.cache .autom4te.cfg
patch -p1 < ../0001-Dont-overwrite-VERSION-on-a-git-repository.patch
patch -p1 < ../0002-Move-variable-declaration-to-the-top-its-block-for-M.patch
patch -p1 < ../0003-Add-a-isblank-definition-for-MSVC-2013.patch
cd ..
hg addremove -q src

View File

@ -29,5 +29,7 @@ DEFINES['MOZ_REPLACE_JEMALLOC'] = True
GENERATED_INCLUDES += ['../../jemalloc/src/include']
if CONFIG['_MSC_VER']:
LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat']
if not CONFIG['HAVE_INTTYPES_H']:
LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat/C99']
DISABLE_STL_WRAPPING = True

View File

@ -1,61 +0,0 @@
project.buildDir = "${topobjdir}/mobile/android/gradle/app/build"
apply plugin: 'android'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
}
buildTypes {
release {
runProguard false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
android {
lintOptions {
abortOnError false
}
}
sourceSets {
main {
manifest {
srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
}
assets {
srcDir "${topobjdir}/dist/fennec/assets"
}
jniLibs {
srcDir "${topobjdir}/dist/fennec/lib"
}
}
androidTest {
java {
srcDir "${topobjdir}/mobile/android/gradle/app/src/androidTest/robocop_harness/java"
srcDir "${topobjdir}/mobile/android/gradle/app/src/androidTest/robocop/java"
srcDir "${topobjdir}/mobile/android/gradle/app/src/androidTest/background/java"
srcDir "${topobjdir}/mobile/android/gradle/app/src/androidTest/browser/java"
}
}
}
}
dependencies {
compile project(':base')
androidTestCompile fileTree(dir: "../../../build/mobile/robocop", include: ['*.jar'])
}

View File

@ -1,6 +1,6 @@
project.buildDir = "${topobjdir}/mobile/android/gradle/base/build"
apply plugin: 'android-library'
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
@ -14,7 +14,7 @@ android {
buildTypes {
release {
runProguard false
minifyEnabled false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
@ -52,7 +52,6 @@ android {
}
res {
srcDir "newtablet/res"
srcDir "../branding/unofficial/res"
srcDir "${topobjdir}/mobile/android/base/res"
// The main resources are symlinked in here.

View File

@ -18,10 +18,10 @@ The debug APK will be at
The ``$OBJDIR/mobile/android/gradle`` directory can be imported into IntelliJ as
follows:
- File > Import Project
- File > Import Project...
- [select ``$OBJDIR/mobile/android/gradle``]
- Import project from external model > Gradle
- [select Use default Gradle wrapper]
- [select Use customizable Gradle wrapper]
When prompted, do not add any files to git. You may need to re-open the
project, or restart IntelliJ, to pick up a compiler language-level change.
@ -42,11 +42,11 @@ Caveats
How the Gradle project is laid out
----------------------------------
To the greatest extent possible, the Gradle configuration lives in the source
directory. The only Gradle configuration that lives in the object directory is
installed when building the ``mobile/android/gradle`` directory.
To the greatest extent possible, the Gradle configuration lives in the object
directory.
At the time of writing, their are three sub-modules: *app*, *base*, and *thirdparty*.
At the time of writing, their are three main sub-modules: *app*, *base*, and
*thirdparty*, and several smaller sub-modules.
*app* is the Fennec wrapper; it generates the **org.mozilla.fennec.R** resource
package. *base* is the Gecko code; it generates the **org.mozilla.gecko.R**

View File

@ -547,7 +547,6 @@ if CONFIG['MOZ_ANDROID_NEW_TABLET_UI'] and max_sdk_version >= 11:
'tabs/TabStripItemView.java',
'tabs/TabStripView.java'
]
ANDROID_RES_DIRS += [ SRCDIR + '/newtablet/res' ]
gbjar.sources += sync_java_files
gbjar.extra_jars += [

Some files were not shown because too many files have changed in this diff Show More