merge fx-team to mozilla-inbound a=merge
|
@ -67,3 +67,6 @@ GPATH
|
|||
|
||||
# Git clone directory for updating web-platform-tests
|
||||
testing/web-platform/sync/
|
||||
|
||||
# Android Gradle artifacts.
|
||||
mobile/android/gradle/.gradle
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,9 +1106,27 @@ 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) => {
|
||||
LoopRooms.on("joined", this.maybeResumeTourOnRoomJoined.bind(this));
|
||||
|
||||
// If expiresTime is not in the future and the user hasn't
|
||||
// previously authenticated then skip registration.
|
||||
if (!MozLoopServiceInternal.urlExpiryTimeIsInFuture() &&
|
||||
!LoopRooms.getGuestCreatedRoom() &&
|
||||
!MozLoopServiceInternal.fxAOAuthTokenData) {
|
||||
return Promise.resolve("registration not needed");
|
||||
}
|
||||
|
||||
let deferredInitialization = Promise.defer();
|
||||
gInitializeTimerFunc(deferredInitialization);
|
||||
|
||||
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;
|
||||
|
||||
|
@ -1127,22 +1152,18 @@ this.MozLoopService = {
|
|||
return;
|
||||
}
|
||||
|
||||
this.resumeTour("open");
|
||||
// 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 expiresTime is not in the future and the user hasn't
|
||||
// previously authenticated then skip registration.
|
||||
if (!MozLoopServiceInternal.urlExpiryTimeIsInFuture() &&
|
||||
!LoopRooms.getGuestCreatedRoom() &&
|
||||
!MozLoopServiceInternal.fxAOAuthTokenData) {
|
||||
return Promise.resolve("registration not needed");
|
||||
if (!chatboxesForRoom.length) {
|
||||
log.warn("Tried to resume the tour from a join when the chatbox was closed", room);
|
||||
return;
|
||||
}
|
||||
|
||||
let deferredInitialization = Promise.defer();
|
||||
gInitializeTimerFunc(deferredInitialization);
|
||||
|
||||
return deferredInitialization.promise;
|
||||
}),
|
||||
this.resumeTour("open");
|
||||
},
|
||||
|
||||
/**
|
||||
* The core of the initialization work that happens once the browser is ready
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 === */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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 += [
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'])
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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**
|
||||
|
|
|
@ -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 += [
|
||||
|
|
До Ширина: | Высота: | Размер: 159 B После Ширина: | Высота: | Размер: 159 B |
До Ширина: | Высота: | Размер: 589 B После Ширина: | Высота: | Размер: 589 B |
До Ширина: | Высота: | Размер: 404 B После Ширина: | Высота: | Размер: 404 B |
До Ширина: | Высота: | Размер: 771 B После Ширина: | Высота: | Размер: 771 B |
До Ширина: | Высота: | Размер: 133 B После Ширина: | Высота: | Размер: 133 B |
До Ширина: | Высота: | Размер: 808 B После Ширина: | Высота: | Размер: 808 B |
До Ширина: | Высота: | Размер: 236 B После Ширина: | Высота: | Размер: 236 B |
До Ширина: | Высота: | Размер: 231 B После Ширина: | Высота: | Размер: 231 B |
До Ширина: | Высота: | Размер: 122 B После Ширина: | Высота: | Размер: 122 B |
До Ширина: | Высота: | Размер: 172 B После Ширина: | Высота: | Размер: 172 B |
До Ширина: | Высота: | Размер: 145 B После Ширина: | Высота: | Размер: 145 B |
До Ширина: | Высота: | Размер: 130 B После Ширина: | Высота: | Размер: 130 B |
До Ширина: | Высота: | Размер: 456 B После Ширина: | Высота: | Размер: 456 B |
До Ширина: | Высота: | Размер: 299 B После Ширина: | Высота: | Размер: 299 B |
До Ширина: | Высота: | Размер: 551 B После Ширина: | Высота: | Размер: 551 B |
До Ширина: | Высота: | Размер: 132 B После Ширина: | Высота: | Размер: 132 B |
До Ширина: | Высота: | Размер: 581 B После Ширина: | Высота: | Размер: 581 B |
До Ширина: | Высота: | Размер: 192 B После Ширина: | Высота: | Размер: 192 B |
До Ширина: | Высота: | Размер: 192 B После Ширина: | Высота: | Размер: 192 B |
До Ширина: | Высота: | Размер: 112 B После Ширина: | Высота: | Размер: 112 B |
До Ширина: | Высота: | Размер: 147 B После Ширина: | Высота: | Размер: 147 B |
До Ширина: | Высота: | Размер: 129 B После Ширина: | Высота: | Размер: 129 B |
До Ширина: | Высота: | Размер: 170 B После Ширина: | Высота: | Размер: 170 B |
До Ширина: | Высота: | Размер: 754 B После Ширина: | Высота: | Размер: 754 B |
До Ширина: | Высота: | Размер: 475 B После Ширина: | Высота: | Размер: 475 B |
До Ширина: | Высота: | Размер: 995 B После Ширина: | Высота: | Размер: 995 B |
До Ширина: | Высота: | Размер: 135 B После Ширина: | Высота: | Размер: 135 B |
До Ширина: | Высота: | Размер: 1.0 KiB После Ширина: | Высота: | Размер: 1.0 KiB |
До Ширина: | Высота: | Размер: 245 B После Ширина: | Высота: | Размер: 245 B |
До Ширина: | Высота: | Размер: 240 B После Ширина: | Высота: | Размер: 240 B |
До Ширина: | Высота: | Размер: 127 B После Ширина: | Высота: | Размер: 127 B |
До Ширина: | Высота: | Размер: 197 B После Ширина: | Высота: | Размер: 197 B |
До Ширина: | Высота: | Размер: 164 B После Ширина: | Высота: | Размер: 164 B |
До Ширина: | Высота: | Размер: 209 B После Ширина: | Высота: | Размер: 209 B |
До Ширина: | Высота: | Размер: 1006 B После Ширина: | Высота: | Размер: 1006 B |
До Ширина: | Высота: | Размер: 661 B После Ширина: | Высота: | Размер: 661 B |
До Ширина: | Высота: | Размер: 1.3 KiB После Ширина: | Высота: | Размер: 1.3 KiB |
До Ширина: | Высота: | Размер: 137 B После Ширина: | Высота: | Размер: 137 B |
До Ширина: | Высота: | Размер: 1016 B После Ширина: | Высота: | Размер: 1016 B |
До Ширина: | Высота: | Размер: 334 B После Ширина: | Высота: | Размер: 334 B |
До Ширина: | Высота: | Размер: 334 B После Ширина: | Высота: | Размер: 334 B |
До Ширина: | Высота: | Размер: 232 B После Ширина: | Высота: | Размер: 232 B |
До Ширина: | Высота: | Размер: 197 B После Ширина: | Высота: | Размер: 197 B |
До Ширина: | Высота: | Размер: 897 B После Ширина: | Высота: | Размер: 897 B |
До Ширина: | Высота: | Размер: 641 B После Ширина: | Высота: | Размер: 641 B |
До Ширина: | Высота: | Размер: 629 B После Ширина: | Высота: | Размер: 629 B |
До Ширина: | Высота: | Размер: 436 B После Ширина: | Высота: | Размер: 436 B |
До Ширина: | Высота: | Размер: 1.1 KiB После Ширина: | Высота: | Размер: 1.1 KiB |
До Ширина: | Высота: | Размер: 744 B После Ширина: | Высота: | Размер: 744 B |
До Ширина: | Высота: | Размер: 1.5 KiB После Ширина: | Высота: | Размер: 1.5 KiB |