merge mozilla-central to mozilla-inbound. r=merge a=merge
16
.cron.yml
@ -38,11 +38,21 @@ jobs:
|
||||
- date
|
||||
when: [] # never (hook only)
|
||||
|
||||
- name: nightly-desktop-win
|
||||
- name: nightly-desktop-win32
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nd-Win
|
||||
target-tasks-method: nightly_win
|
||||
treeherder-symbol: Nd-win32
|
||||
target-tasks-method: nightly_win32
|
||||
run-on-projects:
|
||||
- mozilla-central
|
||||
- date
|
||||
when: [] # never (hook only)
|
||||
|
||||
- name: nightly-desktop-win64
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nd-win64
|
||||
target-tasks-method: nightly_win64
|
||||
run-on-projects:
|
||||
- mozilla-central
|
||||
- date
|
||||
|
@ -98,11 +98,3 @@ interface nsIAccessibilityService : nsISupports
|
||||
*/
|
||||
boolean isLogged(in AString aModule);
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated, use nsIAccessibilityService instead.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(d85e0cbe-47ce-490c-8488-f821dd2be0c2)]
|
||||
interface nsIAccessibleRetrieval : nsIAccessibilityService
|
||||
{
|
||||
};
|
||||
|
@ -91,8 +91,7 @@ xpcAccessibilityService::Release(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE(xpcAccessibilityService, nsIAccessibilityService,
|
||||
nsIAccessibleRetrieval)
|
||||
NS_IMPL_QUERY_INTERFACE(xpcAccessibilityService, nsIAccessibilityService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication)
|
||||
|
@ -7,13 +7,12 @@
|
||||
|
||||
#include "nsIAccessibilityService.h"
|
||||
|
||||
class xpcAccessibilityService : public nsIAccessibleRetrieval
|
||||
class xpcAccessibilityService : public nsIAccessibilityService
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIACCESSIBILITYSERVICE
|
||||
NS_DECL_NSIACCESSIBLERETRIEVAL
|
||||
|
||||
/**
|
||||
* Return true if xpc accessibility service is in use.
|
||||
|
@ -1096,7 +1096,11 @@ pref("security.sandbox.content.level", 3);
|
||||
//
|
||||
// This setting may not be required anymore once we decide to permanently
|
||||
// enable the content sandbox.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("security.sandbox.content.level", 3);
|
||||
#else
|
||||
pref("security.sandbox.content.level", 2);
|
||||
#endif
|
||||
pref("security.sandbox.content.write_path_whitelist", "");
|
||||
pref("security.sandbox.content.read_path_whitelist", "");
|
||||
pref("security.sandbox.content.syscall_whitelist", "");
|
||||
|
@ -22,54 +22,53 @@ XPCOMUtils.defineLazyGetter(this, "extensionNameFromURI", () => {
|
||||
// lazy module getters
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AboutHome: "resource:///modules/AboutHome.jsm",
|
||||
BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
|
||||
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||
CastingApps: "resource:///modules/CastingApps.jsm",
|
||||
CharsetMenu: "resource://gre/modules/CharsetMenu.jsm",
|
||||
Color: "resource://gre/modules/Color.jsm",
|
||||
ContentSearch: "resource:///modules/ContentSearch.jsm",
|
||||
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
|
||||
CustomizableUI: "resource:///modules/CustomizableUI.jsm",
|
||||
Deprecated: "resource://gre/modules/Deprecated.jsm",
|
||||
DownloadsCommon: "resource:///modules/DownloadsCommon.jsm",
|
||||
E10SUtils: "resource:///modules/E10SUtils.jsm",
|
||||
ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
|
||||
FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
|
||||
GMPInstallManager: "resource://gre/modules/GMPInstallManager.jsm",
|
||||
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
|
||||
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
|
||||
PageActions: "resource:///modules/PageActions.jsm",
|
||||
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
|
||||
PluralForm: "resource://gre/modules/PluralForm.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
|
||||
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
|
||||
ReaderMode: "resource://gre/modules/ReaderMode.jsm",
|
||||
ReaderParent: "resource:///modules/ReaderParent.jsm",
|
||||
RecentWindow: "resource:///modules/RecentWindow.jsm",
|
||||
SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm",
|
||||
SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
|
||||
ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm",
|
||||
SimpleServiceDiscovery: "resource://gre/modules/SimpleServiceDiscovery.jsm",
|
||||
SitePermissions: "resource:///modules/SitePermissions.jsm",
|
||||
Social: "resource:///modules/Social.jsm",
|
||||
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
|
||||
TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
|
||||
Translation: "resource:///modules/translation/Translation.jsm",
|
||||
UITour: "resource:///modules/UITour.jsm",
|
||||
UpdateUtils: "resource://gre/modules/UpdateUtils.jsm",
|
||||
Utils: "resource://gre/modules/sessionstore/Utils.jsm",
|
||||
Weave: "resource://services-sync/main.js",
|
||||
WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
|
||||
fxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
||||
gDevTools: "resource://devtools/client/framework/gDevTools.jsm",
|
||||
gDevToolsBrowser: "resource://devtools/client/framework/gDevTools.jsm",
|
||||
webrtcUI: "resource:///modules/webrtcUI.jsm",
|
||||
ZoomUI: "resource:///modules/ZoomUI.jsm",
|
||||
["AboutHome", "resource:///modules/AboutHome.jsm"],
|
||||
["BrowserUITelemetry", "resource:///modules/BrowserUITelemetry.jsm"],
|
||||
["BrowserUsageTelemetry", "resource:///modules/BrowserUsageTelemetry.jsm"],
|
||||
["BrowserUtils", "resource://gre/modules/BrowserUtils.jsm"],
|
||||
["CastingApps", "resource:///modules/CastingApps.jsm"],
|
||||
["CharsetMenu", "resource://gre/modules/CharsetMenu.jsm"],
|
||||
["Color", "resource://gre/modules/Color.jsm"],
|
||||
["ContentSearch", "resource:///modules/ContentSearch.jsm"],
|
||||
["ContextualIdentityService", "resource://gre/modules/ContextualIdentityService.jsm"],
|
||||
["CustomizableUI", "resource:///modules/CustomizableUI.jsm"],
|
||||
["Deprecated", "resource://gre/modules/Deprecated.jsm"],
|
||||
["DownloadsCommon", "resource:///modules/DownloadsCommon.jsm"],
|
||||
["E10SUtils", "resource:///modules/E10SUtils.jsm"],
|
||||
["ExtensionsUI", "resource:///modules/ExtensionsUI.jsm"],
|
||||
["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
|
||||
["LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"],
|
||||
["Log", "resource://gre/modules/Log.jsm"],
|
||||
["LoginManagerParent", "resource://gre/modules/LoginManagerParent.jsm"],
|
||||
["NewTabUtils", "resource://gre/modules/NewTabUtils.jsm"],
|
||||
["PageActions", "resource:///modules/PageActions.jsm"],
|
||||
["PageThumbs", "resource://gre/modules/PageThumbs.jsm"],
|
||||
["PluralForm", "resource://gre/modules/PluralForm.jsm"],
|
||||
["PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"],
|
||||
["ProcessHangMonitor", "resource:///modules/ProcessHangMonitor.jsm"],
|
||||
["PromiseUtils", "resource://gre/modules/PromiseUtils.jsm"],
|
||||
["ReaderMode", "resource://gre/modules/ReaderMode.jsm"],
|
||||
["ReaderParent", "resource:///modules/ReaderParent.jsm"],
|
||||
["RecentWindow", "resource:///modules/RecentWindow.jsm"],
|
||||
["SafeBrowsing", "resource://gre/modules/SafeBrowsing.jsm"],
|
||||
["SessionStore", "resource:///modules/sessionstore/SessionStore.jsm"],
|
||||
["ShortcutUtils", "resource://gre/modules/ShortcutUtils.jsm"],
|
||||
["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
|
||||
["SitePermissions", "resource:///modules/SitePermissions.jsm"],
|
||||
["Social", "resource:///modules/Social.jsm"],
|
||||
["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
|
||||
["TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"],
|
||||
["Translation", "resource:///modules/translation/Translation.jsm"],
|
||||
["UITour", "resource:///modules/UITour.jsm"],
|
||||
["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"],
|
||||
["Utils", "resource://gre/modules/sessionstore/Utils.jsm"],
|
||||
["Weave", "resource://services-sync/main.js"],
|
||||
["WebNavigationFrames", "resource://gre/modules/WebNavigationFrames.jsm"],
|
||||
["fxAccounts", "resource://gre/modules/FxAccounts.jsm"],
|
||||
["gDevTools", "resource://devtools/client/framework/gDevTools.jsm"],
|
||||
["gDevToolsBrowser", "resource://devtools/client/framework/gDevTools.jsm"],
|
||||
["webrtcUI", "resource:///modules/webrtcUI.jsm"],
|
||||
["ZoomUI", "resource:///modules/ZoomUI.jsm"],
|
||||
});
|
||||
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
@ -1609,34 +1608,7 @@ var gBrowserInit = {
|
||||
ctrlTab.readPref();
|
||||
gPrefService.addObserver(ctrlTab.prefName, ctrlTab);
|
||||
|
||||
// Initialize the download manager some time after the app starts so that
|
||||
// auto-resume downloads begin (such as after crashing or quitting with
|
||||
// active downloads) and speeds up the first-load of the download manager UI.
|
||||
// If the user manually opens the download manager before the timeout, the
|
||||
// downloads will start right away, and initializing again won't hurt.
|
||||
setTimeout(function() {
|
||||
try {
|
||||
DownloadsCommon.initializeAllDataLinks();
|
||||
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {})
|
||||
.DownloadsTaskbar.registerIndicator(window);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
// Load the Login Manager data from disk off the main thread, some time
|
||||
// after startup. If the data is required before the timeout, for example
|
||||
// because a restored page contains a password field, it will be loaded on
|
||||
// the main thread, and this initialization request will be ignored.
|
||||
setTimeout(function() {
|
||||
try {
|
||||
Services.logins;
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// The object handling the downloads indicator is also initialized here in the
|
||||
// The object handling the downloads indicator is initialized here in the
|
||||
// delayed startup function, but the actual indicator element is not loaded
|
||||
// unless there are downloads to be displayed.
|
||||
DownloadsButton.initializeIndicator();
|
||||
@ -1660,27 +1632,12 @@ var gBrowserInit = {
|
||||
MenuTouchModeObserver.init();
|
||||
}
|
||||
|
||||
// initialize the sync UI
|
||||
requestIdleCallback(() => {
|
||||
gSync.init();
|
||||
}, {timeout: 1000 * 5});
|
||||
|
||||
if (AppConstants.MOZ_DATA_REPORTING)
|
||||
gDataNotificationInfoBar.init();
|
||||
|
||||
if (!AppConstants.MOZILLA_OFFICIAL)
|
||||
DevelopmentHelpers.init();
|
||||
|
||||
requestIdleCallback(() => {
|
||||
// setup simple gestures support
|
||||
gGestureSupport.init(true);
|
||||
|
||||
// setup history swipe animation
|
||||
gHistorySwipeAnimation.init();
|
||||
});
|
||||
|
||||
requestIdleCallback(() => { gBrowserThumbnails.init(); });
|
||||
|
||||
gExtensionsNotifications.init();
|
||||
|
||||
let wasMinimized = window.windowState == window.STATE_MINIMIZED;
|
||||
@ -1698,23 +1655,6 @@ var gBrowserInit = {
|
||||
gNavToolbox.addEventListener("customizationstarting", CustomizationHandler);
|
||||
gNavToolbox.addEventListener("customizationending", CustomizationHandler);
|
||||
|
||||
// End startup crash tracking after a delay to catch crashes while restoring
|
||||
// tabs and to postpone saving the pref to disk.
|
||||
try {
|
||||
const startupCrashEndDelay = 30 * 1000;
|
||||
setTimeout(Services.startup.trackStartupCrashEnd, startupCrashEndDelay);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Could not end startup crash tracking: " + ex);
|
||||
}
|
||||
|
||||
// Delay this a minute into the idle time because there's no rush.
|
||||
requestIdleCallback(() => {
|
||||
this.gmpInstallManager = new GMPInstallManager();
|
||||
// We don't really care about the results, if someone is interested they
|
||||
// can check the log.
|
||||
this.gmpInstallManager.simpleCheckAndInstall().catch(() => {});
|
||||
}, {timeout: 1000 * 60});
|
||||
|
||||
SessionStore.promiseInitialized.then(() => {
|
||||
// Bail out if the window has been closed in the meantime.
|
||||
if (window.closed) {
|
||||
@ -1727,21 +1667,6 @@ var gBrowserInit = {
|
||||
SidebarUI.startDelayedLoad();
|
||||
SocialUI.init();
|
||||
|
||||
// Telemetry for master-password - we do this after 5 seconds as it
|
||||
// can cause IO if NSS/PSM has not already initialized.
|
||||
setTimeout(() => {
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
|
||||
.getService(Ci.nsIPK11TokenDB);
|
||||
let token = tokenDB.getInternalKeyToken();
|
||||
let mpEnabled = token.hasPassword;
|
||||
if (mpEnabled) {
|
||||
Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
PanicButtonNotifier.init();
|
||||
});
|
||||
|
||||
@ -1756,10 +1681,76 @@ var gBrowserInit = {
|
||||
this.delayedStartupFinished = true;
|
||||
|
||||
_resolveDelayedStartup();
|
||||
|
||||
SessionStore.promiseAllWindowsRestored.then(() => {
|
||||
this._schedulePerWindowIdleTasks();
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
|
||||
TelemetryTimestamps.add("delayedStartupFinished");
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this function as an entry point to schedule tasks that
|
||||
* need to run once per window after startup, and can be scheduled
|
||||
* by using an idle callback.
|
||||
*
|
||||
* The functions scheduled here will fire from idle callbacks
|
||||
* once every window has finished being restored by session
|
||||
* restore, and after the equivalent only-once tasks
|
||||
* have run (from _scheduleStartupIdleTasks in nsBrowserGlue.js).
|
||||
*/
|
||||
_schedulePerWindowIdleTasks() {
|
||||
// Bail out if the window has been closed in the meantime.
|
||||
if (window.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
function scheduleIdleTask(func, options) {
|
||||
requestIdleCallback(function idleTaskRunner() {
|
||||
if (!window.closed) {
|
||||
func();
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
// Initialize the Sync UI
|
||||
gSync.init();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
CombinedStopReload.startAnimationPrefMonitoring();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
// setup simple gestures support
|
||||
gGestureSupport.init(true);
|
||||
|
||||
// setup history swipe animation
|
||||
gHistorySwipeAnimation.init();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
gBrowserThumbnails.init();
|
||||
});
|
||||
|
||||
scheduleIdleTask(() => {
|
||||
// Initialize the download manager some time after the app starts so that
|
||||
// auto-resume downloads begin (such as after crashing or quitting with
|
||||
// active downloads) and speeds up the first-load of the download manager UI.
|
||||
// If the user manually opens the download manager before the timeout, the
|
||||
// downloads will start right away, and initializing again won't hurt.
|
||||
try {
|
||||
DownloadsCommon.initializeAllDataLinks();
|
||||
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {})
|
||||
.DownloadsTaskbar.registerIndicator(window);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}, {timeout: 10000});
|
||||
},
|
||||
|
||||
// Returns the URI(s) to load at startup.
|
||||
_getUriToLoad() {
|
||||
// window.arguments[0]: URI to load (string), or an nsIArray of
|
||||
@ -1875,10 +1866,6 @@ var gBrowserInit = {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
||||
if (this.gmpInstallManager) {
|
||||
this.gmpInstallManager.uninit();
|
||||
}
|
||||
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
|
||||
MenuTouchModeObserver.uninit();
|
||||
}
|
||||
@ -4966,14 +4953,6 @@ var CombinedStopReload = {
|
||||
|
||||
// Disable animations until the browser has fully loaded.
|
||||
this.animate = false;
|
||||
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup)
|
||||
.getStartupInfo();
|
||||
if (startupInfo.sessionRestored) {
|
||||
this.startAnimationPrefMonitoring();
|
||||
} else {
|
||||
Services.obs.addObserver(this, "sessionstore-windows-restored");
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
@ -5010,24 +4989,19 @@ var CombinedStopReload = {
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "sessionstore-windows-restored") {
|
||||
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
||||
this.startAnimationPrefMonitoring();
|
||||
} else if (topic == "nsPref:changed") {
|
||||
if (topic == "nsPref:changed") {
|
||||
this.animate = Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled");
|
||||
}
|
||||
},
|
||||
|
||||
startAnimationPrefMonitoring() {
|
||||
requestIdleCallback(() => {
|
||||
// CombinedStopReload may have been uninitialized before the idleCallback is executed.
|
||||
if (!this._initialized)
|
||||
return;
|
||||
this.animate = Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
|
||||
Services.prefs.getBoolPref("browser.stopReloadAnimation.enabled");
|
||||
Services.prefs.addObserver("toolkit.cosmeticAnimations.enabled", this);
|
||||
this.stopReloadContainer.addEventListener("animationend", this);
|
||||
});
|
||||
// CombinedStopReload may have been uninitialized before the idleCallback is executed.
|
||||
if (!this._initialized)
|
||||
return;
|
||||
this.animate = Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
|
||||
Services.prefs.getBoolPref("browser.stopReloadAnimation.enabled");
|
||||
Services.prefs.addObserver("toolkit.cosmeticAnimations.enabled", this);
|
||||
this.stopReloadContainer.addEventListener("animationend", this);
|
||||
},
|
||||
|
||||
onTabSwitch() {
|
||||
|
@ -1115,7 +1115,7 @@
|
||||
flex="1"/>
|
||||
<toolbarbutton type="menu"
|
||||
id="PlacesChevron"
|
||||
class="chevron"
|
||||
class="toolbarbutton-1"
|
||||
mousethrough="never"
|
||||
collapsed="true"
|
||||
tooltiptext="&bookmarksToolbarChevron.tooltip;"
|
||||
|
@ -5948,6 +5948,8 @@
|
||||
|
||||
Services.prefs.addObserver("privacy.userContext", this);
|
||||
this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
|
||||
|
||||
this._setPositionalAttributes();
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
|
@ -87,14 +87,8 @@ const whitelist = [
|
||||
},
|
||||
|
||||
{
|
||||
file: "chrome://global/skin/icons/chevron.png",
|
||||
hidpi: "chrome://global/skin/icons/chevron@2x.png",
|
||||
platforms: ["macosx"],
|
||||
},
|
||||
|
||||
{
|
||||
file: "chrome://global/skin/toolbar/chevron.gif",
|
||||
platforms: ["win", "linux"],
|
||||
file: "chrome://browser/skin/chevron.svg",
|
||||
platforms: ["win", "linux", "macosx"],
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -15,17 +15,6 @@ const EXPECTED_OVERFLOW_REFLOWS = [
|
||||
"select@chrome://global/content/bindings/textbox.xml",
|
||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
||||
"updateDisplay/<@chrome://browser/content/tabbrowser.xml",
|
||||
"set_selectedIndex@chrome://browser/content/tabbrowser.xml",
|
||||
"set_selectedPanel@chrome://global/content/bindings/tabbox.xml",
|
||||
"set_selectedIndex@chrome://global/content/bindings/tabbox.xml",
|
||||
"set_selectedItem@chrome://global/content/bindings/tabbox.xml",
|
||||
"set_selectedTab@chrome://global/content/bindings/tabbox.xml",
|
||||
"set_selectedTab@chrome://browser/content/tabbrowser.xml",
|
||||
"loadOneTab@chrome://browser/content/tabbrowser.xml",
|
||||
"openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||
"BrowserOpenTab@chrome://browser/content/browser.js",
|
||||
]
|
||||
},
|
||||
];
|
||||
|
@ -212,8 +212,10 @@ const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
|
||||
// Maximum interval between backups. If the last backup is older than these
|
||||
// days we will try to create a new one more aggressively.
|
||||
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3;
|
||||
// Seconds of idle time before reporting media telemetry.
|
||||
const MEDIA_TELEMETRY_IDLE_TIME_SEC = 20;
|
||||
// Seconds of idle time before the late idle tasks will be scheduled.
|
||||
const LATE_TASKS_IDLE_TIME_SEC = 20;
|
||||
// Time after we stop tracking startup crashes.
|
||||
const STARTUP_CRASHES_END_DELAY_MS = 30 * 1000;
|
||||
|
||||
// Factory object
|
||||
const BrowserGlueServiceFactory = {
|
||||
@ -554,9 +556,13 @@ BrowserGlue.prototype = {
|
||||
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
|
||||
delete this._bookmarksBackupIdleTime;
|
||||
}
|
||||
if (this._mediaTelemetryIdleObserver) {
|
||||
this._idleService.removeIdleObserver(this._mediaTelemetryIdleObserver, MEDIA_TELEMETRY_IDLE_TIME_SEC);
|
||||
delete this._mediaTelemetryIdleObserver;
|
||||
if (this._lateTasksIdleObserver) {
|
||||
this._idleService.removeIdleObserver(this._lateTasksIdleObserver, LATE_TASKS_IDLE_TIME_SEC);
|
||||
delete this._lateTasksIdleObserver;
|
||||
}
|
||||
if (this._gmpInstallManager) {
|
||||
this._gmpInstallManager.uninit();
|
||||
delete this._gmpInstallManager;
|
||||
}
|
||||
try {
|
||||
os.removeObserver(this, "places-init-complete");
|
||||
@ -868,17 +874,6 @@ BrowserGlue.prototype = {
|
||||
Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap-enabled.js", true);
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// For Windows 7, initialize the jump list module.
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
if (WINTASKBAR_CONTRACTID in Cc &&
|
||||
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
|
||||
let temp = {};
|
||||
Cu.import("resource:///modules/WindowsJumpLists.jsm", temp);
|
||||
temp.WinTaskbarJumpList.startup();
|
||||
}
|
||||
}
|
||||
|
||||
TabCrashHandler.init();
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
PluginCrashReporter.init();
|
||||
@ -951,27 +946,12 @@ BrowserGlue.prototype = {
|
||||
|
||||
this._firstWindowTelemetry(aWindow);
|
||||
this._firstWindowLoaded();
|
||||
|
||||
this._mediaTelemetryIdleObserver = {
|
||||
browserGlue: this,
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic != "idle") {
|
||||
return;
|
||||
}
|
||||
this.browserGlue._sendMediaTelemetry();
|
||||
}
|
||||
};
|
||||
this._idleService.addIdleObserver(this._mediaTelemetryIdleObserver,
|
||||
MEDIA_TELEMETRY_IDLE_TIME_SEC);
|
||||
},
|
||||
|
||||
_sendMediaTelemetry() {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
let v = win.document.createElementNS("http://www.w3.org/1999/xhtml", "video");
|
||||
v.reportCanPlayTelemetry();
|
||||
this._idleService.removeIdleObserver(this._mediaTelemetryIdleObserver,
|
||||
MEDIA_TELEMETRY_IDLE_TIME_SEC);
|
||||
delete this._mediaTelemetryIdleObserver;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1038,10 +1018,6 @@ BrowserGlue.prototype = {
|
||||
BrowserUsageTelemetry.init();
|
||||
BrowserUITelemetry.init();
|
||||
|
||||
if (AppConstants.MOZ_DEV_EDITION) {
|
||||
this._createExtraDefaultProfile();
|
||||
}
|
||||
|
||||
this._initServiceDiscovery();
|
||||
|
||||
// Show update notification, if needed.
|
||||
@ -1076,99 +1052,143 @@ BrowserGlue.prototype = {
|
||||
this._notifyDisabledNonMpc();
|
||||
}
|
||||
|
||||
// Perform default browser checking.
|
||||
if (ShellService) {
|
||||
let shouldCheck = AppConstants.DEBUG ? false :
|
||||
ShellService.shouldCheckDefaultBrowser;
|
||||
|
||||
const skipDefaultBrowserCheck =
|
||||
Services.prefs.getBoolPref("browser.shell.skipDefaultBrowserCheckOnFirstRun") &&
|
||||
!Services.prefs.getBoolPref("browser.shell.didSkipDefaultBrowserCheckOnFirstRun");
|
||||
|
||||
const usePromptLimit = !AppConstants.RELEASE_OR_BETA;
|
||||
let promptCount =
|
||||
usePromptLimit ? Services.prefs.getIntPref("browser.shell.defaultBrowserCheckCount") : 0;
|
||||
|
||||
let willRecoverSession = false;
|
||||
try {
|
||||
let ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||
getService(Ci.nsISessionStartup);
|
||||
willRecoverSession =
|
||||
(ss.sessionType == Ci.nsISessionStartup.RECOVER_SESSION);
|
||||
} catch (ex) { /* never mind; suppose SessionStore is broken */ }
|
||||
|
||||
// startup check, check all assoc
|
||||
let isDefault = false;
|
||||
let isDefaultError = false;
|
||||
try {
|
||||
isDefault = ShellService.isDefaultBrowser(true, false);
|
||||
} catch (ex) {
|
||||
isDefaultError = true;
|
||||
}
|
||||
|
||||
if (isDefault) {
|
||||
let now = (Math.floor(Date.now() / 1000)).toString();
|
||||
Services.prefs.setCharPref("browser.shell.mostRecentDateSetAsDefault", now);
|
||||
}
|
||||
|
||||
let willPrompt = shouldCheck && !isDefault && !willRecoverSession;
|
||||
|
||||
// Skip the "Set Default Browser" check during first-run or after the
|
||||
// browser has been run a few times.
|
||||
if (willPrompt) {
|
||||
if (skipDefaultBrowserCheck) {
|
||||
Services.prefs.setBoolPref("browser.shell.didSkipDefaultBrowserCheckOnFirstRun", true);
|
||||
willPrompt = false;
|
||||
} else {
|
||||
promptCount++;
|
||||
}
|
||||
if (usePromptLimit && promptCount > 3) {
|
||||
willPrompt = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (usePromptLimit && willPrompt) {
|
||||
Services.prefs.setIntPref("browser.shell.defaultBrowserCheckCount", promptCount);
|
||||
}
|
||||
|
||||
try {
|
||||
// Report default browser status on startup to telemetry
|
||||
// so we can track whether we are the default.
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT")
|
||||
.add(isDefault);
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
|
||||
.add(isDefaultError);
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_ALWAYS_CHECK")
|
||||
.add(shouldCheck);
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_DIALOG_PROMPT_RAWCOUNT")
|
||||
.add(promptCount);
|
||||
} catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
|
||||
|
||||
if (willPrompt) {
|
||||
Services.tm.dispatchToMainThread(function() {
|
||||
DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
UnsubmittedCrashHandler.init();
|
||||
Services.tm.idleDispatchToMainThread(function() {
|
||||
UnsubmittedCrashHandler.checkForUnsubmittedCrashReports();
|
||||
});
|
||||
}
|
||||
|
||||
// Let's load the contextual identities.
|
||||
this._sanitizer.onStartup();
|
||||
E10SAccessibilityCheck.onWindowsRestored();
|
||||
|
||||
this._scheduleStartupIdleTasks();
|
||||
|
||||
this._lateTasksIdleObserver = (idleService, topic, data) => {
|
||||
if (topic == "idle") {
|
||||
idleService.removeIdleObserver(this._lateTasksIdleObserver,
|
||||
LATE_TASKS_IDLE_TIME_SEC);
|
||||
delete this._lateTasksIdleObserver;
|
||||
this._scheduleArbitrarilyLateIdleTasks();
|
||||
}
|
||||
};
|
||||
this._idleService.addIdleObserver(
|
||||
this._lateTasksIdleObserver, LATE_TASKS_IDLE_TIME_SEC);
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this function as an entry point to schedule tasks that
|
||||
* need to run only once after startup, and can be scheduled
|
||||
* by using an idle callback.
|
||||
*
|
||||
* The functions scheduled here will fire from idle callbacks
|
||||
* once every window has finished being restored by session
|
||||
* restore, and it's guaranteed that they will run before
|
||||
* the equivalent per-window idle tasks
|
||||
* (from _schedulePerWindowIdleTasks in browser.js).
|
||||
*
|
||||
* If you have something that can wait even further than the
|
||||
* per-window initialization, please schedule them using
|
||||
* _scheduleArbitrarilyLateIdleTasks.
|
||||
* Don't be fooled by thinking that the use of the timeout parameter
|
||||
* will delay your function: it will just ensure that it potentially
|
||||
* happens _earlier_ than expected (when the timeout limit has been reached),
|
||||
* but it will not make it happen later (and out of order) compared
|
||||
* to the other ones scheduled together.
|
||||
*/
|
||||
_scheduleStartupIdleTasks() {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
ContextualIdentityService.load();
|
||||
});
|
||||
|
||||
// Load the Login Manager data from disk off the main thread, some time
|
||||
// after startup. If the data is required before this runs, for example
|
||||
// because a restored page contains a password field, it will be loaded on
|
||||
// the main thread, and this initialization request will be ignored.
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
try {
|
||||
Services.logins;
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// It's important that SafeBrowsing is initialized reasonably
|
||||
// early, so we use a maximum timeout for it.
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
SafeBrowsing.init();
|
||||
}, 5000);
|
||||
|
||||
this._sanitizer.onStartup();
|
||||
E10SAccessibilityCheck.onWindowsRestored();
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
UnsubmittedCrashHandler.checkForUnsubmittedCrashReports();
|
||||
});
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
// For Windows 7, initialize the jump list module.
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
if (WINTASKBAR_CONTRACTID in Cc &&
|
||||
Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
|
||||
let temp = {};
|
||||
Cu.import("resource:///modules/WindowsJumpLists.jsm", temp);
|
||||
temp.WinTaskbarJumpList.startup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_DEV_EDITION) {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
this._createExtraDefaultProfile();
|
||||
});
|
||||
}
|
||||
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
this._checkForDefaultBrowser();
|
||||
});
|
||||
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
let {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
setTimeout(function() {
|
||||
Services.tm.idleDispatchToMainThread(Services.startup.trackStartupCrashEnd);
|
||||
}, STARTUP_CRASHES_END_DELAY_MS);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this function as an entry point to schedule tasks that need
|
||||
* to run once per session, at any arbitrary point in time.
|
||||
* This function will be called from an idle observer. Check the value of
|
||||
* LATE_TASKS_IDLE_TIME_SEC to see the current value for this idle
|
||||
* observer.
|
||||
*
|
||||
* Note: this function may never be called if the user is never idle for the
|
||||
* full length of the period of time specified. But given a reasonably low
|
||||
* value, this is unlikely.
|
||||
*/
|
||||
_scheduleArbitrarilyLateIdleTasks() {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
this._sendMediaTelemetry();
|
||||
});
|
||||
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
// Telemetry for master-password - we do this after a delay as it
|
||||
// can cause IO if NSS/PSM has not already initialized.
|
||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"]
|
||||
.getService(Ci.nsIPK11TokenDB);
|
||||
let token = tokenDB.getInternalKeyToken();
|
||||
let mpEnabled = token.hasPassword;
|
||||
if (mpEnabled) {
|
||||
Services.telemetry.getHistogramById("MASTER_PASSWORD_ENABLED").add(mpEnabled);
|
||||
}
|
||||
});
|
||||
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
let obj = {};
|
||||
Cu.import("resource://gre/modules/GMPInstallManager.jsm", obj);
|
||||
this._gmpInstallManager = new obj.GMPInstallManager();
|
||||
// We don't really care about the results, if someone is interested they
|
||||
// can check the log.
|
||||
this._gmpInstallManager.simpleCheckAndInstall().catch(() => {});
|
||||
});
|
||||
},
|
||||
|
||||
_createExtraDefaultProfile() {
|
||||
@ -2084,6 +2104,83 @@ BrowserGlue.prototype = {
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
},
|
||||
|
||||
_checkForDefaultBrowser() {
|
||||
// Perform default browser checking.
|
||||
if (!ShellService) {
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldCheck = AppConstants.DEBUG ? false :
|
||||
ShellService.shouldCheckDefaultBrowser;
|
||||
|
||||
const skipDefaultBrowserCheck =
|
||||
Services.prefs.getBoolPref("browser.shell.skipDefaultBrowserCheckOnFirstRun") &&
|
||||
!Services.prefs.getBoolPref("browser.shell.didSkipDefaultBrowserCheckOnFirstRun");
|
||||
|
||||
const usePromptLimit = !AppConstants.RELEASE_OR_BETA;
|
||||
let promptCount =
|
||||
usePromptLimit ? Services.prefs.getIntPref("browser.shell.defaultBrowserCheckCount") : 0;
|
||||
|
||||
let willRecoverSession = false;
|
||||
try {
|
||||
let ss = Cc["@mozilla.org/browser/sessionstartup;1"].
|
||||
getService(Ci.nsISessionStartup);
|
||||
willRecoverSession =
|
||||
(ss.sessionType == Ci.nsISessionStartup.RECOVER_SESSION);
|
||||
} catch (ex) { /* never mind; suppose SessionStore is broken */ }
|
||||
|
||||
// startup check, check all assoc
|
||||
let isDefault = false;
|
||||
let isDefaultError = false;
|
||||
try {
|
||||
isDefault = ShellService.isDefaultBrowser(true, false);
|
||||
} catch (ex) {
|
||||
isDefaultError = true;
|
||||
}
|
||||
|
||||
if (isDefault) {
|
||||
let now = (Math.floor(Date.now() / 1000)).toString();
|
||||
Services.prefs.setCharPref("browser.shell.mostRecentDateSetAsDefault", now);
|
||||
}
|
||||
|
||||
let willPrompt = shouldCheck && !isDefault && !willRecoverSession;
|
||||
|
||||
// Skip the "Set Default Browser" check during first-run or after the
|
||||
// browser has been run a few times.
|
||||
if (willPrompt) {
|
||||
if (skipDefaultBrowserCheck) {
|
||||
Services.prefs.setBoolPref("browser.shell.didSkipDefaultBrowserCheckOnFirstRun", true);
|
||||
willPrompt = false;
|
||||
} else {
|
||||
promptCount++;
|
||||
}
|
||||
if (usePromptLimit && promptCount > 3) {
|
||||
willPrompt = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (usePromptLimit && willPrompt) {
|
||||
Services.prefs.setIntPref("browser.shell.defaultBrowserCheckCount", promptCount);
|
||||
}
|
||||
|
||||
try {
|
||||
// Report default browser status on startup to telemetry
|
||||
// so we can track whether we are the default.
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT")
|
||||
.add(isDefault);
|
||||
Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
|
||||
.add(isDefaultError);
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_ALWAYS_CHECK")
|
||||
.add(shouldCheck);
|
||||
Services.telemetry.getHistogramById("BROWSER_SET_DEFAULT_DIALOG_PROMPT_RAWCOUNT")
|
||||
.add(promptCount);
|
||||
} catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
|
||||
|
||||
if (willPrompt) {
|
||||
DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
|
||||
}
|
||||
},
|
||||
|
||||
// ------------------------------
|
||||
// public nsIBrowserGlue members
|
||||
// ------------------------------
|
||||
|
@ -214,6 +214,10 @@ this.SessionStore = {
|
||||
return SessionStoreInternal.promiseInitialized;
|
||||
},
|
||||
|
||||
get promiseAllWindowsRestored() {
|
||||
return SessionStoreInternal.promiseAllWindowsRestored;
|
||||
},
|
||||
|
||||
get canRestoreLastSession() {
|
||||
return SessionStoreInternal.canRestoreLastSession;
|
||||
},
|
||||
@ -532,6 +536,22 @@ var SessionStoreInternal = {
|
||||
// Whether session has been initialized
|
||||
_sessionInitialized: false,
|
||||
|
||||
// A promise resolved once all windows are restored.
|
||||
_deferredAllWindowsRestored: (function() {
|
||||
let deferred = {};
|
||||
|
||||
deferred.promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
return deferred;
|
||||
})(),
|
||||
|
||||
get promiseAllWindowsRestored() {
|
||||
return this._deferredAllWindowsRestored.promise;
|
||||
},
|
||||
|
||||
// Promise that is resolved when we're ready to initialize
|
||||
// and restore the session.
|
||||
_promiseReadyForInitialization: null,
|
||||
@ -1129,6 +1149,7 @@ var SessionStoreInternal = {
|
||||
|
||||
// Nothing to restore now, notify observers things are complete.
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
} else {
|
||||
TelemetryTimestamps.add("sessionRestoreRestoring");
|
||||
this._restoreCount = aInitialState.windows ? aInitialState.windows.length : 0;
|
||||
@ -1147,6 +1168,7 @@ var SessionStoreInternal = {
|
||||
} else {
|
||||
// Nothing to restore, notify observers things are complete.
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
}
|
||||
// this window was opened by _openWindowWithState
|
||||
} else if (!this._isWindowLoaded(aWindow)) {
|
||||
@ -4450,8 +4472,15 @@ var SessionStoreInternal = {
|
||||
return;
|
||||
|
||||
// This was the last window restored at startup, notify observers.
|
||||
Services.obs.notifyObservers(null,
|
||||
this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED);
|
||||
if (!this._browserSetState) {
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
} else {
|
||||
// _browserSetState is used only by tests, and it uses an alternate
|
||||
// notification in order not to retrigger startup observers that
|
||||
// are listening for NOTIFY_WINDOWS_RESTORED.
|
||||
Services.obs.notifyObservers(null, NOTIFY_BROWSER_STATE_RESTORED);
|
||||
}
|
||||
|
||||
this._browserSetState = false;
|
||||
this._restoreCount = -1;
|
||||
|
@ -385,29 +385,12 @@ var FormAutofillContent = {
|
||||
return true;
|
||||
}
|
||||
|
||||
let {addressRecord, creditCardRecord} = handler.createRecords();
|
||||
|
||||
if (!addressRecord && !creditCardRecord) {
|
||||
let records = handler.createRecords();
|
||||
if (!Object.keys(records).length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let data = {};
|
||||
if (addressRecord) {
|
||||
data.address = {
|
||||
guid: handler.address.filledRecordGUID,
|
||||
record: addressRecord,
|
||||
};
|
||||
}
|
||||
|
||||
if (creditCardRecord) {
|
||||
data.creditCard = {
|
||||
guid: handler.creditCard.filledRecordGUID,
|
||||
record: creditCardRecord,
|
||||
};
|
||||
}
|
||||
|
||||
this._onFormSubmit(data, domWin);
|
||||
|
||||
this._onFormSubmit(records, domWin);
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -451,10 +451,16 @@ FormAutofillHandler.prototype = {
|
||||
* Return the records that is converted from address/creditCard fieldDetails and
|
||||
* only valid form records are included.
|
||||
*
|
||||
* @returns {Object} The new profile that convert from details with trimmed result.
|
||||
* @returns {Object}
|
||||
* Consists of two record objects: address, creditCard. Each one can
|
||||
* be omitted if there's no valid fields. A record object consists of
|
||||
* three properties:
|
||||
* - guid: The id of the previously-filled profile or null if omitted.
|
||||
* - record: A valid record converted from details with trimmed result.
|
||||
* - untouchedFields: Fields that aren't touched after autofilling.
|
||||
*/
|
||||
createRecords() {
|
||||
let records = {};
|
||||
let data = {};
|
||||
|
||||
["address", "creditCard"].forEach(type => {
|
||||
let details = this[type].fieldDetails;
|
||||
@ -462,8 +468,12 @@ FormAutofillHandler.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let recordName = `${type}Record`;
|
||||
records[recordName] = {};
|
||||
data[type] = {
|
||||
guid: this[type].filledRecordGUID,
|
||||
record: {},
|
||||
untouchedFields: [],
|
||||
};
|
||||
|
||||
details.forEach(detail => {
|
||||
let element = detail.elementWeakRef.get();
|
||||
// Remove the unnecessary spaces
|
||||
@ -472,23 +482,27 @@ FormAutofillHandler.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
records[recordName][detail.fieldName] = value;
|
||||
data[type].record[detail.fieldName] = value;
|
||||
|
||||
if (detail.state == "AUTO_FILLED") {
|
||||
data[type].untouchedFields.push(detail.fieldName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (records.addressRecord &&
|
||||
Object.keys(records.addressRecord).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD) {
|
||||
if (data.address &&
|
||||
Object.keys(data.address.record).length < FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD) {
|
||||
log.debug("No address record saving since there are only",
|
||||
Object.keys(records.addressRecord).length,
|
||||
Object.keys(data.address.record).length,
|
||||
"usable fields");
|
||||
delete records.addressRecord;
|
||||
delete data.address;
|
||||
}
|
||||
|
||||
if (records.creditCardRecord && !records.creditCardRecord["cc-number"]) {
|
||||
if (data.creditCard && !data.creditCard.record["cc-number"]) {
|
||||
log.debug("No credit card record saving since card number is empty");
|
||||
delete records.creditCardRecord;
|
||||
delete data.creditCard;
|
||||
}
|
||||
|
||||
return records;
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
@ -286,6 +286,14 @@ FormAutofillParent.prototype = {
|
||||
let {address} = data;
|
||||
|
||||
if (address.guid) {
|
||||
// Avoid updating the fields that users don't modify.
|
||||
let originalAddress = this.profileStorage.addresses.get(address.guid);
|
||||
for (let field in address.record) {
|
||||
if (address.untouchedFields.includes(field) && originalAddress[field]) {
|
||||
address.record[field] = originalAddress[field];
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.profileStorage.addresses.mergeIfPossible(address.guid, address.record)) {
|
||||
FormAutofillDoorhanger.show(target, "update").then((state) => {
|
||||
let changedGUIDs = this.profileStorage.addresses.mergeToStorage(address.record);
|
||||
|
@ -1375,10 +1375,25 @@ class Addresses extends AutofillRecords {
|
||||
let hasMatchingField = false;
|
||||
|
||||
for (let field of this.VALID_FIELDS) {
|
||||
if (addressToMerge[field] !== undefined && addressFound[field] !== undefined) {
|
||||
if (addressToMerge[field] != addressFound[field]) {
|
||||
this.log.debug("Conflicts: field", field, "has different value.");
|
||||
return false;
|
||||
let existingField = addressFound[field];
|
||||
let incomingField = addressToMerge[field];
|
||||
if (incomingField !== undefined && existingField !== undefined) {
|
||||
if (incomingField != existingField) {
|
||||
// Treat "street-address" as mergeable if their single-line versions
|
||||
// match each other.
|
||||
if (field == "street-address" &&
|
||||
FormAutofillUtils.toOneLineAddress(existingField) == FormAutofillUtils.toOneLineAddress(incomingField)) {
|
||||
// Keep the value in storage if its amount of lines is greater than
|
||||
// or equal to the incoming one.
|
||||
if (existingField.split("\n").length >= incomingField.split("\n").length) {
|
||||
// Replace the incoming field with the one in storage so it will
|
||||
// be further merged back to storage.
|
||||
addressToMerge[field] = existingField;
|
||||
}
|
||||
} else {
|
||||
this.log.debug("Conflicts: field", field, "has different value.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
hasMatchingField = true;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ add_task(async function test_update_address() {
|
||||
let form = content.document.getElementById("form");
|
||||
let org = form.querySelector("#organization");
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
org.value = "Mozilla";
|
||||
org.setUserInput("Mozilla");
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
@ -52,7 +52,7 @@ add_task(async function test_create_new_address() {
|
||||
let form = content.document.getElementById("form");
|
||||
let tel = form.querySelector("#tel");
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
tel.value = "+1-234-567-890";
|
||||
tel.setUserInput("+1234567890");
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
@ -66,7 +66,7 @@ add_task(async function test_create_new_address() {
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
is(addresses[1].tel, "+1-234-567-890", "Verify the tel field");
|
||||
is(addresses[1].tel, "+1234567890", "Verify the tel field");
|
||||
});
|
||||
|
||||
add_task(async function test_create_new_address_merge() {
|
||||
@ -85,7 +85,7 @@ add_task(async function test_create_new_address_merge() {
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
let form = content.document.getElementById("form");
|
||||
let tel = form.querySelector("#tel");
|
||||
tel.value = "+1 617 253 5702";
|
||||
tel.setUserInput("+16172535702");
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
@ -100,3 +100,41 @@ add_task(async function test_create_new_address_merge() {
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "Still 2 addresses in storage");
|
||||
});
|
||||
|
||||
add_task(async function test_submit_untouched_fields() {
|
||||
let addresses = await getAddresses();
|
||||
is(addresses.length, 2, "2 addresses in storage");
|
||||
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: FORM_URL},
|
||||
async function(browser) {
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
|
||||
"popupshown");
|
||||
await openPopupOn(browser, "form #organization");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
|
||||
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
let form = content.document.getElementById("form");
|
||||
let org = form.querySelector("#organization");
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
org.setUserInput("Organization");
|
||||
|
||||
let tel = form.querySelector("#tel");
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
tel.value = "12345"; // ".value" won't change the highlight status.
|
||||
|
||||
// Wait 1000ms before submission to make sure the input value applied
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
form.querySelector("input[type=submit]").click();
|
||||
});
|
||||
|
||||
await promiseShown;
|
||||
await clickDoorhangerButton(MAIN_BUTTON_INDEX);
|
||||
}
|
||||
);
|
||||
|
||||
addresses = await getAddresses();
|
||||
is(addresses.length, 2, "Still 2 addresses in storage");
|
||||
is(addresses[0].organization, "Organization", "organization should change");
|
||||
is(addresses[0].tel, "+16172535702", "tel should remain unchanged");
|
||||
});
|
||||
|
@ -102,6 +102,101 @@ const MERGE_TESTCASES = [
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with multi-line street-address in storage and single-line incoming one",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn Avenue Line2",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with 3-line street-address in storage and 2-line incoming one",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2 Line3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with single-line street-address in storage and multi-line incoming one",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue Line2",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with 2-line street-address in storage and 3-line incoming one",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2 Line3",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge an address with the same amount of lines",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
addressToMerge: {
|
||||
"street-address": "331 E. Evelyn\nAvenue Line2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue\nLine2\nLine3",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
let do_check_record_matches = (recordWithMeta, record) => {
|
||||
|
@ -56,6 +56,7 @@ const TESTCASES = [
|
||||
"country": "USA",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -79,6 +80,7 @@ const TESTCASES = [
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2000,
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -104,6 +106,7 @@ const TESTCASES = [
|
||||
"country": "USA",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
creditCard: {
|
||||
guid: null,
|
||||
@ -113,6 +116,7 @@ const TESTCASES = [
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2000,
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -134,6 +138,7 @@ const TESTCASES = [
|
||||
"country": "USA",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -156,6 +161,7 @@ const TESTCASES = [
|
||||
"country": "USA",
|
||||
"tel": "1-650-903-0800",
|
||||
},
|
||||
untouchedFields: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -396,8 +396,10 @@
|
||||
@RESPATH@/components/nsSearchService.js
|
||||
@RESPATH@/components/nsSearchSuggestions.js
|
||||
@RESPATH@/components/nsSidebar.js
|
||||
#ifdef NIGHTLY_BUILD
|
||||
@RESPATH@/components/payments.manifest
|
||||
@RESPATH@/components/paymentUIService.js
|
||||
#endif
|
||||
@RESPATH@/components/passwordmgr.manifest
|
||||
@RESPATH@/components/nsLoginInfo.js
|
||||
@RESPATH@/components/nsLoginManager.js
|
||||
|
@ -10,8 +10,6 @@
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
|
||||
%include ../shared/browser.inc
|
||||
|
||||
%include ../shared/browser.inc.css
|
||||
|
||||
:root {
|
||||
@ -812,28 +810,6 @@ html|span.ac-emphasize-text-url {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important;
|
||||
}
|
||||
|
||||
toolbar[brighttext] toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/toolbar/chevron-inverted.png") !important;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-text,
|
||||
toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Status panel */
|
||||
|
||||
.statuspanel-label {
|
||||
|
@ -195,38 +195,6 @@
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/icons/chevron.png");
|
||||
margin: 1px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
toolbar[brighttext] toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/icons/chevron-inverted.png");
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/icons/chevron@2x.png");
|
||||
}
|
||||
|
||||
toolbar[brighttext] toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/icons/chevron-inverted@2x.png");
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
width: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- BOOKMARK BUTTONS ----- */
|
||||
|
||||
.bookmark-item[container] {
|
||||
@ -1072,10 +1040,6 @@ html|span.ac-emphasize-text-url {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bookmark-item {
|
||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
%include ../../../toolkit/themes/osx/global/shared.inc
|
||||
%include ../shared/browser.inc
|
||||
|
||||
%filter substitution
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
%filter substitution
|
||||
|
||||
% Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none.
|
||||
%define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
|
||||
|
||||
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
|
||||
|
||||
%define panelPaletteIconSize var(--panel-palette-icon-size)
|
@ -17,8 +17,8 @@
|
||||
%define buttonStateActive :not([disabled]):-moz-any([open],:hover:active)
|
||||
%define menuStateActive :not([disabled])[_moz-menuactive]:active
|
||||
%define menuStateMenuActive :not([disabled])[_moz-menuactive]
|
||||
|
||||
%include ../browser.inc
|
||||
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
|
||||
%define panelPaletteIconSize 16px
|
||||
|
||||
:root {
|
||||
--panel-ui-exit-subview-gutter-width: 38px;
|
||||
@ -26,7 +26,6 @@
|
||||
--appmenu-yellow-warning-color: #FFEFBF;
|
||||
--appmenu-yellow-warning-hover-color: #FFE8A2;
|
||||
--appmenu-yellow-warning-active-color: #FFE38F;
|
||||
--panel-palette-icon-size: 16px;
|
||||
}
|
||||
|
||||
#PanelUI-popup #PanelUI-contents:empty {
|
||||
|
@ -1,218 +1,221 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1260" height="36" fill="context-fill">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1278" height="36" fill="context-fill">
|
||||
<svg>
|
||||
<path d="M9.714 17.335l-4.948 -5.052a1 1 0 1 0 -1.429 1.4l4.25 4.337 -4.338 4.248a1 1 0 0 0 -0.04 1.414 1 1 0 0 0 1.414 0.04l0.025 -0.025 5.052 -4.948a1 1 0 0 0 0.014 -1.414zm6 0.062l-4.948 -5.051a1 1 0 1 0 -1.429 1.4l4.249 4.336 -4.338 4.248a1 1 0 0 0 -0.04 1.414 1 1 0 0 0 1.415 0.04l0.025 -0.025 5.051 -4.948a1 1 0 0 0 0.015 -1.414z"/>
|
||||
<path d="M9.707 17.293l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414zm6 0l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414z"/>
|
||||
</svg>
|
||||
<svg x="18">
|
||||
<path d="M9.735 17.456l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.461 -4.461 4.118a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.081c0.01 -0.007 0.017 -0.016 0.026 -0.024l5.196 -4.795a1 1 0 0 0 0.057 -1.413zm5.995 0.24l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.462 -4.461 4.117a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.082l0.026 -0.024 5.196 -4.796a1 1 0 0 0 0.057 -1.413z"/>
|
||||
<path d="M9.714 17.3l-4.948 -5.051a1 1 0 1 0 -1.429 1.4l4.25 4.336 -4.338 4.249a1 1 0 0 0 -0.04 1.413 1 1 0 0 0 1.414 0.04l0.025 -0.025 5.052 -4.948a1 1 0 0 0 0.014 -1.414zm6 0.063l-4.948 -5.052a1 1 0 1 0 -1.429 1.4l4.249 4.337 -4.338 4.248a1 1 0 0 0 -0.04 1.413 1 1 0 0 0 1.415 0.04l0.025 -0.025 5.051 -4.948a1 1 0 0 0 0.015 -1.413z"/>
|
||||
</svg>
|
||||
<svg x="36">
|
||||
<path d="M9.766 17.648l-4.546 -5.416a1 1 0 1 0 -1.532 1.286l3.903 4.65 -4.65 3.903a1 1 0 0 0 -0.148 1.407 1 1 0 0 0 1.407 0.148c0.01 -0.007 0.018 -0.016 0.027 -0.023l5.416 -4.546a1 1 0 0 0 0.123 -1.409zm5.977 0.522l-4.546 -5.416a1 1 0 1 0 -1.532 1.286l3.904 4.65 -4.65 3.903a1 1 0 0 0 -0.149 1.407 1 1 0 0 0 1.407 0.148c0.01 -0.007 0.018 -0.016 0.027 -0.023l5.416 -4.546a1 1 0 0 0 0.123 -1.409z"/>
|
||||
<path d="M9.735 17.322l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.461 -4.461 4.118a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.081c0.01 -0.007 0.017 -0.016 0.026 -0.024l5.196 -4.795a1 1 0 0 0 0.057 -1.413zm5.995 0.24l-4.796 -5.196a1 1 0 1 0 -1.47 1.356l4.118 4.462 -4.461 4.117a1 1 0 0 0 -0.082 1.412 1 1 0 0 0 1.412 0.082l0.026 -0.024 5.196 -4.796a1 1 0 0 0 0.057 -1.413z"/>
|
||||
</svg>
|
||||
<svg x="54">
|
||||
<path d="M9.804 17.905l-4.2 -5.688a1 1 0 1 0 -1.609 1.188l3.607 4.884 -4.884 3.606a1 1 0 0 0 -0.236 1.395 1 1 0 0 0 1.395 0.235l0.028 -0.021 5.689 -4.2a1 1 0 0 0 0.21 -1.399zm5.934 0.894l-4.2 -5.689a1 1 0 1 0 -1.609 1.188l3.606 4.884 -4.884 3.606a1 1 0 0 0 -0.235 1.395 1 1 0 0 0 1.394 0.235l0.029 -0.021 5.688 -4.2a1 1 0 0 0 0.21 -1.398z"/>
|
||||
<path d="M9.766 17.357l-4.546 -5.416a1 1 0 1 0 -1.532 1.286l3.903 4.65 -4.65 3.903a1 1 0 0 0 -0.148 1.407 1 1 0 0 0 1.407 0.148l0.027 -0.023 5.416 -4.546a1 1 0 0 0 0.123 -1.409zm5.977 0.522l-4.546 -5.416a1 1 0 1 0 -1.532 1.286l3.904 4.65 -4.65 3.903a1 1 0 0 0 -0.149 1.407 1 1 0 0 0 1.407 0.148l0.027 -0.023 5.416 -4.546a1 1 0 0 0 0.123 -1.409z"/>
|
||||
</svg>
|
||||
<svg x="72">
|
||||
<path d="M9.847 18.22l-3.76 -5.989a1 1 0 1 0 -1.694 1.063l3.229 5.142 -5.143 3.228a1 1 0 0 0 -0.34 1.373 1 1 0 0 0 1.373 0.34c0.011 -0.006 0.02 -0.013 0.03 -0.02l5.99 -3.758a1 1 0 0 0 0.315 -1.379zm5.849 1.338l-3.76 -5.989a1 1 0 1 0 -1.694 1.063l3.229 5.142 -5.143 3.228a1 1 0 0 0 -0.34 1.373 1 1 0 0 0 1.373 0.34l0.03 -0.02 5.99 -3.758a1 1 0 0 0 0.315 -1.379z"/>
|
||||
<path d="M9.804 17.406l-4.2 -5.688a1 1 0 1 0 -1.609 1.188l3.607 4.884 -4.884 3.606a1 1 0 0 0 -0.236 1.394 1 1 0 0 0 1.395 0.235l0.028 -0.02 5.689 -4.2a1 1 0 0 0 0.21 -1.399zm5.934 0.893l-4.2 -5.688a1 1 0 1 0 -1.609 1.188l3.606 4.884 -4.884 3.606a1 1 0 0 0 -0.235 1.394 1 1 0 0 0 1.394 0.236l0.029 -0.021 5.688 -4.2a1 1 0 0 0 0.21 -1.399z"/>
|
||||
</svg>
|
||||
<svg x="90">
|
||||
<path d="M9.89 18.585l-3.227 -6.292a1 1 0 1 0 -1.78 0.912l2.771 5.403 -5.402 2.77a1 1 0 0 0 -0.458 1.338 1 1 0 0 0 1.339 0.458l0.031 -0.016 6.292 -3.227a1 1 0 0 0 0.434 -1.346zm5.71 1.84l-3.226 -6.293a1 1 0 1 0 -1.78 0.912l2.771 5.403 -5.402 2.77a1 1 0 0 0 -0.457 1.339 1 1 0 0 0 1.338 0.457l0.031 -0.016 6.292 -3.227a1 1 0 0 0 0.434 -1.345z"/>
|
||||
<path d="M9.847 17.468l-3.76 -5.989a1 1 0 1 0 -1.694 1.063l3.229 5.143 -5.143 3.227a1 1 0 0 0 -0.34 1.373 1 1 0 0 0 1.373 0.34c0.011 -0.006 0.02 -0.013 0.03 -0.02l5.99 -3.758a1 1 0 0 0 0.315 -1.379zm5.849 1.339l-3.76 -5.99a1 1 0 1 0 -1.694 1.063l3.229 5.143 -5.143 3.227a1 1 0 0 0 -0.34 1.373 1 1 0 0 0 1.373 0.34l0.03 -0.019 5.99 -3.76a1 1 0 0 0 0.315 -1.377z"/>
|
||||
</svg>
|
||||
<svg x="108">
|
||||
<path d="M9.93 18.993l-2.61 -6.572a1 1 0 1 0 -1.859 0.738l2.24 5.642 -5.642 2.241a1 1 0 0 0 -0.583 1.288 1 1 0 0 0 1.288 0.584l0.033 -0.013 6.572 -2.61a1 1 0 0 0 0.56 -1.298zm5.508 2.377l-2.61 -6.572a1 1 0 1 0 -1.859 0.738l2.242 5.643 -5.643 2.24a1 1 0 0 0 -0.583 1.289 1 1 0 0 0 1.288 0.583l0.033 -0.013 6.572 -2.61a1 1 0 0 0 0.56 -1.298z"/>
|
||||
<path d="M9.89 17.544l-3.227 -6.292a1 1 0 1 0 -1.78 0.912l2.771 5.403 -5.402 2.77a1 1 0 0 0 -0.458 1.338 1 1 0 0 0 1.339 0.457l0.031 -0.016 6.292 -3.226a1 1 0 0 0 0.434 -1.346zm5.71 1.84l-3.226 -6.293a1 1 0 1 0 -1.78 0.912l2.771 5.403 -5.402 2.77a1 1 0 0 0 -0.457 1.338 1 1 0 0 0 1.338 0.458l0.031 -0.016 6.292 -3.227a1 1 0 0 0 0.434 -1.346z"/>
|
||||
</svg>
|
||||
<svg x="126">
|
||||
<path d="M9.962 19.434l-1.92 -6.805a1 1 0 1 0 -1.925 0.543l1.65 5.843 -5.844 1.649a1 1 0 0 0 -0.712 1.222 1 1 0 0 0 1.221 0.712c0.012 -0.002 0.023 -0.006 0.034 -0.01l6.806 -1.92a1 1 0 0 0 0.69 -1.234zm5.236 2.93l-1.92 -6.804a1 1 0 1 0 -1.925 0.543l1.649 5.843 -5.843 1.649a1 1 0 0 0 -0.713 1.221 1 1 0 0 0 1.222 0.713l0.034 -0.01 6.805 -1.92a1 1 0 0 0 0.69 -1.234z"/>
|
||||
<path d="M9.93 17.631l-2.61 -6.572a1 1 0 1 0 -1.859 0.738l2.24 5.643 -5.642 2.24a1 1 0 0 0 -0.583 1.289 1 1 0 0 0 1.288 0.583l0.033 -0.013 6.572 -2.61a1 1 0 0 0 0.56 -1.298zm5.508 2.377l-2.61 -6.572a1 1 0 1 0 -1.859 0.738l2.242 5.643 -5.643 2.24a1 1 0 0 0 -0.583 1.29 1 1 0 0 0 1.288 0.582c0.012 -0.003 0.023 -0.009 0.033 -0.013l6.572 -2.61a1 1 0 0 0 0.56 -1.298z"/>
|
||||
</svg>
|
||||
<svg x="144">
|
||||
<path d="M9.986 19.9l-1.176 -6.972a1 1 0 1 0 -1.972 0.333l1.01 5.986 -5.987 1.01a1 1 0 0 0 -0.84 1.137 1 1 0 0 0 1.138 0.84c0.012 -0.001 0.024 -0.004 0.035 -0.006l6.972 -1.175a1 1 0 0 0 0.82 -1.153zm4.889 3.478l-1.176 -6.972a1 1 0 1 0 -1.972 0.333l1.01 5.986 -5.987 1.01a1 1 0 0 0 -0.84 1.137 1 1 0 0 0 1.138 0.84c0.012 -0.001 0.024 -0.004 0.035 -0.006l6.972 -1.175a1 1 0 0 0 0.82 -1.153z"/>
|
||||
<path d="M9.962 17.728l-1.92 -6.805a1 1 0 1 0 -1.925 0.543l1.65 5.843 -5.844 1.65a1 1 0 0 0 -0.712 1.221 1 1 0 0 0 1.221 0.712c0.012 -0.002 0.023 -0.006 0.034 -0.01l6.806 -1.92a1 1 0 0 0 0.69 -1.234zm5.236 2.931l-1.92 -6.805a1 1 0 1 0 -1.925 0.543l1.649 5.843 -5.843 1.65a1 1 0 0 0 -0.713 1.22 1 1 0 0 0 1.222 0.713c0.012 -0.002 0.023 -0.006 0.034 -0.01l6.805 -1.92a1 1 0 0 0 0.69 -1.234z"/>
|
||||
</svg>
|
||||
<svg x="162">
|
||||
<path d="M9.998 20.382l-0.396 -7.06a1 1 0 1 0 -1.997 0.112l0.34 6.061 -6.061 0.34a1 1 0 0 0 -0.96 1.038 1 1 0 0 0 1.037 0.961l0.035 -0.002 7.06 -0.396a1 1 0 0 0 0.942 -1.054zm4.474 3.998l-0.396 -7.06a1 1 0 1 0 -1.997 0.112l0.34 6.062 -6.061 0.34a1 1 0 0 0 -0.961 1.037 1 1 0 0 0 1.037 0.961l0.036 -0.002 7.06 -0.396a1 1 0 0 0 0.942 -1.054z"/>
|
||||
<path d="M9.986 17.834l-1.176 -6.973a1 1 0 1 0 -1.972 0.333l1.01 5.986 -5.987 1.01a1 1 0 0 0 -0.84 1.138 1 1 0 0 0 1.138 0.84l0.035 -0.006 6.972 -1.176a1 1 0 0 0 0.82 -1.152zm4.889 3.478l-1.176 -6.973a1 1 0 1 0 -1.972 0.333l1.01 5.986 -5.987 1.01a1 1 0 0 0 -0.84 1.138 1 1 0 0 0 1.138 0.84l0.035 -0.006 6.972 -1.176a1 1 0 0 0 0.82 -1.152z"/>
|
||||
</svg>
|
||||
<svg x="180">
|
||||
<path d="M9.998 20.868l0.396 -7.06a1 1 0 1 0 -1.997 -0.112l-0.34 6.062 -6.061 -0.34a1 1 0 0 0 -1.07 0.924 1 1 0 0 0 0.923 1.07l0.035 0.003 7.06 0.396a1 1 0 0 0 1.054 -0.943zm3.999 4.474l0.396 -7.06a1 1 0 1 0 -1.997 -0.112l-0.34 6.062 -6.062 -0.34a1 1 0 0 0 -1.07 0.923 1 1 0 0 0 0.923 1.071 0.211 0.211 0 0 0 0.035 0.002l7.06 0.396a1 1 0 0 0 1.055 -0.942z"/>
|
||||
<path d="M9.998 17.944l-0.396 -7.06a1 1 0 1 0 -1.997 0.112l0.34 6.062 -6.061 0.34a1 1 0 0 0 -0.96 1.037 1 1 0 0 0 1.037 0.961l0.035 -0.002 7.06 -0.396a1 1 0 0 0 0.942 -1.054zm4.474 3.998l-0.396 -7.06a1 1 0 1 0 -1.997 0.112l0.34 6.062 -6.061 0.34a1 1 0 0 0 -0.961 1.038 1 1 0 0 0 1.037 0.96l0.036 -0.001 7.06 -0.396a1 1 0 0 0 0.942 -1.055z"/>
|
||||
</svg>
|
||||
<svg x="198">
|
||||
<path d="M9.986 21.35l1.176 -6.973a1 1 0 1 0 -1.972 -0.333l-1.01 5.987 -5.986 -1.01a1 1 0 0 0 -1.167 0.8 1 1 0 0 0 0.8 1.167l0.034 0.005 6.973 1.176a1 1 0 0 0 1.152 -0.82zm3.478 4.889l1.176 -6.973a1 1 0 1 0 -1.972 -0.333l-1.01 5.987 -5.986 -1.01a1 1 0 0 0 -1.167 0.8 1 1 0 0 0 0.8 1.167l0.034 0.006 6.973 1.175a1 1 0 0 0 1.152 -0.82z"/>
|
||||
<path d="M9.998 18.056l0.396 -7.06a1 1 0 1 0 -1.997 -0.112l-0.34 6.062 -6.061 -0.34a1 1 0 0 0 -1.07 0.923 1 1 0 0 0 0.923 1.071 0.211 0.211 0 0 0 0.035 0.002l7.06 0.396a1 1 0 0 0 1.054 -0.942zm3.999 4.474l0.396 -7.06a1 1 0 1 0 -1.997 -0.112l-0.34 6.061 -6.062 -0.34a1 1 0 0 0 -1.07 0.924 1 1 0 0 0 0.923 1.07l0.035 0.003 7.06 0.396a1 1 0 0 0 1.055 -0.942z"/>
|
||||
</svg>
|
||||
<svg x="216">
|
||||
<path d="M9.962 21.816l1.92 -6.805a1 1 0 1 0 -1.925 -0.543l-1.648 5.843 -5.843 -1.65a1 1 0 0 0 -1.246 0.67 1 1 0 0 0 0.67 1.245l0.033 0.01 6.805 1.92a1 1 0 0 0 1.234 -0.69zm2.931 5.235l1.92 -6.805a1 1 0 1 0 -1.925 -0.543l-1.648 5.843 -5.843 -1.649a1 1 0 0 0 -1.246 0.669 1 1 0 0 0 0.669 1.246l0.034 0.01 6.805 1.92a1 1 0 0 0 1.234 -0.69z"/>
|
||||
<path d="M9.986 18.166l1.176 -6.972a1 1 0 1 0 -1.972 -0.333l-1.01 5.987 -5.986 -1.01a1 1 0 0 0 -1.167 0.8 1 1 0 0 0 0.8 1.166c0.011 0.003 0.023 0.004 0.034 0.006l6.973 1.176a1 1 0 0 0 1.152 -0.82zm3.478 4.89l1.176 -6.973a1 1 0 1 0 -1.972 -0.333l-1.01 5.987 -5.986 -1.01a1 1 0 0 0 -1.167 0.8 1 1 0 0 0 0.8 1.166c0.011 0.003 0.023 0.004 0.034 0.006l6.973 1.176a1 1 0 0 0 1.152 -0.82z"/>
|
||||
</svg>
|
||||
<svg x="234">
|
||||
<path d="M9.93 22.257l2.609 -6.572a1 1 0 1 0 -1.859 -0.738l-2.24 5.643 -5.643 -2.24a1 1 0 0 0 -1.308 0.537 1 1 0 0 0 0.537 1.308l0.033 0.013 6.572 2.61a1 1 0 0 0 1.298 -0.56zm2.377 5.51l2.61 -6.573a1 1 0 1 0 -1.859 -0.738l-2.24 5.643 -5.644 -2.24a1 1 0 0 0 -1.308 0.537 1 1 0 0 0 0.538 1.308l0.032 0.013 6.572 2.61a1 1 0 0 0 1.299 -0.56z"/>
|
||||
<path d="M9.962 18.272l1.92 -6.806a1 1 0 1 0 -1.925 -0.543l-1.648 5.843 -5.843 -1.649a1 1 0 0 0 -1.246 0.669 1 1 0 0 0 0.67 1.246l0.033 0.01 6.805 1.92a1 1 0 0 0 1.234 -0.69zm2.931 5.235l1.92 -6.805a1 1 0 1 0 -1.925 -0.543l-1.648 5.843 -5.843 -1.65a1 1 0 0 0 -1.246 0.67 1 1 0 0 0 0.669 1.246l0.034 0.01 6.805 1.92a1 1 0 0 0 1.234 -0.69z"/>
|
||||
</svg>
|
||||
<svg x="252">
|
||||
<path d="M9.89 22.665l3.226 -6.292a1 1 0 1 0 -1.78 -0.912l-2.77 5.402 -5.402 -2.77a1 1 0 0 0 -1.353 0.41 1 1 0 0 0 0.41 1.353l0.03 0.016 6.293 3.226a1 1 0 0 0 1.346 -0.433zm1.84 5.71l3.226 -6.291a1 1 0 1 0 -1.78 -0.912l-2.77 5.402 -5.402 -2.77a1 1 0 0 0 -1.354 0.41 1 1 0 0 0 0.41 1.353l0.031 0.016 6.292 3.226a1 1 0 0 0 1.346 -0.433z"/>
|
||||
<path d="M9.93 18.369l2.609 -6.572a1 1 0 1 0 -1.859 -0.738l-2.24 5.643 -5.643 -2.24a1 1 0 0 0 -1.308 0.536 1 1 0 0 0 0.537 1.309l0.033 0.013 6.572 2.61a1 1 0 0 0 1.298 -0.561zm2.377 5.509l2.61 -6.572a1 1 0 1 0 -1.859 -0.738l-2.24 5.643 -5.644 -2.241a1 1 0 0 0 -1.308 0.537 1 1 0 0 0 0.538 1.308c0.01 0.006 0.022 0.01 0.032 0.014l6.572 2.61a1 1 0 0 0 1.299 -0.561z"/>
|
||||
</svg>
|
||||
<svg x="270">
|
||||
<path d="M9.847 23.03l3.759 -5.99a1 1 0 1 0 -1.694 -1.063l-3.227 5.143 -5.143 -3.228a1 1 0 0 0 -1.384 0.291 1 1 0 0 0 0.291 1.384l0.03 0.02 5.99 3.758a1 1 0 0 0 1.378 -0.315zm1.338 5.849l3.759 -5.99a1 1 0 1 0 -1.694 -1.063l-3.227 5.143 -5.143 -3.228a1 1 0 0 0 -1.384 0.291 1 1 0 0 0 0.291 1.384l0.03 0.02 5.99 3.758a1 1 0 0 0 1.378 -0.315z"/>
|
||||
<path d="M9.89 18.456l3.226 -6.292a1 1 0 1 0 -1.78 -0.912l-2.77 5.402 -5.402 -2.77a1 1 0 0 0 -1.353 0.41 1 1 0 0 0 0.41 1.353l0.03 0.016 6.293 3.227a1 1 0 0 0 1.346 -0.434zm1.84 5.711l3.226 -6.292a1 1 0 1 0 -1.78 -0.912l-2.77 5.402 -5.402 -2.77a1 1 0 0 0 -1.354 0.41 1 1 0 0 0 0.41 1.353l0.031 0.016 6.292 3.227a1 1 0 0 0 1.346 -0.434z"/>
|
||||
</svg>
|
||||
<svg x="288">
|
||||
<path d="M9.804 23.345l4.2 -5.689a1 1 0 1 0 -1.609 -1.188l-3.605 4.884 -4.885 -3.606a1 1 0 0 0 -1.402 0.186 1 1 0 0 0 0.186 1.402l0.029 0.02 5.688 4.201a1 1 0 0 0 1.398 -0.21zm0.893 5.933l4.2 -5.689a1 1 0 1 0 -1.609 -1.188l-3.605 4.885 -4.885 -3.607a1 1 0 0 0 -1.402 0.186 1 1 0 0 0 0.186 1.402l0.029 0.021 5.688 4.2a1 1 0 0 0 1.398 -0.21z"/>
|
||||
<path d="M9.847 18.532l3.759 -5.99a1 1 0 1 0 -1.694 -1.063l-3.227 5.143 -5.143 -3.228a1 1 0 0 0 -1.384 0.291 1 1 0 0 0 0.291 1.384l0.03 0.019 5.99 3.759a1 1 0 0 0 1.378 -0.315zm1.338 5.848l3.759 -5.989a1 1 0 1 0 -1.694 -1.063l-3.227 5.143 -5.143 -3.228a1 1 0 0 0 -1.384 0.291 1 1 0 0 0 0.291 1.384l0.03 0.019 5.99 3.759a1 1 0 0 0 1.378 -0.316z"/>
|
||||
</svg>
|
||||
<svg x="306">
|
||||
<path d="M9.766 23.602l4.546 -5.416a1 1 0 1 0 -1.532 -1.286l-3.903 4.65 -4.65 -3.903a1 1 0 0 0 -1.411 0.098 1 1 0 0 0 0.098 1.41c0.009 0.01 0.018 0.016 0.027 0.024l5.416 4.546a1 1 0 0 0 1.409 -0.123zm0.522 5.977l4.546 -5.416a1 1 0 1 0 -1.532 -1.286l-3.903 4.65 -4.65 -3.903a1 1 0 0 0 -1.411 0.098 1 1 0 0 0 0.098 1.411l0.027 0.023 5.416 4.546a1 1 0 0 0 1.409 -0.123z"/>
|
||||
<path d="M9.804 18.594l4.2 -5.689a1 1 0 1 0 -1.609 -1.188l-3.605 4.885 -4.885 -3.606a1 1 0 0 0 -1.402 0.185 1 1 0 0 0 0.186 1.402l0.029 0.021 5.688 4.2a1 1 0 0 0 1.398 -0.21zm0.893 5.933l4.2 -5.688a1 1 0 1 0 -1.609 -1.188l-3.605 4.884 -4.885 -3.606a1 1 0 0 0 -1.402 0.185 1 1 0 0 0 0.186 1.402l0.029 0.021 5.688 4.2a1 1 0 0 0 1.398 -0.21z"/>
|
||||
</svg>
|
||||
<svg x="324">
|
||||
<path d="M9.735 23.794l4.795 -5.196a1 1 0 1 0 -1.47 -1.356l-4.117 4.461 -4.461 -4.117a1 1 0 0 0 -1.414 0.031 1 1 0 0 0 0.032 1.414 0.195 0.195 0 0 0 0.026 0.024l5.196 4.796a1 1 0 0 0 1.413 -0.057zm0.24 5.995l4.796 -5.196a1 1 0 1 0 -1.47 -1.356l-4.117 4.461 -4.462 -4.117a1 1 0 0 0 -1.414 0.032 1 1 0 0 0 0.032 1.413c0.008 0.01 0.018 0.017 0.026 0.024l5.196 4.796a1 1 0 0 0 1.413 -0.057z"/>
|
||||
<path d="M9.766 18.643l4.546 -5.416a1 1 0 1 0 -1.532 -1.286l-3.903 4.65 -4.65 -3.903a1 1 0 0 0 -1.411 0.098 1 1 0 0 0 0.098 1.411l0.027 0.023 5.416 4.546a1 1 0 0 0 1.409 -0.123zm0.522 5.977l4.546 -5.416a1 1 0 1 0 -1.532 -1.286l-3.903 4.65 -4.65 -3.903a1 1 0 0 0 -1.411 0.099 1 1 0 0 0 0.098 1.41 0.276 0.276 0 0 0 0.027 0.023l5.416 4.546a1 1 0 0 0 1.409 -0.123z"/>
|
||||
</svg>
|
||||
<svg x="342">
|
||||
<path d="M9.714 23.915l4.948 -5.052a1 1 0 1 0 -1.429 -1.4l-4.248 4.338 -4.337 -4.248a1 1 0 0 0 -1.414 -0.01 1 1 0 0 0 -0.01 1.414l0.025 0.025 5.051 4.948a1 1 0 0 0 1.414 -0.015zm0.062 6l4.948 -5.052a1 1 0 1 0 -1.429 -1.4l-4.247 4.338 -4.338 -4.248a1 1 0 0 0 -1.414 -0.01 1 1 0 0 0 -0.01 1.414l0.025 0.024 5.052 4.948a1 1 0 0 0 1.413 -0.014z"/>
|
||||
<path d="M9.735 18.678l4.795 -5.196a1 1 0 1 0 -1.47 -1.356l-4.117 4.461 -4.461 -4.117a1 1 0 0 0 -1.414 0.031 1 1 0 0 0 0.032 1.414c0.008 0.009 0.017 0.016 0.026 0.024l5.196 4.796a1 1 0 0 0 1.413 -0.057zm0.24 5.995l4.796 -5.196a1 1 0 1 0 -1.47 -1.356l-4.117 4.461 -4.462 -4.117a1 1 0 0 0 -1.414 0.031 1 1 0 0 0 0.032 1.414c0.008 0.009 0.018 0.017 0.026 0.024l5.196 4.796a1 1 0 0 0 1.413 -0.057z"/>
|
||||
</svg>
|
||||
<svg x="360">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.714 18.7l4.948 -5.052a1 1 0 1 0 -1.429 -1.4l-4.248 4.338 -4.337 -4.248a1 1 0 0 0 -1.414 -0.01 1 1 0 0 0 -0.01 1.414l0.025 0.024 5.051 4.948a1 1 0 0 0 1.414 -0.014zm0.062 6l4.948 -5.052a1 1 0 1 0 -1.429 -1.4l-4.247 4.338 -4.338 -4.249a1 1 0 0 0 -1.414 -0.01 1 1 0 0 0 -0.01 1.414c0.008 0.01 0.017 0.017 0.025 0.025l5.052 4.948a1 1 0 0 0 1.413 -0.015z"/>
|
||||
</svg>
|
||||
<svg x="378">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="396">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.793l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="414">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 19.02l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="432">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 19.34l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="450">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 19.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="468">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 20.074l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="486">
|
||||
<path d="M9.722 23.957l5.103 -5a0.985 0.985 0 0 0 -0.026 -1.414 1.036 1.036 0 0 0 -1.418 0l-4.381 4.293 -4.381 -4.293a1.036 1.036 0 0 0 -1.444 -0.025 0.987 0.987 0 0 0 -0.025 1.414l0.025 0.025 5.103 5a1.036 1.036 0 0 0 1.444 0zm0 6l5.103 -5a0.985 0.985 0 0 0 -0.026 -1.414 1.036 1.036 0 0 0 -1.418 0l-4.381 4.293 -4.381 -4.293a1.036 1.036 0 0 0 -1.444 -0.025 0.987 0.987 0 0 0 -0.025 1.414l0.025 0.025 5.103 5a1.036 1.036 0 0 0 1.444 0z"/>
|
||||
<path d="M9.707 20.394l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414c0.008 0.01 0.017 0.017 0.025 0.025l5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414c0.008 0.01 0.017 0.017 0.025 0.025l5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="504">
|
||||
<path d="M9.738 23.957l5.217 -5a0.97 0.97 0 0 0 -0.026 -1.414 1.076 1.076 0 0 0 -1.45 0l-4.479 4.293 -4.48 -4.293a1.077 1.077 0 0 0 -1.475 -0.025 0.972 0.972 0 0 0 -0.026 1.414l0.026 0.025 5.217 5a1.077 1.077 0 0 0 1.476 0zm0 6l5.217 -5a0.97 0.97 0 0 0 -0.026 -1.414 1.076 1.076 0 0 0 -1.45 0l-4.479 4.293 -4.48 -4.293a1.077 1.077 0 0 0 -1.475 -0.025 0.972 0.972 0 0 0 -0.026 1.414l0.026 0.025 5.217 5a1.077 1.077 0 0 0 1.476 0z"/>
|
||||
<path d="M9.722 20.621l5.103 -5a0.985 0.985 0 0 0 -0.026 -1.414 1.036 1.036 0 0 0 -1.418 0l-4.381 4.293 -4.381 -4.293a1.036 1.036 0 0 0 -1.444 -0.025 0.987 0.987 0 0 0 -0.025 1.414l0.025 0.025 5.103 5a1.036 1.036 0 0 0 1.444 0zm0 6l5.103 -5a0.985 0.985 0 0 0 -0.026 -1.414 1.036 1.036 0 0 0 -1.418 0l-4.381 4.293 -4.381 -4.293a1.036 1.036 0 0 0 -1.444 -0.025 0.987 0.987 0 0 0 -0.025 1.414l0.025 0.025 5.103 5a1.036 1.036 0 0 0 1.444 0z"/>
|
||||
</svg>
|
||||
<svg x="522">
|
||||
<path d="M9.755 24.235l5.34 -5c0.41 -0.397 0.398 -1.03 -0.027 -1.414 -0.413 -0.374 -1.069 -0.374 -1.483 0l-4.585 4.293 -4.585 -4.293c-0.41 -0.397 -1.086 -0.408 -1.51 -0.025 -0.424 0.384 -0.435 1.017 -0.026 1.414 0.008 0.01 0.018 0.017 0.026 0.025l5.34 5c0.418 0.39 1.092 0.39 1.51 0zm0 6l5.34 -5c0.41 -0.397 0.398 -1.03 -0.027 -1.414 -0.413 -0.374 -1.069 -0.374 -1.483 0l-4.585 4.293 -4.585 -4.293c-0.41 -0.397 -1.086 -0.408 -1.51 -0.025 -0.424 0.384 -0.435 1.017 -0.026 1.414 0.008 0.01 0.018 0.017 0.026 0.025l5.34 5c0.418 0.39 1.092 0.39 1.51 0z"/>
|
||||
<path d="M9.738 20.707l5.217 -5a0.97 0.97 0 0 0 -0.026 -1.414 1.076 1.076 0 0 0 -1.45 0l-4.479 4.293 -4.48 -4.293a1.077 1.077 0 0 0 -1.475 -0.025 0.972 0.972 0 0 0 -0.026 1.414l0.026 0.025 5.217 5a1.077 1.077 0 0 0 1.476 0zm0 6l5.217 -5a0.97 0.97 0 0 0 -0.026 -1.414 1.076 1.076 0 0 0 -1.45 0l-4.479 4.293 -4.48 -4.293a1.077 1.077 0 0 0 -1.475 -0.025 0.972 0.972 0 0 0 -0.026 1.414l0.026 0.025 5.217 5a1.077 1.077 0 0 0 1.476 0z"/>
|
||||
</svg>
|
||||
<svg x="540">
|
||||
<path d="M9.773 24.93l5.466 -5c0.42 -0.397 0.408 -1.03 -0.027 -1.414 -0.423 -0.374 -1.094 -0.374 -1.518 0l-4.694 4.293 -4.694 -4.293c-0.42 -0.397 -1.111 -0.408 -1.545 -0.025 -0.434 0.384 -0.447 1.017 -0.028 1.414l0.028 0.025 5.466 5c0.428 0.39 1.118 0.39 1.546 0zm0 6l5.466 -5c0.42 -0.397 0.408 -1.03 -0.027 -1.414 -0.423 -0.374 -1.094 -0.374 -1.518 0l-4.694 4.293 -4.694 -4.293c-0.42 -0.397 -1.111 -0.408 -1.545 -0.025 -0.434 0.384 -0.447 1.017 -0.028 1.414l0.028 0.025 5.466 5c0.428 0.39 1.118 0.39 1.546 0z"/>
|
||||
<path d="M9.755 20.855l5.34 -5c0.41 -0.397 0.398 -1.03 -0.027 -1.414 -0.413 -0.374 -1.069 -0.374 -1.483 0l-4.585 4.293 -4.585 -4.293c-0.41 -0.397 -1.086 -0.408 -1.51 -0.025 -0.424 0.384 -0.435 1.017 -0.026 1.414 0.008 0.01 0.018 0.017 0.026 0.025l5.34 5c0.418 0.39 1.092 0.39 1.51 0zm0 6l5.34 -5c0.41 -0.397 0.398 -1.03 -0.027 -1.414 -0.413 -0.374 -1.069 -0.374 -1.483 0l-4.585 4.293 -4.585 -4.293c-0.41 -0.397 -1.086 -0.408 -1.51 -0.025 -0.424 0.384 -0.435 1.017 -0.026 1.414 0.008 0.01 0.018 0.017 0.026 0.025l5.34 5c0.418 0.39 1.092 0.39 1.51 0z"/>
|
||||
</svg>
|
||||
<svg x="558">
|
||||
<path d="M9.791 25.832l5.595 -5c0.43 -0.397 0.417 -1.03 -0.028 -1.414 -0.433 -0.374 -1.12 -0.374 -1.555 0l-4.803 4.293 -4.803 -4.293c-0.43 -0.397 -1.138 -0.408 -1.583 -0.025 -0.444 0.384 -0.456 1.017 -0.027 1.414 0.008 0.009 0.019 0.017 0.027 0.025l5.595 5c0.437 0.39 1.145 0.39 1.582 0zm0 6l5.595 -5c0.43 -0.397 0.417 -1.03 -0.028 -1.414 -0.433 -0.374 -1.12 -0.374 -1.555 0l-4.803 4.293 -4.803 -4.293c-0.43 -0.397 -1.138 -0.408 -1.583 -0.025 -0.444 0.384 -0.456 1.017 -0.027 1.414 0.008 0.009 0.019 0.017 0.027 0.025l5.595 5c0.437 0.39 1.145 0.39 1.582 0z"/>
|
||||
<path d="M9.773 21.226l5.466 -5c0.42 -0.397 0.408 -1.03 -0.027 -1.414 -0.423 -0.374 -1.094 -0.374 -1.518 0l-4.694 4.293 -4.694 -4.293c-0.42 -0.397 -1.111 -0.408 -1.545 -0.025 -0.434 0.384 -0.447 1.017 -0.028 1.414l0.028 0.025 5.466 5c0.428 0.39 1.118 0.39 1.546 0zm0 6l5.466 -5c0.42 -0.397 0.408 -1.03 -0.027 -1.414 -0.423 -0.374 -1.094 -0.374 -1.518 0l-4.694 4.293 -4.694 -4.293c-0.42 -0.397 -1.111 -0.408 -1.545 -0.025 -0.434 0.384 -0.447 1.017 -0.028 1.414l0.028 0.025 5.466 5c0.428 0.39 1.118 0.39 1.546 0z"/>
|
||||
</svg>
|
||||
<svg x="576">
|
||||
<path d="M9.809 26.734l5.72 -5c0.44 -0.397 0.427 -1.03 -0.029 -1.414 -0.442 -0.374 -1.145 -0.374 -1.589 0l-4.911 4.293 -4.911 -4.293c-0.44 -0.397 -1.164 -0.408 -1.618 -0.025 -0.454 0.384 -0.467 1.017 -0.029 1.414 0.01 0.01 0.02 0.017 0.029 0.025l5.72 5c0.447 0.39 1.17 0.39 1.618 0zm0 6l5.72 -5c0.44 -0.397 0.427 -1.03 -0.029 -1.414 -0.442 -0.374 -1.145 -0.374 -1.589 0l-4.911 4.293 -4.911 -4.293c-0.44 -0.397 -1.164 -0.408 -1.618 -0.025 -0.454 0.384 -0.467 1.017 -0.029 1.414 0.01 0.01 0.02 0.017 0.029 0.025l5.72 5c0.447 0.39 1.17 0.39 1.618 0z"/>
|
||||
<path d="M9.791 21.707l5.595 -5c0.43 -0.397 0.417 -1.03 -0.028 -1.414 -0.433 -0.374 -1.12 -0.374 -1.555 0l-4.803 4.293 -4.803 -4.293c-0.43 -0.397 -1.138 -0.408 -1.583 -0.025 -0.444 0.384 -0.456 1.017 -0.027 1.414 0.008 0.009 0.019 0.017 0.027 0.025l5.595 5c0.437 0.39 1.145 0.39 1.582 0zm0 6l5.595 -5c0.43 -0.397 0.417 -1.03 -0.028 -1.414 -0.433 -0.374 -1.12 -0.374 -1.555 0l-4.803 4.293 -4.803 -4.293c-0.43 -0.397 -1.138 -0.408 -1.583 -0.025 -0.444 0.384 -0.456 1.017 -0.027 1.414 0.008 0.009 0.019 0.017 0.027 0.025l5.595 5c0.437 0.39 1.145 0.39 1.582 0z"/>
|
||||
</svg>
|
||||
<svg x="594">
|
||||
<path d="M9.826 27.429l5.84 -5c0.449 -0.397 0.436 -1.03 -0.03 -1.414 -0.451 -0.374 -1.168 -0.374 -1.622 0l-5.014 4.293 -5.014 -4.293c-0.449 -0.397 -1.188 -0.408 -1.652 -0.025 -0.464 0.384 -0.477 1.017 -0.03 1.414l0.03 0.025 5.84 5c0.457 0.39 1.195 0.39 1.652 0zm0 6l5.84 -5c0.449 -0.397 0.436 -1.03 -0.03 -1.414 -0.451 -0.374 -1.168 -0.374 -1.622 0l-5.014 4.293 -5.014 -4.293c-0.449 -0.397 -1.188 -0.408 -1.652 -0.025 -0.464 0.384 -0.477 1.017 -0.03 1.414l0.03 0.025 5.84 5c0.457 0.39 1.195 0.39 1.652 0z"/>
|
||||
<path d="M9.809 22.188l5.72 -5c0.44 -0.397 0.427 -1.03 -0.029 -1.414 -0.442 -0.374 -1.145 -0.374 -1.589 0l-4.911 4.293 -4.911 -4.293c-0.44 -0.397 -1.164 -0.408 -1.618 -0.025 -0.454 0.384 -0.467 1.017 -0.029 1.414 0.01 0.01 0.02 0.017 0.029 0.025l5.72 5c0.447 0.39 1.17 0.39 1.618 0zm0 6l5.72 -5c0.44 -0.397 0.427 -1.03 -0.029 -1.414 -0.442 -0.374 -1.145 -0.374 -1.589 0l-4.911 4.293 -4.911 -4.293c-0.44 -0.397 -1.164 -0.408 -1.618 -0.025 -0.454 0.384 -0.467 1.017 -0.029 1.414 0.01 0.01 0.02 0.017 0.029 0.025l5.72 5c0.447 0.39 1.17 0.39 1.618 0z"/>
|
||||
</svg>
|
||||
<svg x="612">
|
||||
<path d="M9.841 27.707l5.952 -5c0.457 -0.397 0.444 -1.03 -0.03 -1.414 -0.46 -0.374 -1.192 -0.374 -1.653 0l-5.11 4.293 -5.11 -4.293c-0.457 -0.397 -1.21 -0.408 -1.683 -0.025 -0.472 0.384 -0.485 1.017 -0.03 1.414l0.03 0.025 5.952 5c0.465 0.39 1.217 0.39 1.682 0zm0 6l5.952 -5c0.457 -0.397 0.444 -1.03 -0.03 -1.414 -0.46 -0.374 -1.192 -0.374 -1.653 0l-5.11 4.293 -5.11 -4.293c-0.457 -0.397 -1.21 -0.408 -1.683 -0.025 -0.472 0.384 -0.485 1.017 -0.03 1.414l0.03 0.025 5.952 5c0.465 0.39 1.217 0.39 1.682 0z"/>
|
||||
<path d="M9.826 22.559l5.84 -5c0.449 -0.397 0.436 -1.03 -0.03 -1.414 -0.451 -0.374 -1.168 -0.374 -1.622 0l-5.014 4.293 -5.014 -4.293c-0.449 -0.397 -1.188 -0.408 -1.652 -0.025 -0.464 0.384 -0.477 1.017 -0.03 1.414l0.03 0.025 5.84 5c0.457 0.39 1.195 0.39 1.652 0zm0 6l5.84 -5c0.449 -0.397 0.436 -1.03 -0.03 -1.414 -0.451 -0.374 -1.168 -0.374 -1.622 0l-5.014 4.293 -5.014 -4.293c-0.449 -0.397 -1.188 -0.408 -1.652 -0.025 -0.464 0.384 -0.477 1.017 -0.03 1.414l0.03 0.025 5.84 5c0.457 0.39 1.195 0.39 1.652 0z"/>
|
||||
</svg>
|
||||
<svg x="630">
|
||||
<path d="M9.855 27.317l6.05 -5c0.465 -0.397 0.451 -1.03 -0.03 -1.414 -0.469 -0.374 -1.211 -0.374 -1.68 0l-5.195 4.293 -5.194 -4.293c-0.465 -0.397 -1.23 -0.408 -1.711 -0.025 -0.48 0.384 -0.494 1.017 -0.03 1.414l0.03 0.025 6.05 5c0.473 0.39 1.237 0.39 1.71 0zm0 6l6.05 -5c0.465 -0.397 0.451 -1.03 -0.03 -1.414 -0.469 -0.374 -1.211 -0.374 -1.68 0l-5.195 4.293 -5.194 -4.293c-0.465 -0.397 -1.23 -0.408 -1.711 -0.025 -0.48 0.384 -0.494 1.017 -0.03 1.414l0.03 0.025 6.05 5c0.473 0.39 1.237 0.39 1.71 0z"/>
|
||||
<path d="M9.841 22.707l5.952 -5c0.457 -0.397 0.444 -1.03 -0.03 -1.414 -0.46 -0.374 -1.192 -0.374 -1.653 0l-5.11 4.293 -5.11 -4.293c-0.457 -0.397 -1.21 -0.408 -1.683 -0.025 -0.472 0.384 -0.485 1.017 -0.03 1.414l0.03 0.025 5.952 5c0.465 0.39 1.217 0.39 1.682 0zm0 6l5.952 -5c0.457 -0.397 0.444 -1.03 -0.03 -1.414 -0.46 -0.374 -1.192 -0.374 -1.653 0l-5.11 4.293 -5.11 -4.293c-0.457 -0.397 -1.21 -0.408 -1.683 -0.025 -0.472 0.384 -0.485 1.017 -0.03 1.414l0.03 0.025 5.952 5c0.465 0.39 1.217 0.39 1.682 0z"/>
|
||||
</svg>
|
||||
<svg x="648">
|
||||
<path d="M9.867 26.387l6.132 -5c0.471 -0.397 0.458 -1.03 -0.03 -1.414 -0.475 -0.374 -1.228 -0.374 -1.704 0l-5.265 4.293 -5.265 -4.293c-0.471 -0.397 -1.247 -0.408 -1.734 -0.025 -0.487 0.384 -0.5 1.017 -0.03 1.414 0.009 0.009 0.02 0.017 0.03 0.025l6.132 5c0.48 0.39 1.255 0.39 1.734 0zm0 6l6.132 -5c0.471 -0.397 0.458 -1.03 -0.03 -1.414 -0.475 -0.374 -1.228 -0.374 -1.704 0l-5.265 4.293 -5.265 -4.293c-0.471 -0.397 -1.247 -0.408 -1.734 -0.025 -0.487 0.384 -0.5 1.017 -0.03 1.414 0.009 0.009 0.02 0.017 0.03 0.025l6.132 5c0.48 0.39 1.255 0.39 1.734 0z"/>
|
||||
<path d="M9.855 22.29l6.05 -5c0.465 -0.396 0.451 -1.03 -0.03 -1.413 -0.469 -0.374 -1.211 -0.374 -1.68 0l-5.195 4.293 -5.194 -4.293c-0.465 -0.397 -1.23 -0.408 -1.711 -0.025 -0.48 0.384 -0.494 1.017 -0.03 1.414l0.03 0.025 6.05 5c0.473 0.39 1.237 0.39 1.71 0zm0 6l6.05 -5c0.465 -0.396 0.451 -1.03 -0.03 -1.413 -0.469 -0.374 -1.211 -0.374 -1.68 0l-5.195 4.293 -5.194 -4.293c-0.465 -0.397 -1.23 -0.408 -1.711 -0.025 -0.48 0.384 -0.494 1.017 -0.03 1.414l0.03 0.025 6.05 5c0.473 0.39 1.237 0.39 1.71 0z"/>
|
||||
</svg>
|
||||
<svg x="666">
|
||||
<path d="M9.876 25.277l6.195 -5c0.476 -0.397 0.462 -1.03 -0.03 -1.414 -0.48 -0.374 -1.241 -0.374 -1.722 0l-5.319 4.293 -5.32 -4.293c-0.475 -0.397 -1.26 -0.408 -1.751 -0.025 -0.492 0.384 -0.506 1.017 -0.031 1.414 0.01 0.01 0.02 0.017 0.03 0.025l6.196 5c0.484 0.39 1.268 0.39 1.752 0zm0 6l6.195 -5c0.476 -0.397 0.462 -1.03 -0.03 -1.414 -0.48 -0.374 -1.241 -0.374 -1.722 0l-5.319 4.293 -5.32 -4.293c-0.475 -0.397 -1.26 -0.408 -1.751 -0.025 -0.492 0.384 -0.506 1.017 -0.031 1.414 0.01 0.01 0.02 0.017 0.03 0.025l6.196 5c0.484 0.39 1.268 0.39 1.752 0z"/>
|
||||
<path d="M9.867 21.299l6.132 -5c0.471 -0.397 0.458 -1.03 -0.03 -1.414 -0.475 -0.374 -1.228 -0.374 -1.704 0l-5.265 4.293 -5.265 -4.293c-0.471 -0.397 -1.247 -0.408 -1.734 -0.025 -0.487 0.384 -0.5 1.017 -0.03 1.414 0.009 0.009 0.02 0.017 0.03 0.025l6.132 5c0.48 0.39 1.255 0.39 1.734 0zm0 6l6.132 -5c0.471 -0.397 0.458 -1.03 -0.03 -1.414 -0.475 -0.374 -1.228 -0.374 -1.704 0l-5.265 4.293 -5.265 -4.293c-0.471 -0.397 -1.247 -0.408 -1.734 -0.025 -0.487 0.384 -0.5 1.017 -0.03 1.414 0.009 0.009 0.02 0.017 0.03 0.025l6.132 5c0.48 0.39 1.255 0.39 1.734 0z"/>
|
||||
</svg>
|
||||
<svg x="684">
|
||||
<path d="M9.882 24.347l6.235 -5c0.48 -0.397 0.466 -1.03 -0.03 -1.414 -0.483 -0.374 -1.25 -0.374 -1.733 0l-5.354 4.293 -5.354 -4.293c-0.479 -0.397 -1.268 -0.408 -1.763 -0.025 -0.496 0.384 -0.51 1.017 -0.032 1.414 0.01 0.01 0.022 0.017 0.032 0.025l6.235 5c0.488 0.39 1.276 0.39 1.764 0zm0 6l6.235 -5c0.48 -0.397 0.466 -1.03 -0.03 -1.414 -0.483 -0.374 -1.25 -0.374 -1.733 0l-5.354 4.293 -5.354 -4.293c-0.479 -0.397 -1.268 -0.408 -1.763 -0.025 -0.496 0.384 -0.51 1.017 -0.032 1.414 0.01 0.01 0.022 0.017 0.032 0.025l6.235 5c0.488 0.39 1.276 0.39 1.764 0z"/>
|
||||
<path d="M9.876 20.115l6.195 -5c0.476 -0.397 0.462 -1.03 -0.03 -1.414 -0.48 -0.374 -1.241 -0.374 -1.722 0l-5.319 4.293 -5.32 -4.293c-0.475 -0.397 -1.26 -0.408 -1.751 -0.025 -0.492 0.384 -0.506 1.017 -0.031 1.414 0.01 0.01 0.02 0.017 0.03 0.025l6.196 5c0.484 0.39 1.268 0.39 1.752 0zm0 6l6.195 -5c0.476 -0.397 0.462 -1.03 -0.03 -1.414 -0.48 -0.374 -1.241 -0.374 -1.722 0l-5.319 4.293 -5.32 -4.293c-0.475 -0.397 -1.26 -0.408 -1.751 -0.025 -0.492 0.384 -0.506 1.017 -0.031 1.414 0.01 0.01 0.02 0.017 0.03 0.025l6.196 5c0.484 0.39 1.268 0.39 1.752 0z"/>
|
||||
</svg>
|
||||
<svg x="702">
|
||||
<path d="M9.884 23.957l6.25 -5c0.48 -0.397 0.466 -1.03 -0.032 -1.414 -0.483 -0.374 -1.25 -0.374 -1.736 0l-5.366 4.293 -5.366 -4.293c-0.48 -0.397 -1.272 -0.408 -1.768 -0.025 -0.496 0.384 -0.51 1.017 -0.031 1.414l0.031 0.025 6.25 5c0.489 0.39 1.279 0.39 1.768 0zm0 6l6.25 -5c0.48 -0.397 0.466 -1.03 -0.032 -1.414 -0.483 -0.374 -1.25 -0.374 -1.736 0l-5.366 4.293 -5.366 -4.293c-0.48 -0.397 -1.272 -0.408 -1.768 -0.025 -0.496 0.384 -0.51 1.017 -0.031 1.414l0.031 0.025 6.25 5c0.489 0.39 1.279 0.39 1.768 0z"/>
|
||||
<path d="M9.882 19.123l6.235 -5c0.48 -0.397 0.466 -1.03 -0.03 -1.414 -0.483 -0.374 -1.25 -0.374 -1.733 0l-5.354 4.293 -5.354 -4.293c-0.479 -0.397 -1.268 -0.408 -1.763 -0.025 -0.496 0.384 -0.51 1.017 -0.032 1.414 0.01 0.01 0.022 0.017 0.032 0.025l6.235 5c0.488 0.39 1.276 0.39 1.764 0zm0 6l6.235 -5c0.48 -0.397 0.466 -1.03 -0.03 -1.414 -0.483 -0.374 -1.25 -0.374 -1.733 0l-5.354 4.293 -5.354 -4.293c-0.479 -0.397 -1.268 -0.408 -1.763 -0.025 -0.496 0.384 -0.51 1.017 -0.032 1.414 0.01 0.01 0.022 0.017 0.032 0.025l6.235 5c0.488 0.39 1.276 0.39 1.764 0z"/>
|
||||
</svg>
|
||||
<svg x="720">
|
||||
<path d="M9.862 23.957l6.098 -5c0.468 -0.397 0.454 -1.03 -0.03 -1.414 -0.473 -0.374 -1.222 -0.374 -1.695 0l-5.235 4.293 -5.235 -4.293c-0.468 -0.397 -1.24 -0.408 -1.725 -0.025 -0.484 0.384 -0.497 1.017 -0.03 1.414l0.03 0.025 6.098 5c0.477 0.39 1.247 0.39 1.724 0zm0 6l6.098 -5c0.468 -0.397 0.454 -1.03 -0.03 -1.414 -0.473 -0.374 -1.222 -0.374 -1.695 0l-5.235 4.293 -5.235 -4.293c-0.468 -0.397 -1.24 -0.408 -1.725 -0.025 -0.484 0.384 -0.497 1.017 -0.03 1.414l0.03 0.025 6.098 5c0.477 0.39 1.247 0.39 1.724 0z"/>
|
||||
<path d="M9.884 18.707l6.25 -5c0.48 -0.397 0.466 -1.03 -0.032 -1.414 -0.483 -0.374 -1.25 -0.374 -1.736 0l-5.366 4.293 -5.366 -4.293c-0.48 -0.397 -1.272 -0.408 -1.768 -0.025 -0.496 0.384 -0.51 1.017 -0.031 1.414l0.031 0.025 6.25 5c0.489 0.39 1.279 0.39 1.768 0zm0 6l6.25 -5c0.48 -0.397 0.466 -1.03 -0.032 -1.414 -0.483 -0.374 -1.25 -0.374 -1.736 0l-5.366 4.293 -5.366 -4.293c-0.48 -0.397 -1.272 -0.408 -1.768 -0.025 -0.496 0.384 -0.51 1.017 -0.031 1.414l0.031 0.025 6.25 5c0.489 0.39 1.279 0.39 1.768 0z"/>
|
||||
</svg>
|
||||
<svg x="738">
|
||||
<path d="M9.838 23.957l5.924 -5c0.455 -0.397 0.442 -1.03 -0.03 -1.414 -0.458 -0.374 -1.186 -0.374 -1.645 0l-5.087 4.293 -5.087 -4.293c-0.455 -0.397 -1.205 -0.408 -1.675 -0.025 -0.47 0.384 -0.483 1.017 -0.03 1.414l0.03 0.025 5.924 5c0.464 0.39 1.212 0.39 1.676 0zm0 6l5.924 -5c0.455 -0.397 0.442 -1.03 -0.03 -1.414 -0.458 -0.374 -1.186 -0.374 -1.645 0l-5.087 4.293 -5.087 -4.293c-0.455 -0.397 -1.205 -0.408 -1.675 -0.025 -0.47 0.384 -0.483 1.017 -0.03 1.414l0.03 0.025 5.924 5c0.464 0.39 1.212 0.39 1.676 0z"/>
|
||||
<path d="M9.862 18.707l6.098 -5c0.468 -0.397 0.454 -1.03 -0.03 -1.414 -0.473 -0.374 -1.222 -0.374 -1.695 0l-5.235 4.293 -5.235 -4.293c-0.468 -0.397 -1.24 -0.408 -1.725 -0.025 -0.484 0.384 -0.497 1.017 -0.03 1.414l0.03 0.025 6.098 5c0.477 0.39 1.247 0.39 1.724 0zm0 6l6.098 -5c0.468 -0.397 0.454 -1.03 -0.03 -1.414 -0.473 -0.374 -1.222 -0.374 -1.695 0l-5.235 4.293 -5.235 -4.293c-0.468 -0.397 -1.24 -0.408 -1.725 -0.025 -0.484 0.384 -0.497 1.017 -0.03 1.414l0.03 0.025 6.098 5c0.477 0.39 1.247 0.39 1.724 0z"/>
|
||||
</svg>
|
||||
<svg x="756">
|
||||
<path d="M9.812 23.957l5.74 -5c0.441 -0.397 0.429 -1.03 -0.028 -1.414 -0.444 -0.374 -1.15 -0.374 -1.595 0l-4.929 4.293 -4.93 -4.293c-0.44 -0.397 -1.167 -0.408 -1.623 -0.025 -0.455 0.384 -0.468 1.017 -0.028 1.414l0.028 0.025 5.741 5c0.45 0.39 1.175 0.39 1.624 0zm0 6l5.74 -5c0.441 -0.397 0.429 -1.03 -0.028 -1.414 -0.444 -0.374 -1.15 -0.374 -1.595 0l-4.929 4.293 -4.93 -4.293c-0.44 -0.397 -1.167 -0.408 -1.623 -0.025 -0.455 0.384 -0.468 1.017 -0.028 1.414l0.028 0.025 5.741 5c0.45 0.39 1.175 0.39 1.624 0z"/>
|
||||
<path d="M9.838 18.707l5.924 -5c0.455 -0.397 0.442 -1.03 -0.03 -1.414 -0.458 -0.374 -1.186 -0.374 -1.645 0l-5.087 4.293 -5.087 -4.293c-0.455 -0.397 -1.205 -0.408 -1.675 -0.025 -0.47 0.384 -0.483 1.017 -0.03 1.414l0.03 0.025 5.924 5c0.464 0.39 1.212 0.39 1.676 0zm0 6l5.924 -5c0.455 -0.397 0.442 -1.03 -0.03 -1.414 -0.458 -0.374 -1.186 -0.374 -1.645 0l-5.087 4.293 -5.087 -4.293c-0.455 -0.397 -1.205 -0.408 -1.675 -0.025 -0.47 0.384 -0.483 1.017 -0.03 1.414l0.03 0.025 5.924 5c0.464 0.39 1.212 0.39 1.676 0z"/>
|
||||
</svg>
|
||||
<svg x="774">
|
||||
<path d="M9.786 23.957l5.557 -5c0.427 -0.397 0.415 -1.03 -0.028 -1.414 -0.43 -0.374 -1.112 -0.374 -1.543 0l-4.772 4.293 -4.772 -4.293c-0.426 -0.397 -1.13 -0.408 -1.571 -0.025 -0.441 0.384 -0.454 1.017 -0.028 1.414l0.028 0.025 5.557 5c0.435 0.39 1.137 0.39 1.572 0zm0 6l5.557 -5c0.427 -0.397 0.415 -1.03 -0.028 -1.414 -0.43 -0.374 -1.112 -0.374 -1.543 0l-4.772 4.293 -4.772 -4.293c-0.426 -0.397 -1.13 -0.408 -1.571 -0.025 -0.441 0.384 -0.454 1.017 -0.028 1.414l0.028 0.025 5.557 5c0.435 0.39 1.137 0.39 1.572 0z"/>
|
||||
<path d="M9.812 18.707l5.74 -5c0.441 -0.397 0.429 -1.03 -0.028 -1.414 -0.444 -0.374 -1.15 -0.374 -1.595 0l-4.929 4.293 -4.93 -4.293c-0.44 -0.397 -1.167 -0.408 -1.623 -0.025 -0.455 0.384 -0.468 1.017 -0.028 1.414l0.028 0.025 5.741 5c0.45 0.39 1.175 0.39 1.624 0zm0 6l5.74 -5c0.441 -0.397 0.429 -1.03 -0.028 -1.414 -0.444 -0.374 -1.15 -0.374 -1.595 0l-4.929 4.293 -4.93 -4.293c-0.44 -0.397 -1.167 -0.408 -1.623 -0.025 -0.455 0.384 -0.468 1.017 -0.028 1.414l0.028 0.025 5.741 5c0.45 0.39 1.175 0.39 1.624 0z"/>
|
||||
</svg>
|
||||
<svg x="792">
|
||||
<path d="M9.761 23.957l5.385 -5c0.413 -0.397 0.401 -1.03 -0.027 -1.414 -0.417 -0.374 -1.078 -0.374 -1.496 0l-4.623 4.293 -4.623 -4.293c-0.413 -0.397 -1.095 -0.408 -1.523 -0.025 -0.427 0.384 -0.439 1.017 -0.027 1.414l0.027 0.025 5.385 5c0.42 0.39 1.101 0.39 1.522 0zm0 6l5.385 -5c0.413 -0.397 0.401 -1.03 -0.027 -1.414 -0.417 -0.374 -1.078 -0.374 -1.496 0l-4.623 4.293 -4.623 -4.293c-0.413 -0.397 -1.095 -0.408 -1.523 -0.025 -0.427 0.384 -0.439 1.017 -0.027 1.414l0.027 0.025 5.385 5c0.42 0.39 1.101 0.39 1.522 0z"/>
|
||||
<path d="M9.786 18.707l5.557 -5c0.427 -0.397 0.415 -1.03 -0.028 -1.414 -0.43 -0.374 -1.112 -0.374 -1.543 0l-4.772 4.293 -4.772 -4.293c-0.426 -0.397 -1.13 -0.408 -1.571 -0.025 -0.441 0.384 -0.454 1.017 -0.028 1.414l0.028 0.025 5.557 5c0.435 0.39 1.137 0.39 1.572 0zm0 6l5.557 -5c0.427 -0.397 0.415 -1.03 -0.028 -1.414 -0.43 -0.374 -1.112 -0.374 -1.543 0l-4.772 4.293 -4.772 -4.293c-0.426 -0.397 -1.13 -0.408 -1.571 -0.025 -0.441 0.384 -0.454 1.017 -0.028 1.414l0.028 0.025 5.557 5c0.435 0.39 1.137 0.39 1.572 0z"/>
|
||||
</svg>
|
||||
<svg x="810">
|
||||
<path d="M9.74 23.957l5.231 -5a0.968 0.968 0 0 0 -0.026 -1.414 1.082 1.082 0 0 0 -1.453 0l-4.492 4.293 -4.492 -4.293a1.082 1.082 0 0 0 -1.48 -0.025 0.97 0.97 0 0 0 -0.026 1.414l0.027 0.025 5.231 5a1.082 1.082 0 0 0 1.48 0zm0 6l5.231 -5a0.968 0.968 0 0 0 -0.026 -1.414 1.082 1.082 0 0 0 -1.453 0l-4.492 4.293 -4.492 -4.293a1.082 1.082 0 0 0 -1.48 -0.025 0.97 0.97 0 0 0 -0.026 1.414l0.027 0.025 5.231 5a1.082 1.082 0 0 0 1.48 0z"/>
|
||||
<path d="M9.761 18.707l5.385 -5c0.413 -0.397 0.401 -1.03 -0.027 -1.414 -0.417 -0.374 -1.078 -0.374 -1.496 0l-4.623 4.293 -4.623 -4.293c-0.413 -0.397 -1.095 -0.408 -1.523 -0.025 -0.427 0.384 -0.439 1.017 -0.027 1.414l0.027 0.025 5.385 5c0.42 0.39 1.101 0.39 1.522 0zm0 6l5.385 -5c0.413 -0.397 0.401 -1.03 -0.027 -1.414 -0.417 -0.374 -1.078 -0.374 -1.496 0l-4.623 4.293 -4.623 -4.293c-0.413 -0.397 -1.095 -0.408 -1.523 -0.025 -0.427 0.384 -0.439 1.017 -0.027 1.414l0.027 0.025 5.385 5c0.42 0.39 1.101 0.39 1.522 0z"/>
|
||||
</svg>
|
||||
<svg x="828">
|
||||
<path d="M9.723 23.957l5.11 -5a0.984 0.984 0 0 0 -0.026 -1.414 1.038 1.038 0 0 0 -1.42 0l-4.387 4.293 -4.387 -4.293a1.039 1.039 0 0 0 -1.445 -0.025 0.986 0.986 0 0 0 -0.026 1.414l0.026 0.025 5.11 5a1.039 1.039 0 0 0 1.445 0zm0 6l5.11 -5a0.984 0.984 0 0 0 -0.026 -1.414 1.038 1.038 0 0 0 -1.42 0l-4.387 4.293 -4.387 -4.293a1.039 1.039 0 0 0 -1.445 -0.025 0.986 0.986 0 0 0 -0.026 1.414l0.026 0.025 5.11 5a1.039 1.039 0 0 0 1.445 0z"/>
|
||||
<path d="M9.74 18.707l5.231 -5a0.968 0.968 0 0 0 -0.026 -1.414 1.082 1.082 0 0 0 -1.453 0l-4.492 4.293 -4.492 -4.293a1.082 1.082 0 0 0 -1.48 -0.025 0.97 0.97 0 0 0 -0.026 1.414l0.027 0.025 5.231 5a1.082 1.082 0 0 0 1.48 0zm0 6l5.231 -5a0.968 0.968 0 0 0 -0.026 -1.414 1.082 1.082 0 0 0 -1.453 0l-4.492 4.293 -4.492 -4.293a1.082 1.082 0 0 0 -1.48 -0.025 0.97 0.97 0 0 0 -0.026 1.414l0.027 0.025 5.231 5a1.082 1.082 0 0 0 1.48 0z"/>
|
||||
</svg>
|
||||
<svg x="846">
|
||||
<path d="M9.711 23.957l5.03 -5a0.995 0.995 0 0 0 -0.026 -1.414 1.01 1.01 0 0 0 -1.397 0l-4.318 4.293 -4.318 -4.293a1.01 1.01 0 0 0 -1.422 -0.025 0.997 0.997 0 0 0 -0.025 1.414l0.025 0.025 5.029 5a1.01 1.01 0 0 0 1.422 0zm0 6l5.03 -5a0.995 0.995 0 0 0 -0.026 -1.414 1.01 1.01 0 0 0 -1.397 0l-4.318 4.293 -4.318 -4.293a1.01 1.01 0 0 0 -1.422 -0.025 0.997 0.997 0 0 0 -0.025 1.414l0.025 0.025 5.029 5a1.01 1.01 0 0 0 1.422 0z"/>
|
||||
<path d="M9.723 18.707l5.11 -5a0.984 0.984 0 0 0 -0.026 -1.414 1.038 1.038 0 0 0 -1.42 0l-4.387 4.293 -4.387 -4.293a1.039 1.039 0 0 0 -1.445 -0.025 0.986 0.986 0 0 0 -0.026 1.414l0.026 0.025 5.11 5a1.039 1.039 0 0 0 1.445 0zm0 6l5.11 -5a0.984 0.984 0 0 0 -0.026 -1.414 1.038 1.038 0 0 0 -1.42 0l-4.387 4.293 -4.387 -4.293a1.039 1.039 0 0 0 -1.445 -0.025 0.986 0.986 0 0 0 -0.026 1.414l0.026 0.025 5.11 5a1.039 1.039 0 0 0 1.445 0z"/>
|
||||
</svg>
|
||||
<svg x="864">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.711 18.707l5.03 -5a0.995 0.995 0 0 0 -0.026 -1.414 1.01 1.01 0 0 0 -1.397 0l-4.318 4.293 -4.318 -4.293a1.01 1.01 0 0 0 -1.422 -0.025 0.997 0.997 0 0 0 -0.025 1.414l0.025 0.025 5.029 5a1.01 1.01 0 0 0 1.422 0zm0 6l5.03 -5a0.995 0.995 0 0 0 -0.026 -1.414 1.01 1.01 0 0 0 -1.397 0l-4.318 4.293 -4.318 -4.293a1.01 1.01 0 0 0 -1.422 -0.025 0.997 0.997 0 0 0 -0.025 1.414l0.025 0.025 5.029 5a1.01 1.01 0 0 0 1.422 0z"/>
|
||||
</svg>
|
||||
<svg x="882">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="900">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="918">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="936">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="954">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="972">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="990">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1008">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1026">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1044">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1062">
|
||||
<path d="M9.707 23.957l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1080">
|
||||
<path d="M9.737 23.778l4.775 -5.215a1 1 0 1 0 -1.475 -1.35l-4.1 4.477 -4.477 -4.1a1 1 0 0 0 -1.414 0.038 1 1 0 0 0 0.037 1.413l0.027 0.024 5.215 4.775a1 1 0 0 0 1.412 -0.062zm0.265 5.994l4.775 -5.215a1 1 0 1 0 -1.475 -1.35l-4.1 4.477 -4.478 -4.1a1 1 0 0 0 -1.414 0.038 1 1 0 0 0 0.038 1.414l0.026 0.023 5.215 4.775a1 1 0 0 0 1.413 -0.062z"/>
|
||||
<path d="M9.707 18.707l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0zm0 6l5 -5a1 1 0 1 0 -1.414 -1.414l-4.293 4.293 -4.293 -4.293a1 1 0 0 0 -1.414 -0.025 1 1 0 0 0 -0.025 1.414l0.025 0.025 5 5a1 1 0 0 0 1.414 0z"/>
|
||||
</svg>
|
||||
<svg x="1098">
|
||||
<path d="M9.813 23.286l4.12 -5.747a1 1 0 1 0 -1.625 -1.165l-3.538 4.934 -4.935 -3.537a1 1 0 0 0 -1.399 0.206 1 1 0 0 0 0.206 1.4c0.009 0.007 0.02 0.013 0.028 0.02l5.748 4.12a1 1 0 0 0 1.395 -0.231zm0.976 5.92l4.12 -5.747a1 1 0 1 0 -1.625 -1.165l-3.537 4.934 -4.935 -3.537a1 1 0 0 0 -1.4 0.206 1 1 0 0 0 0.206 1.4l0.029 0.02 5.747 4.12a1 1 0 0 0 1.395 -0.231z"/>
|
||||
<path d="M9.737 18.675l4.775 -5.215a1 1 0 1 0 -1.475 -1.35l-4.1 4.477 -4.477 -4.1a1 1 0 0 0 -1.414 0.038 1 1 0 0 0 0.037 1.414l0.027 0.023 5.215 4.775a1 1 0 0 0 1.412 -0.062zm0.265 5.994l4.775 -5.215a1 1 0 1 0 -1.475 -1.35l-4.1 4.478 -4.478 -4.1a1 1 0 0 0 -1.414 0.037 1 1 0 0 0 0.038 1.414l0.026 0.024 5.215 4.775a1 1 0 0 0 1.413 -0.063z"/>
|
||||
</svg>
|
||||
<svg x="1116">
|
||||
<path d="M9.902 22.547l3.05 -6.38a1 1 0 1 0 -1.804 -0.862l-2.619 5.477 -5.477 -2.618a1 1 0 0 0 -1.342 0.447 1 1 0 0 0 0.447 1.341l0.032 0.016 6.38 3.05a1 1 0 0 0 1.333 -0.471zm1.998 5.657l3.05 -6.38a1 1 0 1 0 -1.804 -0.862l-2.619 5.478 -5.477 -2.619a1 1 0 0 0 -1.342 0.447 1 1 0 0 0 0.447 1.342c0.01 0.006 0.022 0.01 0.032 0.015l6.38 3.05a1 1 0 0 0 1.333 -0.47z"/>
|
||||
<path d="M9.813 18.582l4.12 -5.747a1 1 0 1 0 -1.625 -1.165l-3.538 4.935 -4.935 -3.537a1 1 0 0 0 -1.399 0.205 1 1 0 0 0 0.206 1.4l0.028 0.02 5.748 4.12a1 1 0 0 0 1.395 -0.23zm0.976 5.92l4.12 -5.747a1 1 0 1 0 -1.625 -1.165l-3.537 4.935 -4.935 -3.537a1 1 0 0 0 -1.4 0.205 1 1 0 0 0 0.206 1.4l0.029 0.02 5.747 4.12a1 1 0 0 0 1.395 -0.23z"/>
|
||||
</svg>
|
||||
<svg x="1134">
|
||||
<path d="M9.973 21.632l1.628 -6.881a1 1 0 1 0 -1.946 -0.46l-1.398 5.907 -5.908 -1.398a1 1 0 0 0 -1.216 0.722 1 1 0 0 0 0.721 1.216c0.012 0.004 0.024 0.006 0.035 0.008l6.88 1.629a1 1 0 0 0 1.204 -0.743zm3.152 5.106l1.628 -6.882a1 1 0 1 0 -1.946 -0.46l-1.398 5.908 -5.908 -1.398a1 1 0 0 0 -1.217 0.721 1 1 0 0 0 0.722 1.217l0.034 0.008 6.881 1.628a1 1 0 0 0 1.204 -0.742z"/>
|
||||
<path d="M9.902 18.431l3.05 -6.38a1 1 0 1 0 -1.804 -0.862l-2.619 5.478 -5.477 -2.619a1 1 0 0 0 -1.342 0.447 1 1 0 0 0 0.447 1.342c0.01 0.006 0.022 0.01 0.032 0.015l6.38 3.05a1 1 0 0 0 1.333 -0.47zm1.998 5.658l3.05 -6.38a1 1 0 1 0 -1.804 -0.862l-2.619 5.477 -5.477 -2.618a1 1 0 0 0 -1.342 0.447 1 1 0 0 0 0.447 1.342l0.032 0.015 6.38 3.05a1 1 0 0 0 1.333 -0.471z"/>
|
||||
</svg>
|
||||
<svg x="1152">
|
||||
<path d="M10 20.625v-7.071a1 1 0 1 0 -2 0v6.071h-6.071a1 1 0 0 0 -1.018 0.982 1 1 0 0 0 0.983 1.018h7.106a1 1 0 0 0 1 -1zm4.242 4.243v-7.071a1 1 0 1 0 -2 0v6.07h-6.07a1 1 0 0 0 -1.018 0.983 1 1 0 0 0 0.982 1.017h7.106a1 1 0 0 0 1 -1z"/>
|
||||
<path d="M9.973 18.23l1.628 -6.88a1 1 0 1 0 -1.946 -0.46l-1.398 5.907 -5.908 -1.398a1 1 0 0 0 -1.216 0.721 1 1 0 0 0 0.721 1.216l0.035 0.009 6.88 1.628a1 1 0 0 0 1.204 -0.743zm3.152 5.106l1.628 -6.881a1 1 0 1 0 -1.946 -0.46l-1.398 5.907 -5.908 -1.398a1 1 0 0 0 -1.217 0.722 1 1 0 0 0 0.722 1.216c0.011 0.004 0.023 0.006 0.034 0.008l6.881 1.629a1 1 0 0 0 1.204 -0.743z"/>
|
||||
</svg>
|
||||
<svg x="1170">
|
||||
<path d="M9.973 19.618l-1.628 -6.88a1 1 0 1 0 -1.946 0.46l1.398 5.908 -5.908 1.398a1 1 0 0 0 -0.764 1.19 1 1 0 0 0 1.19 0.764l0.034 -0.008 6.881 -1.629a1 1 0 0 0 0.743 -1.203zm5.106 3.152l-1.629 -6.881a1 1 0 1 0 -1.946 0.46l1.398 5.908 -5.908 1.398a1 1 0 0 0 -0.764 1.19 1 1 0 0 0 1.19 0.764l0.035 -0.008 6.88 -1.628a1 1 0 0 0 0.744 -1.203z"/>
|
||||
<path d="M10 18v-7.071a1 1 0 1 0 -2 0v6.071h-6.071a1 1 0 0 0 -1.018 0.982 1 1 0 0 0 0.983 1.018h7.106a1 1 0 0 0 1 -1zm4.242 4.243v-7.071a1 1 0 1 0 -2 0v6.07h-6.07a1 1 0 0 0 -1.018 0.983 1 1 0 0 0 0.982 1.017h7.106a1 1 0 0 0 1 -1z"/>
|
||||
</svg>
|
||||
<svg x="1188">
|
||||
<path d="M9.902 18.703l-3.05 -6.38a1 1 0 1 0 -1.804 0.862l2.619 5.479 -5.478 2.618a1 1 0 0 0 -0.494 1.325 1 1 0 0 0 1.325 0.495l0.032 -0.016 6.38 -3.05a1 1 0 0 0 0.47 -1.333zm5.658 1.998l-3.05 -6.38a1 1 0 1 0 -1.804 0.862l2.618 5.479 -5.477 2.618a1 1 0 0 0 -0.495 1.325 1 1 0 0 0 1.325 0.495l0.032 -0.016 6.38 -3.05a1 1 0 0 0 0.47 -1.333z"/>
|
||||
<path d="M9.973 17.77l-1.628 -6.881a1 1 0 1 0 -1.946 0.46l1.398 5.908 -5.908 1.398a1 1 0 0 0 -0.764 1.19 1 1 0 0 0 1.19 0.764l0.034 -0.008 6.881 -1.628a1 1 0 0 0 0.743 -1.203zm5.106 3.151l-1.629 -6.88a1 1 0 1 0 -1.946 0.46l1.398 5.908 -5.908 1.398a1 1 0 0 0 -0.764 1.19 1 1 0 0 0 1.19 0.764l0.035 -0.008 6.88 -1.628a1 1 0 0 0 0.744 -1.204z"/>
|
||||
</svg>
|
||||
<svg x="1206">
|
||||
<path d="M9.813 17.964l-4.12 -5.747a1 1 0 1 0 -1.625 1.165l3.537 4.934 -4.935 3.537a1 1 0 0 0 -0.255 1.391 1 1 0 0 0 1.392 0.255l0.028 -0.02 5.747 -4.12a1 1 0 0 0 0.23 -1.395zm5.92 0.977l-4.12 -5.748a1 1 0 1 0 -1.625 1.165l3.537 4.935 -4.935 3.537a1 1 0 0 0 -0.255 1.391 1 1 0 0 0 1.392 0.255l0.028 -0.02 5.747 -4.12a1 1 0 0 0 0.23 -1.395z"/>
|
||||
<path d="M9.902 17.569l-3.05 -6.38a1 1 0 1 0 -1.804 0.862l2.619 5.478 -5.478 2.619a1 1 0 0 0 -0.494 1.325 1 1 0 0 0 1.325 0.494l0.032 -0.015 6.38 -3.05a1 1 0 0 0 0.47 -1.333zm5.658 1.998l-3.05 -6.38a1 1 0 1 0 -1.804 0.862l2.618 5.478 -5.477 2.619a1 1 0 0 0 -0.495 1.325 1 1 0 0 0 1.325 0.494l0.032 -0.015 6.38 -3.05a1 1 0 0 0 0.47 -1.333z"/>
|
||||
</svg>
|
||||
<svg x="1224">
|
||||
<path d="M9.737 17.472l-4.775 -5.215a1 1 0 1 0 -1.475 1.35l4.1 4.478 -4.477 4.1a1 1 0 0 0 -0.088 1.411 1 1 0 0 0 1.412 0.088l0.026 -0.024 5.215 -4.775a1 1 0 0 0 0.062 -1.413zm5.995 0.264l-4.775 -5.215a1 1 0 1 0 -1.475 1.35l4.1 4.478 -4.478 4.1a1 1 0 0 0 -0.088 1.411 1 1 0 0 0 1.412 0.088l0.026 -0.024 5.215 -4.775a1 1 0 0 0 0.063 -1.413z"/>
|
||||
<path d="M9.813 17.418l-4.12 -5.748a1 1 0 1 0 -1.625 1.165l3.537 4.935 -4.935 3.537a1 1 0 0 0 -0.255 1.39 1 1 0 0 0 1.392 0.256l0.028 -0.02 5.747 -4.12a1 1 0 0 0 0.23 -1.395zm5.92 0.976l-4.12 -5.747a1 1 0 1 0 -1.625 1.165l3.537 4.935 -4.935 3.536a1 1 0 0 0 -0.255 1.392 1 1 0 0 0 1.392 0.254l0.028 -0.02 5.747 -4.12a1 1 0 0 0 0.23 -1.395z"/>
|
||||
</svg>
|
||||
<svg x="1242">
|
||||
<path d="M9.707 17.293l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414zm6 0l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414z"/>
|
||||
<path d="M9.737 17.325l-4.775 -5.215a1 1 0 1 0 -1.475 1.35l4.1 4.478 -4.477 4.1a1 1 0 0 0 -0.088 1.411 1 1 0 0 0 1.412 0.087c0.01 -0.007 0.018 -0.016 0.026 -0.024l5.215 -4.775a1 1 0 0 0 0.062 -1.412zm5.995 0.264l-4.775 -5.215a1 1 0 1 0 -1.475 1.35l4.1 4.478 -4.478 4.1a1 1 0 0 0 -0.088 1.411 1 1 0 0 0 1.412 0.087c0.01 -0.007 0.018 -0.016 0.026 -0.023l5.215 -4.775a1 1 0 0 0 0.063 -1.413z"/>
|
||||
</svg>
|
||||
<svg x="1260">
|
||||
<path d="M9.707 17.293l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414zm6 0l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414z"/>
|
||||
</svg>
|
||||
<svg x="1278">
|
||||
<path d="M9.707 17.293l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414zm6 0l-5 -5a1 1 0 1 0 -1.414 1.414l4.293 4.293 -4.293 4.293a1 1 0 0 0 -0.025 1.414 1 1 0 0 0 1.414 0.025l0.025 -0.025 5 -5a1 1 0 0 0 0 -1.414z"/>
|
||||
</svg>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
@ -115,25 +115,12 @@ caption > label {
|
||||
|
||||
#categories {
|
||||
max-height: 100vh;
|
||||
background-color: #fafafc;
|
||||
}
|
||||
|
||||
#categories > scrollbox {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 1.45rem;
|
||||
}
|
||||
|
||||
.category,
|
||||
.category:hover,
|
||||
.category[selected] {
|
||||
background-color: transparent;
|
||||
border-inline-start: initial;
|
||||
padding-inline-start: 44px;
|
||||
}
|
||||
|
||||
/**
|
||||
* We want the last category to always have non-0 getBoundingClientRect().bottom
|
||||
* so we can use the value to figure out the max-height of the list in
|
||||
|
@ -6,12 +6,10 @@
|
||||
|
||||
:root {
|
||||
--tab-toolbar-navbar-overlap: 1px;
|
||||
/* Temporarily using the compact tab strip by default because of bug 1386964:
|
||||
--tab-min-height: 33px;
|
||||
}
|
||||
|
||||
:root[uidensity=compact] {
|
||||
*/
|
||||
--tab-min-height: 29px;
|
||||
}
|
||||
|
||||
@ -312,6 +310,10 @@
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
:root:not([sizemode=normal]) .tabbrowser-tab[first-visible-tab] > .tab-stack > .tab-background[selected=true] {
|
||||
border-inline-start-style: none;
|
||||
}
|
||||
|
||||
.tab-line[selected=true] {
|
||||
background-color: Highlight;
|
||||
}
|
||||
@ -439,9 +441,6 @@
|
||||
#TabsToolbar > #new-tab-button ,
|
||||
#TabsToolbar > toolbarpaletteitem > #new-tab-button {
|
||||
list-style-image: url(chrome://browser/skin/tabbrowser/newtab.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.tabs-newtab-button {
|
||||
@ -462,8 +461,6 @@
|
||||
|
||||
#alltabs-button {
|
||||
list-style-image: url(chrome://browser/skin/arrow-dropdown-16.svg);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.alltabs-item > .menu-iconic-left > .menu-iconic-icon {
|
||||
|
@ -300,6 +300,7 @@ toolbar:not([brighttext]) #bookmarks-menu-button[starred] > .toolbarbutton-menub
|
||||
list-style-image: url("chrome://browser/skin/zoom-in.svg");
|
||||
}
|
||||
|
||||
#PlacesChevron,
|
||||
#nav-bar-overflow-button {
|
||||
list-style-image: url("chrome://browser/skin/chevron.svg");
|
||||
}
|
||||
@ -316,7 +317,7 @@ toolbar:not([brighttext]) #bookmarks-menu-button[starred] > .toolbarbutton-menub
|
||||
fill: #30A3FF;
|
||||
}
|
||||
to {
|
||||
transform: translateX(-1242px);
|
||||
transform: translateX(-1260px);
|
||||
fill: #30A3FF;
|
||||
}
|
||||
}
|
||||
@ -329,7 +330,7 @@ toolbar:not([brighttext]) #bookmarks-menu-button[starred] > .toolbarbutton-menub
|
||||
fill: #30A3FF;
|
||||
}
|
||||
to {
|
||||
transform: scaleX(-1) translateX(-1242px);
|
||||
transform: scaleX(-1) translateX(-1260px);
|
||||
fill: #30A3FF;
|
||||
}
|
||||
}
|
||||
@ -370,10 +371,10 @@ toolbar:not([brighttext]) #bookmarks-menu-button[starred] > .toolbarbutton-menub
|
||||
|
||||
#nav-bar-overflow-button[animate] > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
|
||||
animation-name: overflow-animation;
|
||||
animation-timing-function: steps(69);
|
||||
animation-duration: 1150ms;
|
||||
animation-timing-function: steps(70);
|
||||
animation-duration: 1167ms;
|
||||
background-image: url("chrome://browser/skin/chevron-animation.svg");
|
||||
width: 1260px;
|
||||
width: 1278px;
|
||||
}
|
||||
|
||||
#nav-bar-overflow-button[animate]:-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
|
||||
|
@ -11,8 +11,8 @@
|
||||
--backbutton-background: hsla(0,100%,100%,.8);
|
||||
--backbutton-hover-background: var(--backbutton-background);
|
||||
--backbutton-active-background: var(--toolbarbutton-active-background);
|
||||
|
||||
--backbutton-border-color: hsla(240,5%,5%,.3);
|
||||
|
||||
/* This default value of --toolbarbutton-height is defined to prevent
|
||||
CSS errors for an invalid variable. The value should not get used,
|
||||
as a more specific value should be set when the value will be used. */
|
||||
@ -49,8 +49,8 @@ toolbar[brighttext] {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
:-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
.toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
max-width: 16px;
|
||||
}
|
||||
|
||||
@ -60,7 +60,6 @@ toolbar[brighttext] {
|
||||
margin: 0 0 var(--tab-toolbar-navbar-overlap);
|
||||
}
|
||||
|
||||
#TabsToolbar .toolbarbutton-1,
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-up,
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-down {
|
||||
-moz-appearance: none;
|
||||
@ -89,49 +88,48 @@ toolbar[brighttext] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 {
|
||||
toolbar .toolbarbutton-1 {
|
||||
-moz-appearance: none;
|
||||
margin: 0;
|
||||
padding: 0 2px;
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
#nav-bar #PanelUI-menu-button {
|
||||
#PanelUI-menu-button {
|
||||
padding-inline-start: 5px;
|
||||
padding-inline-end: 5px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > menupopup {
|
||||
toolbar .toolbarbutton-1 > menupopup {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > menupopup.cui-widget-panel {
|
||||
toolbar .toolbarbutton-1 > menupopup.cui-widget-panel {
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.findbar-button > .toolbarbutton-text,
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack {
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-badge-stack {
|
||||
padding: var(--toolbarbutton-inner-padding);
|
||||
border-radius: var(--toolbarbutton-border-radius);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon {
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-icon {
|
||||
/* horizontal padding + actual icon width */
|
||||
max-width: calc(2 * var(--toolbarbutton-inner-padding) + 16px);
|
||||
}
|
||||
|
||||
.bookmark-item > .toolbarbutton-menu-dropmarker,
|
||||
#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text {
|
||||
toolbar .toolbarbutton-1 > .toolbarbutton-text {
|
||||
padding-top: var(--toolbarbutton-vertical-text-padding);
|
||||
padding-bottom: 0;
|
||||
/* To make the hover feedback line up with sibling buttons, it needs the same
|
||||
@ -141,17 +139,17 @@ toolbarbutton.bookmark-item:not(.subviewbutton),
|
||||
min-height: calc(16px + 2 * var(--toolbarbutton-inner-padding));
|
||||
}
|
||||
|
||||
#nav-bar .toolbaritem-combined-buttons {
|
||||
toolbar .toolbaritem-combined-buttons {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 {
|
||||
toolbar .toolbaritem-combined-buttons > .toolbarbutton-1 {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbaritem-combined-buttons:not(:hover) > separator {
|
||||
toolbar .toolbaritem-combined-buttons:not(:hover) > separator {
|
||||
content: "";
|
||||
display: -moz-box;
|
||||
width: 1px;
|
||||
@ -164,19 +162,17 @@ toolbarbutton.bookmark-item:not(.subviewbutton),
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
#nav-bar[brighttext] .toolbaritem-combined-buttons > separator {
|
||||
toolbar[brighttext] .toolbaritem-combined-buttons > separator {
|
||||
opacity: .3;
|
||||
}
|
||||
|
||||
#TabsToolbar .toolbarbutton-1:not([disabled=true]):hover,
|
||||
#TabsToolbar .toolbarbutton-1[open],
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled=true]):hover,
|
||||
.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled=true]):hover,
|
||||
.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover > .toolbarbutton-text,
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not([open]),
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack {
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack {
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
color: inherit;
|
||||
}
|
||||
@ -184,15 +180,15 @@ toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not
|
||||
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active:not([disabled="true"]),
|
||||
toolbarbutton.bookmark-item[open="true"],
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
toolbar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
background-color: var(--toolbarbutton-active-background);
|
||||
transition-duration: 10ms;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
|
||||
toolbar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
transition: background-color .4s;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
%filter substitution
|
||||
%define toolbarShadowColor hsla(209,67%,12%,0.35)
|
||||
%define glassActiveBorderColor rgb(37, 44, 51)
|
||||
%define glassInactiveBorderColor rgb(102, 102, 102)
|
||||
|
||||
|
@ -8,9 +8,6 @@
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@namespace svg url("http://www.w3.org/2000/svg");
|
||||
|
||||
%include ../shared/browser.inc
|
||||
%define toolbarShadowColor hsla(209,67%,12%,0.35)
|
||||
|
||||
%include ../shared/browser.inc.css
|
||||
|
||||
:root {
|
||||
@ -1045,28 +1042,6 @@ treechildren.searchbar-treebody::-moz-tree-row(selected) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important;
|
||||
}
|
||||
|
||||
toolbar[brighttext] toolbarbutton.chevron {
|
||||
list-style-image: url("chrome://global/skin/toolbar/chevron-inverted.png") !important;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-text,
|
||||
toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Bookmarks toolbar */
|
||||
#PlacesToolbarDropIndicator {
|
||||
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
|
||||
|
@ -1141,13 +1141,13 @@ option('--enable-gold',
|
||||
help='Enable GNU Gold Linker when it is not already the default',
|
||||
when=build_not_win_mac)
|
||||
|
||||
imply_option('--enable-linker',
|
||||
depends_if('--enable-gold', when=build_not_win_mac)(lambda x: 'gold'),
|
||||
when=build_not_win_mac)
|
||||
|
||||
@depends('--enable-gold', c_compiler, developer_options, check_build_environment, when=build_not_win_mac)
|
||||
@checking('for ld', lambda x: x.KIND)
|
||||
@imports('os')
|
||||
@imports('shutil')
|
||||
def enable_gold(enable_gold_option, c_compiler, developer_options, build_env):
|
||||
linker = None
|
||||
def enable_gnu_linker(enable_gold_option, c_compiler, developer_options, build_env, linker_name):
|
||||
# Used to check the kind of linker
|
||||
version_check = ['-Wl,--version']
|
||||
cmd_base = c_compiler.wrapper + [c_compiler.compiler] + c_compiler.flags
|
||||
@ -1182,7 +1182,7 @@ def enable_gold(enable_gold_option, c_compiler, developer_options, build_env):
|
||||
# The -B trick didn't work, removing the directory
|
||||
shutil.rmtree(targetDir)
|
||||
|
||||
if enable_gold_option or developer_options:
|
||||
if (enable_gold_option or developer_options) and linker_name != 'bfd':
|
||||
result = resolve_gold()
|
||||
|
||||
if result:
|
||||
@ -1213,5 +1213,30 @@ def enable_gold(enable_gold_option, c_compiler, developer_options, build_env):
|
||||
KIND='other'
|
||||
)
|
||||
|
||||
set_config('LD_IS_BFD', depends(enable_gold.KIND)(lambda x: x == 'bfd' or None))
|
||||
set_config('LINKER_LDFLAGS', enable_gold.LINKER_FLAG)
|
||||
js_option('--enable-linker', nargs=1,
|
||||
choices=('bfd', 'gold', 'lld', 'other'),
|
||||
help='Select the linker',
|
||||
when=build_not_win_mac)
|
||||
|
||||
@depends('--enable-linker', c_compiler, developer_options, check_build_environment, when=build_not_win_mac)
|
||||
@checking('for linker', lambda x: x.KIND)
|
||||
def select_linker(linker, c_compiler, developer_options, build_env):
|
||||
linker = linker[0] if linker else 'other'
|
||||
if linker in ('gold', 'bfd', 'other'):
|
||||
return enable_gnu_linker(linker == 'gold', c_compiler, developer_options, build_env, linker)
|
||||
if linker == 'lld':
|
||||
version_check = ['-Wl,--version']
|
||||
cmd_base = c_compiler.wrapper + [c_compiler.compiler] + c_compiler.flags
|
||||
lld = "-fuse-ld=" + linker
|
||||
cmd = cmd_base + [lld] + version_check
|
||||
if 'LLD' in check_cmd_output(*cmd).decode('utf-8'):
|
||||
return namespace(
|
||||
KIND='lld',
|
||||
LINKER_FLAG=lld,
|
||||
)
|
||||
else:
|
||||
die("Could not use lld as linker")
|
||||
|
||||
|
||||
set_config('LD_IS_BFD', depends(select_linker.KIND)(lambda x: x == 'bfd' or None))
|
||||
set_config('LINKER_LDFLAGS', select_linker.LINKER_FLAG)
|
||||
|
@ -8,13 +8,16 @@
|
||||
|
||||
document.body.innerText = "Background Page Body Test Content";
|
||||
|
||||
// This function are called from the webconsole test:
|
||||
// browser_addons_debug_webextension.js
|
||||
// These functions are called from the following about:debugging tests:
|
||||
// - browser_addons_debug_webextension.js
|
||||
// - browser_addons_debug_webextension_popup.js
|
||||
|
||||
function myWebExtensionAddonFunction() { // eslint-disable-line no-unused-vars
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function myWebExtensionAddonFunction() {
|
||||
console.log("Background page function called", browser.runtime.getManifest());
|
||||
}
|
||||
|
||||
function myWebExtensionShowPopup() { // eslint-disable-line no-unused-vars
|
||||
console.log("readyForOpenPopup");
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function myWebExtensionShowPopup() {
|
||||
browser.test.sendMessage("readyForOpenPopup");
|
||||
}
|
||||
|
@ -6,8 +6,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// This function is called from the webconsole test:
|
||||
// This function is called from the following about:debugging test:
|
||||
// browser_addons_debug_webextension.js
|
||||
function myWebExtensionPopupAddonFunction() { // eslint-disable-line no-unused-vars
|
||||
console.log("Popup page function called", browser.runtime.getManifest());
|
||||
//
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function myWebExtensionPopupAddonFunction() {
|
||||
browser.test.sendMessage("popupPageFunctionCalled", browser.runtime.getManifest());
|
||||
}
|
||||
|
@ -23,31 +23,39 @@ add_task(function* testWebExtensionsToolboxWebConsole() {
|
||||
tab, document, debugBtn,
|
||||
} = yield setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
|
||||
|
||||
// Wait for a notification sent by a script evaluated the test addon via
|
||||
// the web console.
|
||||
let onCustomMessage = new Promise(done => {
|
||||
Services.obs.addObserver(function listener(message, topic) {
|
||||
let apiMessage = message.wrappedJSObject;
|
||||
if (apiMessage.addonId != ADDON_ID) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(listener, "console-api-log-event");
|
||||
done(apiMessage.arguments);
|
||||
}, "console-api-log-event");
|
||||
});
|
||||
|
||||
// Be careful, this JS function is going to be executed in the addon toolbox,
|
||||
// which lives in another process. So do not try to use any scope variable!
|
||||
let env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let testScript = function () {
|
||||
/* eslint-disable no-undef */
|
||||
function findMessages(hud, text, selector = ".message") {
|
||||
const messages = hud.ui.outputNode.querySelectorAll(selector);
|
||||
const elements = Array.prototype.filter.call(
|
||||
messages,
|
||||
(el) => el.textContent.includes(text)
|
||||
);
|
||||
return elements;
|
||||
}
|
||||
|
||||
async function waitFor(condition) {
|
||||
while (!condition()) {
|
||||
await new Promise(done => window.setTimeout(done, 1000));
|
||||
}
|
||||
}
|
||||
|
||||
toolbox.selectTool("webconsole")
|
||||
.then(console => {
|
||||
let { jsterm } = console.hud;
|
||||
return jsterm.execute("myWebExtensionAddonFunction()");
|
||||
.then(async console => {
|
||||
let { hud } = console;
|
||||
let { jsterm } = hud;
|
||||
let onMessage = waitFor(() => {
|
||||
return findMessages(hud, "Background page function called").length > 0;
|
||||
});
|
||||
await jsterm.execute("myWebExtensionAddonFunction()");
|
||||
await onMessage;
|
||||
await toolbox.destroy();
|
||||
})
|
||||
.then(() => toolbox.destroy());
|
||||
.catch(e => dump("Exception from browser toolbox process: " + e + "\n"));
|
||||
/* eslint-enable no-undef */
|
||||
};
|
||||
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
|
||||
@ -59,12 +67,6 @@ add_task(function* testWebExtensionsToolboxWebConsole() {
|
||||
|
||||
debugBtn.click();
|
||||
|
||||
let args = yield onCustomMessage;
|
||||
ok(true, "Received console message from the background page function as expected");
|
||||
is(args[0], "Background page function called", "Got the expected console message");
|
||||
is(args[1] && args[1].name, ADDON_NAME,
|
||||
"Got the expected manifest from WebExtension API");
|
||||
|
||||
yield onToolboxClose;
|
||||
ok(true, "Addon toolbox closed");
|
||||
|
||||
|
@ -37,28 +37,48 @@ function makeWidgetId(id) {
|
||||
}
|
||||
|
||||
add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
let onReadyForOpenPopup;
|
||||
let onPopupCustomMessage;
|
||||
|
||||
Management.on("startup", function listener(event, extension) {
|
||||
if (extension.name != ADDON_NAME) {
|
||||
return;
|
||||
}
|
||||
|
||||
Management.off("startup", listener);
|
||||
|
||||
function waitForExtensionTestMessage(expectedMessage) {
|
||||
return new Promise(done => {
|
||||
extension.on("test-message", function testLogListener(evt, ...args) {
|
||||
const [message, ] = args;
|
||||
|
||||
if (message !== expectedMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
extension.off("test-message", testLogListener);
|
||||
done(args);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Wait for the test script running in the browser toolbox process
|
||||
// to be ready for selecting the popup page in the frame list selector.
|
||||
onReadyForOpenPopup = waitForExtensionTestMessage("readyForOpenPopup");
|
||||
|
||||
// Wait for a notification sent by a script evaluated the test addon via
|
||||
// the web console.
|
||||
onPopupCustomMessage = waitForExtensionTestMessage("popupPageFunctionCalled");
|
||||
});
|
||||
|
||||
let {
|
||||
tab, document, debugBtn,
|
||||
} = yield setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
|
||||
|
||||
let onReadyForOpenPopup = new Promise(done => {
|
||||
Services.obs.addObserver(function listener(message, topic) {
|
||||
let apiMessage = message.wrappedJSObject;
|
||||
if (apiMessage.addonId != ADDON_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiMessage.arguments[0] == "readyForOpenPopup") {
|
||||
Services.obs.removeObserver(listener, "console-api-log-event");
|
||||
done();
|
||||
}
|
||||
}, "console-api-log-event");
|
||||
});
|
||||
|
||||
// Be careful, this JS function is going to be executed in the addon toolbox,
|
||||
// which lives in another process. So do not try to use any scope variable!
|
||||
let env = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment);
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
let testScript = function () {
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
@ -66,7 +86,7 @@ add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
let popupFramePromise;
|
||||
|
||||
toolbox.selectTool("webconsole")
|
||||
.then(console => {
|
||||
.then(async (console) => {
|
||||
dump(`Clicking the noautohide button\n`);
|
||||
toolbox.doc.getElementById("command-button-noautohide").click();
|
||||
dump(`Clicked the noautohide button\n`);
|
||||
@ -81,32 +101,25 @@ add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
toolbox.target.on("frame-update", listener);
|
||||
});
|
||||
|
||||
let waitForFrameListUpdate = new Promise((done) => {
|
||||
toolbox.target.once("frame-update", () => {
|
||||
done(console);
|
||||
});
|
||||
});
|
||||
let waitForFrameListUpdate = toolbox.target.once("frame-update");
|
||||
|
||||
jsterm = console.hud.jsterm;
|
||||
jsterm.execute("myWebExtensionShowPopup()");
|
||||
|
||||
// Wait the initial frame update (which list the background page).
|
||||
return waitForFrameListUpdate;
|
||||
})
|
||||
.then((console) => {
|
||||
// Wait the new frame update (once the extension popup has been opened).
|
||||
return popupFramePromise;
|
||||
})
|
||||
.then(() => {
|
||||
await Promise.all([
|
||||
// Wait the initial frame update (which list the background page).
|
||||
waitForFrameListUpdate,
|
||||
// Wait the new frame update (once the extension popup has been opened).
|
||||
popupFramePromise,
|
||||
]);
|
||||
|
||||
dump(`Clicking the frame list button\n`);
|
||||
let btn = toolbox.doc.getElementById("command-button-frames");
|
||||
let menu = toolbox.showFramesMenu({target: btn});
|
||||
let frameMenu = toolbox.showFramesMenu({target: btn});
|
||||
dump(`Clicked the frame list button\n`);
|
||||
return menu.once("open").then(() => {
|
||||
return menu;
|
||||
});
|
||||
})
|
||||
.then(frameMenu => {
|
||||
|
||||
await frameMenu.once("open");
|
||||
|
||||
let frames = frameMenu.items;
|
||||
|
||||
if (frames.length != 2) {
|
||||
@ -125,12 +138,12 @@ add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
|
||||
popupFrameBtn.click();
|
||||
|
||||
return waitForNavigated;
|
||||
await waitForNavigated;
|
||||
|
||||
await jsterm.execute("myWebExtensionPopupAddonFunction()");
|
||||
|
||||
await toolbox.destroy();
|
||||
})
|
||||
.then(() => {
|
||||
return jsterm.execute("myWebExtensionPopupAddonFunction()");
|
||||
})
|
||||
.then(() => toolbox.destroy())
|
||||
.catch((error) => {
|
||||
dump("Error while running code in the browser toolbox process:\n");
|
||||
dump(error + "\n");
|
||||
@ -143,22 +156,6 @@ add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
|
||||
});
|
||||
|
||||
// Wait for a notification sent by a script evaluated the test addon via
|
||||
// the web console.
|
||||
let onPopupCustomMessage = new Promise(done => {
|
||||
Services.obs.addObserver(function listener(message, topic) {
|
||||
let apiMessage = message.wrappedJSObject;
|
||||
if (apiMessage.addonId != ADDON_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiMessage.arguments[0] == "Popup page function called") {
|
||||
Services.obs.removeObserver(listener, "console-api-log-event");
|
||||
done(apiMessage.arguments);
|
||||
}
|
||||
}, "console-api-log-event");
|
||||
});
|
||||
|
||||
let onToolboxClose = BrowserToolboxProcess.once("close");
|
||||
|
||||
debugBtn.click();
|
||||
@ -174,7 +171,7 @@ add_task(function* testWebExtensionsToolboxSwitchToPopup() {
|
||||
|
||||
let args = yield onPopupCustomMessage;
|
||||
ok(true, "Received console message from the popup page function as expected");
|
||||
is(args[0], "Popup page function called", "Got the expected console message");
|
||||
is(args[0], "popupPageFunctionCalled", "Got the expected console message");
|
||||
is(args[1] && args[1].name, ADDON_NAME,
|
||||
"Got the expected manifest from WebExtension API");
|
||||
|
||||
|
@ -25,7 +25,7 @@ loader.lazyGetter(this, "prefBranch", function () {
|
||||
|
||||
loader.lazyRequireGetter(this, "gcliInit", "devtools/shared/gcli/commands/index");
|
||||
loader.lazyRequireGetter(this, "util", "gcli/util/util");
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/utils/webconsole-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/webconsole/listeners", true);
|
||||
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
|
||||
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
|
||||
loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" fill="#fbfbfb">
|
||||
<path d="M12,17c0.5,0,1-0.5,1-1v-4c0,0,0.2-0.8,0.8-0.8c0.6,0,0.6,0.8,1.8,0.8 c0.6,0,1.5-0.2,1.5-2c0-1.8-0.9-2-1.5-2c-1.1,0-1.2,0.8-1.8,0.8C13.2,8.8,13,8,13,8V6c0-0.6-0.4-1-1-1H9c0,0-0.8-0.1-0.8-0.8 S9,3.6,9,2.5C9,1.9,8.8,1,7,1S5,1.9,5,2.5c0,1.1,0.8,1.2,0.8,1.8S5,5,5,5H2C1.4,5,1,5.4,1,6l0,2.5c0,0-0.1,1.5,1.1,1.5 c0.8,0,0.9-1,1.9-1c0.5,0,1,0.5,1,1.6c0,1-0.5,1.6-1,1.6c-1,0-1.1-1-1.9-1C0.9,11,1,12.5,1,12.5L1,16c0,0.6,0.4,1,1,1h3.9 c0,0,1.5,0.1,1.5-1.1c0-0.8-1-0.9-1-1.9c0-0.5,0.7-1.2,1.8-1.2s1.9,0.7,1.9,1.2c0,1-1,1.1-1,1.9c0,1.2,1.5,1.1,1.5,1.1H12z" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" d="M14.5 8c-.971 0-1 1-1.75 1a.765.765 0 0 1-.75-.75V5a1 1 0 0 0-1-1H7.75A.765.765 0 0 1 7 3.25c0-.75 1-.779 1-1.75C8 .635 7.1 0 6 0S4 .635 4 1.5c0 .971 1 1 1 1.75a.765.765 0 0 1-.75.75H1a1 1 0 0 0-1 1v2.25A.765.765 0 0 0 .75 8c.75 0 .779-1 1.75-1C3.365 7 4 7.9 4 9s-.635 2-1.5 2c-.971 0-1-1-1.75-1a.765.765 0 0 0-.75.75V15a1 1 0 0 0 1 1h3.25a.765.765 0 0 0 .75-.75c0-.75-1-.779-1-1.75 0-.865.9-1.5 2-1.5s2 .635 2 1.5c0 .971-1 1-1 1.75a.765.765 0 0 0 .75.75H11a1 1 0 0 0 1-1v-3.25a.765.765 0 0 1 .75-.75c.75 0 .779 1 1.75 1 .865 0 1.5-.9 1.5-2s-.635-2-1.5-2z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 874 B After Width: | Height: | Size: 899 B |
@ -1,3 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path d="M17,12v2a1,1,0,0,1-1,1H2a1,1,0,0,1-1-1V12a1,1,0,0,1,1-1H1.142c2.3,0,2.536-1.773,2.874-4,0.351-2.316.083-4,3.13-4h3.707C13.917,3,13.647,4.684,14,7c0.34,2.228.582,4,2.89,4H16A1,1,0,0,1,17,12Z" fill="white"/>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<path fill="context-fill" d="M15 11h-1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 401 B |
@ -1,7 +1,7 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#fbfbfb">
|
||||
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill">
|
||||
<path d="M14.6,6.1L13.5,5l0,0c0.1-0.1,0.2-0.4,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6l-0.4-0.4c-0.3-0.3-0.8-0.3-1.1,0l0,0
|
||||
L10.5,2c-0.2-0.2-0.3-0.2-0.5-0.2c-0.2,0-0.3,0.1-0.5,0.2L8.3,3.2C8.1,3.3,8.1,3.4,8.1,3.6S8.2,4,8.3,4.1l1.6,1.6L7.8,7.8L5.6,5.7
|
||||
l1.5-1.5C7.3,4,7.4,3.8,7.4,3.6c0-0.2-0.1-0.4-0.2-0.6l-1-1C5.8,1.7,5.3,1.7,5,2L0.9,6.1C0.7,6.3,0.6,6.5,0.6,6.7
|
||||
|
Before Width: | Height: | Size: 963 B After Width: | Height: | Size: 948 B |
@ -190,9 +190,8 @@ HUD_SERVICE.prototype =
|
||||
return client.connect()
|
||||
.then(() => client.getProcess())
|
||||
.then(aResponse => {
|
||||
// Set chrome:false in order to attach to the target
|
||||
// (i.e. send an `attach` request to the chrome actor)
|
||||
return { form: aResponse.form, client: client, chrome: false };
|
||||
// Use a TabActor in order to ensure calling `attach` to the ChromeActor
|
||||
return { form: aResponse.form, client, chrome: true, isTabActor: true };
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,11 @@ WebConsoleConnectionProxy.prototype = {
|
||||
_attachConsole: function () {
|
||||
let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity"];
|
||||
// Enable the forwarding of console messages to the parent process
|
||||
// when we open the Browser Console or Toolbox.
|
||||
if (this.target.chrome && !this.target.isAddon) {
|
||||
listeners.push("ContentProcessMessages");
|
||||
}
|
||||
this.client.attachConsole(this._consoleActor, listeners,
|
||||
this._onAttachConsole);
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ var Services = require("Services");
|
||||
var { ActorPool } = require("devtools/server/actors/common");
|
||||
var { TabSources } = require("./utils/TabSources");
|
||||
var makeDebugger = require("./utils/make-debugger");
|
||||
var { ConsoleAPIListener } = require("devtools/server/actors/utils/webconsole-listeners");
|
||||
var { ConsoleAPIListener } = require("devtools/server/actors/webconsole/listeners");
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
var { assert, update } = DevToolsUtils;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
DIRS += [
|
||||
'highlighters',
|
||||
'utils',
|
||||
'webconsole',
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
|
@ -15,7 +15,4 @@ DevToolsModules(
|
||||
'stack.js',
|
||||
'TabSources.js',
|
||||
'walker-search.js',
|
||||
'webconsole-listeners.js',
|
||||
'webconsole-utils.js',
|
||||
'webconsole-worker-listeners.js',
|
||||
)
|
||||
|
@ -25,20 +25,21 @@ loader.lazyRequireGetter(this, "ServerLoggingListener", "devtools/shared/webcons
|
||||
loader.lazyRequireGetter(this, "JSPropertyProvider", "devtools/shared/webconsole/js-property-provider", true);
|
||||
loader.lazyRequireGetter(this, "Parser", "resource://devtools/shared/Parser.jsm", true);
|
||||
loader.lazyRequireGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm", true);
|
||||
loader.lazyRequireGetter(this, "addWebConsoleCommands", "devtools/server/actors/utils/webconsole-utils", true);
|
||||
loader.lazyRequireGetter(this, "CONSOLE_WORKER_IDS", "devtools/server/actors/utils/webconsole-utils", true);
|
||||
loader.lazyRequireGetter(this, "WebConsoleUtils", "devtools/server/actors/utils/webconsole-utils", true);
|
||||
loader.lazyRequireGetter(this, "addWebConsoleCommands", "devtools/server/actors/webconsole/utils", true);
|
||||
loader.lazyRequireGetter(this, "CONSOLE_WORKER_IDS", "devtools/server/actors/webconsole/utils", true);
|
||||
loader.lazyRequireGetter(this, "WebConsoleUtils", "devtools/server/actors/webconsole/utils", true);
|
||||
loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
|
||||
|
||||
// Overwrite implemented listeners for workers so that we don't attempt
|
||||
// to load an unsupported module.
|
||||
if (isWorker) {
|
||||
loader.lazyRequireGetter(this, "ConsoleAPIListener", "devtools/server/actors/utils/webconsole-worker-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/utils/webconsole-worker-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleAPIListener", "devtools/server/actors/webconsole/worker-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/webconsole/worker-listeners", true);
|
||||
} else {
|
||||
loader.lazyRequireGetter(this, "ConsoleAPIListener", "devtools/server/actors/utils/webconsole-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/utils/webconsole-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleReflowListener", "devtools/server/actors/utils/webconsole-listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleAPIListener", "devtools/server/actors/webconsole/listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/server/actors/webconsole/listeners", true);
|
||||
loader.lazyRequireGetter(this, "ConsoleReflowListener", "devtools/server/actors/webconsole/listeners", true);
|
||||
loader.lazyRequireGetter(this, "ContentProcessListener", "devtools/server/actors/webconsole/listeners", true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -368,6 +369,10 @@ WebConsoleActor.prototype =
|
||||
this.serverLoggingListener.destroy();
|
||||
this.serverLoggingListener = null;
|
||||
}
|
||||
if (this.contentProcessListener) {
|
||||
this.contentProcessListener.destroy();
|
||||
this.contentProcessListener = null;
|
||||
}
|
||||
|
||||
events.off(this.parentActor, "changed-toplevel-document",
|
||||
this._onChangedToplevelDocument);
|
||||
@ -664,6 +669,16 @@ WebConsoleActor.prototype =
|
||||
}
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
case "ContentProcessMessages":
|
||||
// Workers don't support this message type
|
||||
if (isWorker) {
|
||||
break;
|
||||
}
|
||||
if (!this.contentProcessListener) {
|
||||
this.contentProcessListener = new ContentProcessListener(this);
|
||||
}
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,7 +708,7 @@ WebConsoleActor.prototype =
|
||||
// listeners.
|
||||
let toDetach = request.listeners ||
|
||||
["PageError", "ConsoleAPI", "NetworkActivity",
|
||||
"FileActivity", "ServerLogging"];
|
||||
"FileActivity", "ServerLogging", "ContentProcessMessages"];
|
||||
|
||||
while (toDetach.length > 0) {
|
||||
let listener = toDetach.shift();
|
||||
@ -749,6 +764,13 @@ WebConsoleActor.prototype =
|
||||
}
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
case "ContentProcessMessages":
|
||||
if (this.contentProcessListener) {
|
||||
this.contentProcessListener.destroy();
|
||||
this.contentProcessListener = null;
|
||||
}
|
||||
stoppedListeners.push(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
136
devtools/server/actors/webconsole/content-process-forward.js
Normal file
@ -0,0 +1,136 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
|
||||
"resource:///modules/E10SUtils.jsm");
|
||||
|
||||
/*
|
||||
* The message manager has an upper limit on message sizes that it can
|
||||
* reliably forward to the parent so we limit the size of console log event
|
||||
* messages that we forward here. The web console is local and receives the
|
||||
* full console message, but addons subscribed to console event messages
|
||||
* in the parent receive the truncated version. Due to fragmentation,
|
||||
* messages as small as 1MB have resulted in IPC allocation failures on
|
||||
* 32-bit platforms. To limit IPC allocation sizes, console.log messages
|
||||
* with arguments with total size > MSG_MGR_CONSOLE_MAX_SIZE (bytes) have
|
||||
* their arguments completely truncated. MSG_MGR_CONSOLE_VAR_SIZE is an
|
||||
* approximation of how much space (in bytes) a JS non-string variable will
|
||||
* require in the manager's implementation. For strings, we use 2 bytes per
|
||||
* char. The console message URI and function name are limited to
|
||||
* MSG_MGR_CONSOLE_INFO_MAX characters. We don't attempt to calculate
|
||||
* the exact amount of space the message manager implementation will require
|
||||
* for a given message so this is imperfect.
|
||||
*/
|
||||
const MSG_MGR_CONSOLE_MAX_SIZE = 1024 * 1024; // 1MB
|
||||
const MSG_MGR_CONSOLE_VAR_SIZE = 8;
|
||||
const MSG_MGR_CONSOLE_INFO_MAX = 1024;
|
||||
|
||||
function ContentProcessForward() {
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
Services.obs.addObserver(this, "xpcom-shutdown");
|
||||
cpmm.addMessageListener("DevTools:StopForwardingContentProcessMessage", this);
|
||||
}
|
||||
ContentProcessForward.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
receiveMessage(message) {
|
||||
if (message.name == "DevTools:StopForwardingContentProcessMessage") {
|
||||
this.uninit();
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "console-api-log-event": {
|
||||
let consoleMsg = subject.wrappedJSObject;
|
||||
|
||||
let msgData = {
|
||||
level: consoleMsg.level,
|
||||
filename: consoleMsg.filename.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
lineNumber: consoleMsg.lineNumber,
|
||||
functionName: consoleMsg.functionName &&
|
||||
consoleMsg.functionName.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
timeStamp: consoleMsg.timeStamp,
|
||||
addonId: consoleMsg.addonId,
|
||||
arguments: [],
|
||||
};
|
||||
|
||||
// We can't send objects over the message manager, so we sanitize
|
||||
// them out, replacing those arguments with "<unavailable>".
|
||||
let unavailString = "<unavailable>";
|
||||
let unavailStringLength = unavailString.length * 2; // 2-bytes per char
|
||||
|
||||
// When the sum of argument sizes reaches MSG_MGR_CONSOLE_MAX_SIZE,
|
||||
// replace all arguments with "<truncated>".
|
||||
let totalArgLength = 0;
|
||||
|
||||
// Walk through the arguments, checking the type and size.
|
||||
for (let arg of consoleMsg.arguments) {
|
||||
if ((typeof arg == "object" || typeof arg == "function") &&
|
||||
arg !== null) {
|
||||
if (Services.appinfo.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE) {
|
||||
// For OOP extensions: we want the developer to be able to see the
|
||||
// logs in the Browser Console. When the Addon Toolbox will be more
|
||||
// prominent we can revisit.
|
||||
try {
|
||||
// If the argument is clonable, then send it as-is. If
|
||||
// cloning fails, fall back to the unavailable string.
|
||||
arg = Cu.cloneInto(arg, {});
|
||||
} catch (e) {
|
||||
arg = unavailString;
|
||||
}
|
||||
} else {
|
||||
arg = unavailString;
|
||||
}
|
||||
totalArgLength += unavailStringLength;
|
||||
} else if (typeof arg == "string") {
|
||||
totalArgLength += arg.length * 2; // 2-bytes per char
|
||||
} else {
|
||||
totalArgLength += MSG_MGR_CONSOLE_VAR_SIZE;
|
||||
}
|
||||
|
||||
if (totalArgLength <= MSG_MGR_CONSOLE_MAX_SIZE) {
|
||||
msgData.arguments.push(arg);
|
||||
} else {
|
||||
// arguments take up too much space
|
||||
msgData.arguments = ["<truncated>"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cpmm.sendAsyncMessage("Console:Log", msgData);
|
||||
break;
|
||||
}
|
||||
|
||||
case "xpcom-shutdown":
|
||||
this.uninit();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
cpmm.removeMessageListener("DevTools:StopForwardingContentProcessMessage", this);
|
||||
}
|
||||
};
|
||||
|
||||
// loadProcessScript loads in all processes, including the parent,
|
||||
// in which we don't need any forwarding
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
new ContentProcessForward();
|
||||
}
|
||||
|
@ -8,13 +8,16 @@ const {Cc, Ci, components} = require("chrome");
|
||||
const {isWindowIncluded} = require("devtools/shared/layout/utils");
|
||||
const Services = require("Services");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {CONSOLE_WORKER_IDS, WebConsoleUtils} = require("devtools/server/actors/utils/webconsole-utils");
|
||||
const {CONSOLE_WORKER_IDS, WebConsoleUtils} = require("devtools/server/actors/webconsole/utils");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this,
|
||||
"swm",
|
||||
"@mozilla.org/serviceworkers/manager;1",
|
||||
"nsIServiceWorkerManager");
|
||||
|
||||
// Process script used to forward console calls from content processes to parent process
|
||||
const CONTENT_PROCESS_SCRIPT = "resource://devtools/server/actors/webconsole/content-process-forward.js";
|
||||
|
||||
// The page errors listener
|
||||
|
||||
/**
|
||||
@ -451,3 +454,39 @@ ConsoleReflowListener.prototype =
|
||||
this.listener = this.docshell = null;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Forward console message calls from content processes to the parent process.
|
||||
* Used by Browser console and toolbox to see messages from all processes.
|
||||
*
|
||||
* @constructor
|
||||
* @param object owner
|
||||
* The listener owner which needs to implement:
|
||||
* - onConsoleAPICall(message)
|
||||
*/
|
||||
function ContentProcessListener(listener) {
|
||||
this.listener = listener;
|
||||
|
||||
Services.ppmm.addMessageListener("Console:Log", this);
|
||||
Services.ppmm.loadProcessScript(CONTENT_PROCESS_SCRIPT, true);
|
||||
}
|
||||
|
||||
exports.ContentProcessListener = ContentProcessListener;
|
||||
|
||||
ContentProcessListener.prototype = {
|
||||
receiveMessage(message) {
|
||||
let logMsg = message.data;
|
||||
logMsg.wrappedJSObject = logMsg;
|
||||
this.listener.onConsoleAPICall(logMsg);
|
||||
},
|
||||
|
||||
destroy() {
|
||||
// Tell the content processes to stop listening and forwarding messages
|
||||
Services.ppmm.broadcastAsyncMessage("DevTools:StopForwardingContentProcessMessage");
|
||||
|
||||
Services.ppmm.removeMessageListener("Console:Log", this);
|
||||
Services.ppmm.removeDelayedProcessScript(CONTENT_PROCESS_SCRIPT);
|
||||
|
||||
this.listener = null;
|
||||
}
|
||||
};
|
12
devtools/server/actors/webconsole/moz.build
Normal file
@ -0,0 +1,12 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'content-process-forward.js',
|
||||
'listeners.js',
|
||||
'utils.js',
|
||||
'worker-listeners.js',
|
||||
)
|
@ -34,6 +34,7 @@ support-files =
|
||||
[test_css-logic.html]
|
||||
[test_css-logic-media-queries.html]
|
||||
[test_css-logic-specificity.html]
|
||||
fail-if = stylo # bug 1387905
|
||||
[test_css-properties.html]
|
||||
[test_Debugger.Source.prototype.introductionScript.html]
|
||||
[test_Debugger.Source.prototype.introductionType.html]
|
||||
|
@ -4,7 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
const { console, ConsoleAPI } = require("resource://gre/modules/Console.jsm");
|
||||
const { ConsoleAPIListener } = require("devtools/server/actors/utils/webconsole-listeners");
|
||||
const { ConsoleAPIListener } = require("devtools/server/actors/webconsole/listeners");
|
||||
const Services = require("Services");
|
||||
|
||||
var seenMessages = 0;
|
||||
|
@ -97,7 +97,7 @@ function doConsoleCalls() {
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var {ConsoleServiceListener, ConsoleAPIListener} =
|
||||
require("devtools/server/actors/utils/webconsole-listeners");
|
||||
require("devtools/server/actors/webconsole/listeners");
|
||||
|
||||
let consoleAPIListener, consoleServiceListener;
|
||||
let consoleAPICalls = 0;
|
||||
|
@ -18,7 +18,7 @@ SimpleTest.waitForExplicitFinish();
|
||||
let gState;
|
||||
let tests;
|
||||
|
||||
let {WebConsoleCommands} = require("devtools/server/actors/utils/webconsole-utils");
|
||||
let {WebConsoleCommands} = require("devtools/server/actors/webconsole/utils");
|
||||
|
||||
function evaluateJS(input) {
|
||||
return new Promise((resolve) => gState.client.evaluateJS(input, resolve));
|
||||
|
@ -4123,8 +4123,11 @@ Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32
|
||||
|
||||
void
|
||||
Element::ClearServoData() {
|
||||
MOZ_ASSERT(IsStyledByServo());
|
||||
#ifdef MOZ_STYLO
|
||||
Servo_Element_ClearData(this);
|
||||
UnsetFlags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO |
|
||||
ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
|
||||
#else
|
||||
MOZ_CRASH("Accessing servo node data in non-stylo build");
|
||||
#endif
|
||||
|
@ -605,14 +605,24 @@ Selection::GetTableCellLocationFromRange(nsRange* aRange,
|
||||
if (!content)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsIContent *child = content->GetChildAt(aRange->StartOffset());
|
||||
nsCOMPtr<nsIContent> child = content->GetChildAt(aRange->StartOffset());
|
||||
if (!child)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// GetCellLayout depends on current frame, we need flush frame to get
|
||||
// nsITableCellLayout
|
||||
nsCOMPtr<nsIPresShell> presShell = mFrameSelection->GetShell();
|
||||
if (presShell) {
|
||||
presShell->FlushPendingNotifications(FlushType::Frames);
|
||||
|
||||
// Since calling FlushPendingNotifications, so check whether disconnected.
|
||||
if (!mFrameSelection || !mFrameSelection->GetShell()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
//Note: This is a non-ref-counted pointer to the frame
|
||||
nsITableCellLayout *cellLayout = mFrameSelection->GetCellLayout(child);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
if (!cellLayout)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -2276,6 +2286,9 @@ Selection::AddRangeInternal(nsRange& aRange, nsIDocument* aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
// AddTableCellRange might flush frame.
|
||||
RefPtr<Selection> kungFuDeathGrip(this);
|
||||
|
||||
// This inserts a table cell range in proper document order
|
||||
// and returns NS_OK if range doesn't contain just one table cell
|
||||
bool didAddRange;
|
||||
|
@ -13219,7 +13219,10 @@ nsIDocument::UpdateStyleBackendType()
|
||||
|
||||
#ifdef MOZ_STYLO
|
||||
if (nsLayoutUtils::StyloEnabled()) {
|
||||
if (!mDocumentContainer) {
|
||||
if (IsBeingUsedAsImage()) {
|
||||
// Enable stylo for SVG-as-image.
|
||||
mStyleBackendType = StyleBackendType::Servo;
|
||||
} else if (!mDocumentContainer) {
|
||||
NS_WARNING("stylo: No docshell yet, assuming Gecko style system");
|
||||
} else if ((IsHTMLOrXHTML() || IsSVGDocument()) &&
|
||||
IsContentDocument()) {
|
||||
|
@ -313,6 +313,7 @@ skip-if = toolkit == 'android'
|
||||
[test_bug338583.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug338679.html]
|
||||
fail-if = stylo # bug 1370779
|
||||
[test_bug339494.html]
|
||||
[test_bug339494.xhtml]
|
||||
[test_bug340571.html]
|
||||
@ -620,6 +621,7 @@ skip-if = toolkit == 'android'
|
||||
[test_bug1314032.html]
|
||||
[test_bug1318303.html]
|
||||
[test_bug1375050.html]
|
||||
[test_bug1381710.html]
|
||||
[test_bug1384658.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_caretPositionFromPoint.html]
|
||||
@ -680,6 +682,7 @@ skip-if = (toolkit == 'android') # Android: Bug 775227
|
||||
[test_innersize_scrollport.html]
|
||||
[test_integer_attr_with_leading_zero.html]
|
||||
[test_intersectionobservers.html]
|
||||
skip-if = stylo # timeout bug 1384001
|
||||
[test_link_prefetch.html]
|
||||
skip-if = !e10s # Track Bug 1281415
|
||||
[test_link_stylesheet.html]
|
||||
@ -703,6 +706,7 @@ skip-if = (os != 'android') # meta-viewport tag support is mobile-only
|
||||
[test_mozbrowser_apis_blocked.html]
|
||||
[test_mozMatchesSelector.html]
|
||||
[test_mutationobserver_anonymous.html]
|
||||
skip-if = stylo # bug 1383985
|
||||
[test_mutationobservers.html]
|
||||
[test_named_frames.html]
|
||||
[test_navigator_hardwareConcurrency.html]
|
||||
|
40
dom/base/test/test_bug1381710.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1381710
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Mozilla Bug 1381710</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1381710">Mozilla Bug 1381710</a>
|
||||
<div id="content">
|
||||
<div id="nonedit"></div>
|
||||
<div id="edit" contenteditable=true></div>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
function test(element)
|
||||
{
|
||||
let selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
let range = document.createRange();
|
||||
|
||||
element.innerHTML = "<table><tr id=tr><td id=td>A</td><td>B</td><tr></table>";
|
||||
let td = document.getElementById("td");
|
||||
range.selectNode(td);
|
||||
// Don't throw exception
|
||||
selection.addRange(range);
|
||||
is(selection.anchorNode, document.getElementById("tr"),
|
||||
"anchor node should be <TR> element");
|
||||
element.innerHTML = "";
|
||||
}
|
||||
|
||||
test(document.getElementById("nonedit"));
|
||||
test(document.getElementById("edit"));
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -77,6 +77,15 @@ function shouldSkipTest(test) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SpecialPowers.DOMWindowUtils.isStyledByServo &&
|
||||
SpecialPowers.isDebugBuild &&
|
||||
navigator.platform.indexOf('Mac') >= 0) {
|
||||
if (test == "file_fullscreen-backdrop.html") {
|
||||
todo(false, `${test} skipped due to bug 1387942`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,10 @@
|
||||
#include "GMPServiceChild.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
#include "mozilla/Omnijar.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
#include "ChildProfilerController.h"
|
||||
#endif
|
||||
@ -172,6 +176,14 @@
|
||||
#include "mozilla/audio/AudioNotificationReceiver.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
// Info.plist key associated with the developer repo path
|
||||
#define MAC_DEV_REPO_KEY "MozillaDeveloperRepoPath"
|
||||
// Info.plist key associated with the developer repo object directory
|
||||
#define MAC_DEV_OBJ_KEY "MozillaDeveloperObjPath"
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
#ifdef MOZ_X11
|
||||
#include "mozilla/X11Util.h"
|
||||
#endif
|
||||
@ -3563,4 +3575,125 @@ ContentChild::GetSpecificMessageEventTarget(const Message& aMsg)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
bool IsDevelopmentBuild()
|
||||
{
|
||||
nsCOMPtr<nsIFile> path = mozilla::Omnijar::GetPath(mozilla::Omnijar::GRE);
|
||||
// If the path doesn't exist, we're a dev build.
|
||||
return path == nullptr;
|
||||
}
|
||||
#endif /* !XP_WIN */
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
/*
|
||||
* Helper function to read a string value for a given key from the .app's
|
||||
* Info.plist.
|
||||
*/
|
||||
static nsresult
|
||||
GetStringValueFromBundlePlist(const nsAString& aKey, nsAutoCString& aValue)
|
||||
{
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
if (mainBundle == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Read this app's bundle Info.plist as a dictionary
|
||||
CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(mainBundle);
|
||||
if (bundleInfoDict == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoCString keyAutoCString = NS_ConvertUTF16toUTF8(aKey);
|
||||
CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
keyAutoCString.get(),
|
||||
kCFStringEncodingUTF8);
|
||||
if (key == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CFStringRef value = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, key);
|
||||
CFRelease(key);
|
||||
if (value == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CFIndex valueLength = CFStringGetLength(value);
|
||||
if (valueLength == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const char* valueCString = CFStringGetCStringPtr(value,
|
||||
kCFStringEncodingUTF8);
|
||||
if (valueCString) {
|
||||
aValue.Assign(valueCString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CFIndex maxLength =
|
||||
CFStringGetMaximumSizeForEncoding(valueLength, kCFStringEncodingUTF8) + 1;
|
||||
char* valueBuffer = static_cast<char*>(moz_xmalloc(maxLength));
|
||||
if (!valueBuffer) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!CFStringGetCString(value, valueBuffer, maxLength,
|
||||
kCFStringEncodingUTF8)) {
|
||||
free(valueBuffer);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aValue.Assign(valueBuffer);
|
||||
free(valueBuffer);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for reading a path string from the .app's Info.plist
|
||||
* and returning a directory object for that path with symlinks resolved.
|
||||
*/
|
||||
static nsresult
|
||||
GetDirFromBundlePlist(const nsAString& aKey, nsIFile **aDir)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString dirPath;
|
||||
rv = GetStringValueFromBundlePlist(aKey, dirPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> dir;
|
||||
rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(dirPath),
|
||||
false,
|
||||
getter_AddRefs(dir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = dir->Normalize();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isDirectory = false;
|
||||
rv = dir->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!isDirectory) {
|
||||
return NS_ERROR_FILE_NOT_DIRECTORY;
|
||||
}
|
||||
|
||||
dir.swap(*aDir);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetRepoDir(nsIFile **aRepoDir)
|
||||
{
|
||||
MOZ_ASSERT(IsDevelopmentBuild());
|
||||
return GetDirFromBundlePlist(NS_LITERAL_STRING(MAC_DEV_REPO_KEY), aRepoDir);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetObjDir(nsIFile **aObjDir)
|
||||
{
|
||||
MOZ_ASSERT(IsDevelopmentBuild());
|
||||
return GetDirFromBundlePlist(NS_LITERAL_STRING(MAC_DEV_OBJ_KEY), aObjDir);
|
||||
}
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -40,6 +40,23 @@ class ChildProfilerController;
|
||||
|
||||
using mozilla::loader::PScriptCacheChild;
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
// Returns whether or not the currently running build is an unpackaged
|
||||
// developer build. This check is implemented by looking for omni.ja in the
|
||||
// the obj/dist dir. We use this routine to detect when the build dir will
|
||||
// use symlinks to the repo and object dir. On Windows, dev builds don't
|
||||
// use symlinks.
|
||||
bool IsDevelopmentBuild();
|
||||
#endif /* !XP_WIN */
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// Return the repo directory and the repo object directory respectively. These
|
||||
// should only be used on Mac developer builds to determine the path to the
|
||||
// repo or object directory.
|
||||
nsresult GetRepoDir(nsIFile **aRepoDir);
|
||||
nsresult GetObjDir(nsIFile **aObjDir);
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
namespace ipc {
|
||||
class OptionalURIParams;
|
||||
class URIParams;
|
||||
|
@ -43,8 +43,6 @@ private:
|
||||
return principal.forget();
|
||||
}
|
||||
// These methods are called off the main thread.
|
||||
// The mode is initially MODE_PLAYBACK.
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override {}
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer,
|
||||
uint32_t aCount, uint32_t* aBytes) override
|
||||
{
|
||||
|
@ -254,6 +254,9 @@ ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
||||
rv = OpenResource(aStreamListener);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set mode to METADATA since we are about to read metadata.
|
||||
mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
|
||||
|
||||
SetStateMachine(CreateStateMachine());
|
||||
NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
|
||||
|
||||
@ -501,6 +504,17 @@ ChannelMediaDecoder::Resume()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaDecoder::MetadataLoaded(
|
||||
UniquePtr<MediaInfo> aInfo,
|
||||
UniquePtr<MetadataTags> aTags,
|
||||
MediaDecoderEventVisibility aEventVisibility)
|
||||
{
|
||||
MediaDecoder::MetadataLoaded(Move(aInfo), Move(aTags), aEventVisibility);
|
||||
// Set mode to PLAYBACK after reading metadata.
|
||||
mResource->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// avoid redefined macro in unified build
|
||||
|
@ -57,6 +57,10 @@ protected:
|
||||
void OnPlaybackEvent(MediaEventType aEvent) override;
|
||||
void DurationChanged() override;
|
||||
void DownloadProgressed() override;
|
||||
void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
|
||||
UniquePtr<MetadataTags> aTags,
|
||||
MediaDecoderEventVisibility aEventVisibility) override;
|
||||
|
||||
RefPtr<ResourceCallback> mResourceCallback;
|
||||
RefPtr<BaseMediaResource> mResource;
|
||||
|
||||
|
@ -2124,14 +2124,6 @@ MediaCacheStream::Close()
|
||||
mMediaCache->QueueUpdate();
|
||||
}
|
||||
|
||||
void
|
||||
MediaCacheStream::EnsureCacheUpdate()
|
||||
{
|
||||
if (mHasHadUpdate)
|
||||
return;
|
||||
mMediaCache->Update();
|
||||
}
|
||||
|
||||
void
|
||||
MediaCacheStream::CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor)
|
||||
{
|
||||
|
@ -232,11 +232,6 @@ public:
|
||||
// Get the principal for this stream. Anything accessing the contents of
|
||||
// this stream must have a principal that subsumes this principal.
|
||||
nsIPrincipal* GetCurrentPrincipal() { return mPrincipal; }
|
||||
// Ensure a global media cache update has run with this stream present.
|
||||
// This ensures the cache has had a chance to suspend or unsuspend this stream.
|
||||
// Called only on main thread. This can change the state of streams, fire
|
||||
// notifications, etc.
|
||||
void EnsureCacheUpdate();
|
||||
|
||||
// These callbacks are called on the main thread by the client
|
||||
// when data has been received via the channel.
|
||||
|
@ -812,9 +812,6 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
|
||||
|
||||
Invalidate();
|
||||
|
||||
// This can run cache callbacks.
|
||||
GetResource()->EnsureCacheUpToDate();
|
||||
|
||||
// The element can run javascript via events
|
||||
// before reaching here, so only change the
|
||||
// state if we're still set to the original
|
||||
@ -823,10 +820,6 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
|
||||
ChangeState(mNextState);
|
||||
}
|
||||
|
||||
// Run NotifySuspendedStatusChanged now to give us a chance to notice
|
||||
// that autoplay should run.
|
||||
NotifySuspendedStatusChanged();
|
||||
|
||||
// GetOwner()->FirstFrameLoaded() might call us back. Put it at the bottom of
|
||||
// this function to avoid unexpected shutdown from reentrant calls.
|
||||
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
|
||||
|
@ -450,6 +450,12 @@ protected:
|
||||
|
||||
virtual void OnPlaybackEvent(MediaEventType aEvent);
|
||||
|
||||
// Called when the metadata from the media file has been loaded by the
|
||||
// state machine. Call on the main thread only.
|
||||
virtual void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
|
||||
UniquePtr<MetadataTags> aTags,
|
||||
MediaDecoderEventVisibility aEventVisibility);
|
||||
|
||||
/******
|
||||
* The following members should be accessed with the decoder lock held.
|
||||
******/
|
||||
@ -490,12 +496,6 @@ protected:
|
||||
private:
|
||||
nsCString GetDebugInfo();
|
||||
|
||||
// Called when the metadata from the media file has been loaded by the
|
||||
// state machine. Call on the main thread only.
|
||||
void MetadataLoaded(UniquePtr<MediaInfo> aInfo,
|
||||
UniquePtr<MetadataTags> aTags,
|
||||
MediaDecoderEventVisibility aEventVisibility);
|
||||
|
||||
// Called when the owner's activity changed.
|
||||
void NotifyCompositor();
|
||||
|
||||
|
@ -341,9 +341,6 @@ public:
|
||||
MOZ_ASSERT(!mMetadataRequest.Exists());
|
||||
SLOG("Dispatching AsyncReadMetadata");
|
||||
|
||||
// Set mode to METADATA since we are about to read metadata.
|
||||
Resource()->SetReadMode(MediaCacheStream::MODE_METADATA);
|
||||
|
||||
// We disconnect mMetadataRequest in Exit() so it is fine to capture
|
||||
// a raw pointer here.
|
||||
Reader()->ReadMetadata()
|
||||
@ -1867,17 +1864,23 @@ public:
|
||||
|
||||
void HandleAudioDecoded(AudioData* aAudio) override
|
||||
{
|
||||
mMaster->PushAudio(aAudio);
|
||||
if (!mMaster->HaveEnoughDecodedAudio()) {
|
||||
mMaster->RequestAudioData();
|
||||
}
|
||||
// This might be the sample we need to exit buffering.
|
||||
// Schedule Step() to check it.
|
||||
mMaster->PushAudio(aAudio);
|
||||
mMaster->ScheduleStateMachine();
|
||||
}
|
||||
|
||||
void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart) override
|
||||
{
|
||||
mMaster->PushVideo(aVideo);
|
||||
if (!mMaster->HaveEnoughDecodedVideo()) {
|
||||
mMaster->RequestVideoData(media::TimeUnit());
|
||||
}
|
||||
// This might be the sample we need to exit buffering.
|
||||
// Schedule Step() to check it.
|
||||
mMaster->PushVideo(aVideo);
|
||||
mMaster->ScheduleStateMachine();
|
||||
}
|
||||
|
||||
@ -1924,8 +1927,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void DispatchDecodeTasksIfNeeded();
|
||||
|
||||
TimeStamp mBufferingStart;
|
||||
|
||||
// The maximum number of second we spend buffering when we are short on
|
||||
@ -2224,9 +2225,6 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder&& aMetadata)
|
||||
{
|
||||
mMetadataRequest.Complete();
|
||||
|
||||
// Set mode to PLAYBACK after reading metadata.
|
||||
Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
|
||||
|
||||
mMaster->mInfo.emplace(*aMetadata.mInfo);
|
||||
mMaster->mMediaSeekable = Info().mMediaSeekable;
|
||||
mMaster->mMediaSeekableOnlyInBufferedRanges =
|
||||
@ -2542,25 +2540,6 @@ SeekingState::SeekCompleted()
|
||||
GoToNextState();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::
|
||||
BufferingState::DispatchDecodeTasksIfNeeded()
|
||||
{
|
||||
if (mMaster->IsAudioDecoding()
|
||||
&& !mMaster->HaveEnoughDecodedAudio()
|
||||
&& !mMaster->IsRequestingAudioData()
|
||||
&& !mMaster->IsWaitingAudioData()) {
|
||||
mMaster->RequestAudioData();
|
||||
}
|
||||
|
||||
if (mMaster->IsVideoDecoding()
|
||||
&& !mMaster->HaveEnoughDecodedVideo()
|
||||
&& !mMaster->IsRequestingVideoData()
|
||||
&& !mMaster->IsWaitingVideoData()) {
|
||||
mMaster->RequestVideoData(media::TimeUnit());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::
|
||||
BufferingState::Step()
|
||||
@ -2582,11 +2561,9 @@ BufferingState::Step()
|
||||
SLOG("Buffering: wait %ds, timeout in %.3lfs",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds());
|
||||
mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
return;
|
||||
}
|
||||
} else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
MOZ_ASSERT(!mMaster->OutOfDecodedAudio()
|
||||
|| mMaster->IsRequestingAudioData()
|
||||
|| mMaster->IsWaitingAudioData());
|
||||
|
@ -975,12 +975,6 @@ ChannelMediaResource::IsDataCachedToEndOfResource(int64_t aOffset)
|
||||
return mCacheStream.IsDataCachedToEndOfStream(aOffset);
|
||||
}
|
||||
|
||||
void
|
||||
ChannelMediaResource::EnsureCacheUpToDate()
|
||||
{
|
||||
mCacheStream.EnsureCacheUpdate();
|
||||
}
|
||||
|
||||
bool
|
||||
ChannelMediaResource::IsSuspendedByCache()
|
||||
{
|
||||
|
@ -164,8 +164,6 @@ public:
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
|
||||
|
||||
// These methods are called off the main thread.
|
||||
// The mode is initially MODE_PLAYBACK.
|
||||
virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0;
|
||||
// Read up to aCount bytes from the stream. The read starts at
|
||||
// aOffset in the stream, seeking to that location initially if
|
||||
// it is not the current stream offset. The remaining arguments,
|
||||
@ -194,9 +192,6 @@ public:
|
||||
// media.
|
||||
// A call to ReadAt will update this position.
|
||||
virtual int64_t Tell() = 0;
|
||||
// Ensures that the value returned by IsSuspendedByCache below is up to date
|
||||
// (i.e. the cache has examined this stream at least once).
|
||||
virtual void EnsureCacheUpToDate() {}
|
||||
|
||||
// These can be called on any thread.
|
||||
// Cached blocks associated with this stream will not be evicted
|
||||
@ -325,6 +320,9 @@ public:
|
||||
// Resume any downloads that have been suspended.
|
||||
virtual void Resume() = 0;
|
||||
|
||||
// The mode is initially MODE_PLAYBACK.
|
||||
virtual void SetReadMode(MediaCacheStream::ReadMode aMode) = 0;
|
||||
|
||||
/**
|
||||
* Open the stream. This creates a stream listener and returns it in
|
||||
* aStreamListener; this listener needs to be notified of incoming data.
|
||||
@ -507,7 +505,6 @@ public:
|
||||
already_AddRefed<BaseMediaResource> CloneData(
|
||||
MediaResourceCallback* aDecoder) override;
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
|
||||
void EnsureCacheUpToDate() override;
|
||||
|
||||
// Other thread
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override;
|
||||
|
@ -20,7 +20,6 @@ public:
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override {}
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
|
||||
uint32_t* aBytes) override;
|
||||
// Data stored in file, caching recommended.
|
||||
|
@ -48,7 +48,6 @@ public:
|
||||
~HLSResource();
|
||||
void Suspend();
|
||||
void Resume();
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override { UNIMPLEMENTED(); }
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
|
||||
bool ShouldCacheReads() override { UNIMPLEMENTED(); return false; }
|
||||
int64_t Tell() override { UNIMPLEMENTED(); return -1; }
|
||||
|
@ -32,7 +32,6 @@ public:
|
||||
, mEnded(false)
|
||||
{}
|
||||
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override { UNIMPLEMENTED(); }
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
|
||||
bool ShouldCacheReads() override { UNIMPLEMENTED(); return false; }
|
||||
int64_t Tell() override { UNIMPLEMENTED(); return -1; }
|
||||
|
@ -45,10 +45,6 @@ public:
|
||||
UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
}
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode) override
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
nsresult ReadAt(int64_t aOffset,
|
||||
char* aBuffer,
|
||||
uint32_t aCount,
|
||||
|
@ -27,7 +27,7 @@ function manifestVideo() {
|
||||
// name "mochi.test".
|
||||
let serverUrl = SpecialPowers.Services.prefs.getCharPref("media.hls.server.url");
|
||||
var gHLSTests = [
|
||||
{ name: serverUrl + "/bipbop_4x3_variant.m3u8", type:"audio/x-mpegurl", duration:19.95334 }
|
||||
{ name: serverUrl + "/bipbop_4x3_variant.m3u8", type:"audio/x-mpegurl", duration:20.000 }
|
||||
];
|
||||
|
||||
// These are small test files, good for just seeing if something loads. We
|
||||
|
@ -1,3 +1,3 @@
|
||||
skip-if(Android) fuzzy-if(OSX,22,49977) skip-if(winWidget) fuzzy-if(webrender,70,600) HTTP(..) == short.mp4.firstframe.html short.mp4.firstframe-ref.html
|
||||
skip-if(Android) fuzzy-if(OSX,23,51392) fuzzy-if(winWidget,59,76797) fuzzy-if(webrender,60,1800) HTTP(..) == short.mp4.lastframe.html short.mp4.lastframe-ref.html
|
||||
skip-if(Android) skip-if(winWidget) fuzzy-if(webrender,55,4281) fuzzy-if(OSX,3,111852) HTTP(..) == bipbop_300_215kbps.mp4.lastframe.html bipbop_300_215kbps.mp4.lastframe-ref.html
|
||||
skip-if(Android) fuzzy-if(OSX,22,49977) skip-if(winWidget) fuzzy-if(gtkWidget&&layersGPUAccelerated,70,600) HTTP(..) == short.mp4.firstframe.html short.mp4.firstframe-ref.html
|
||||
skip-if(Android) fuzzy-if(OSX,23,51392) fuzzy-if(winWidget,59,76797) fuzzy-if(gtkWidget&&layersGPUAccelerated,60,1800) HTTP(..) == short.mp4.lastframe.html short.mp4.lastframe-ref.html
|
||||
skip-if(Android) skip-if(winWidget) fuzzy-if(gtkWidget&&layersGPUAccelerated,55,4281) fuzzy-if(OSX,3,111852) HTTP(..) == bipbop_300_215kbps.mp4.lastframe.html bipbop_300_215kbps.mp4.lastframe-ref.html
|
||||
|
@ -217,6 +217,18 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
|
||||
return object.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<AudioContext>
|
||||
AudioContext::Constructor(const GlobalObject& aGlobal,
|
||||
const OfflineAudioContextOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return Constructor(aGlobal,
|
||||
aOptions.mNumberOfChannels,
|
||||
aOptions.mLength,
|
||||
aOptions.mSampleRate,
|
||||
aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<AudioContext>
|
||||
AudioContext::Constructor(const GlobalObject& aGlobal,
|
||||
uint32_t aNumberOfChannels,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef AudioContext_h_
|
||||
#define AudioContext_h_
|
||||
|
||||
#include "mozilla/dom/OfflineAudioContextBinding.h"
|
||||
#include "MediaBufferDecoder.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
@ -152,6 +153,12 @@ public:
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
// Constructor for offline AudioContext with options object
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const OfflineAudioContextOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Constructor for offline AudioContext
|
||||
static already_AddRefed<AudioContext>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
|
@ -31,17 +31,28 @@ function setOrCompareRenderedBuffer(aRenderedBuffer) {
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var ctx = new OfflineAudioContext(2, 100, 22050);
|
||||
ok(ctx instanceof EventTarget, "OfflineAudioContexts must be EventTargets");
|
||||
is(ctx.length, 100, "OfflineAudioContext.length is equal to the value passed to the ctor.");
|
||||
let ctxs = [
|
||||
new OfflineAudioContext(2, 100, 22050),
|
||||
new OfflineAudioContext({length: 100, sampleRate: 22050}),
|
||||
new OfflineAudioContext({channels: 2, length: 100, sampleRate: 22050}),
|
||||
];
|
||||
|
||||
var buf = ctx.createBuffer(2, 100, ctx.sampleRate);
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
for (var j = 0; j < 100; ++j) {
|
||||
buf.getChannelData(i)[j] = Math.sin(2 * Math.PI * 200 * j / ctx.sampleRate);
|
||||
for (let ctx of ctxs) {
|
||||
ok(ctx instanceof EventTarget, "OfflineAudioContexts must be EventTargets");
|
||||
is(ctx.length, 100, "OfflineAudioContext.length is equal to the value passed to the ctor.");
|
||||
|
||||
var buf = ctx.createBuffer(2, 100, ctx.sampleRate);
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
for (var j = 0; j < 100; ++j) {
|
||||
buf.getChannelData(i)[j] = Math.sin(2 * Math.PI * 200 * j / ctx.sampleRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is(ctxs[1].destination.channelCount, 1, "OfflineAudioContext defaults to to correct channelCount.");
|
||||
|
||||
let ctx = ctxs[0];
|
||||
|
||||
expectException(function() {
|
||||
new OfflineAudioContext(2, 100, 0);
|
||||
}, DOMException.NOT_SUPPORTED_ERR);
|
||||
@ -58,6 +69,15 @@ addLoadEvent(function() {
|
||||
expectException(function() {
|
||||
new OfflineAudioContext(2, 0, 44100);
|
||||
}, DOMException.NOT_SUPPORTED_ERR);
|
||||
expectTypeError(function() {
|
||||
new OfflineAudioContext({});
|
||||
});
|
||||
expectTypeError(function() {
|
||||
new OfflineAudioContext({sampleRate: 44100});
|
||||
});
|
||||
expectTypeError(function() {
|
||||
new OfflineAudioContext({length: 44100*40});
|
||||
});
|
||||
|
||||
var src = ctx.createBufferSource();
|
||||
src.buffer = buf;
|
||||
|
@ -50,9 +50,8 @@ VREventObserver::DisconnectFromOwner()
|
||||
// The WebVR content is closed, and we will collect the telemetry info
|
||||
// for the users who view it in 2D view only.
|
||||
Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 0);
|
||||
Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPEND_FOR_VIEWING_IN_2D,
|
||||
static_cast<uint32_t>((TimeStamp::Now() - mSpendTimeIn2DView)
|
||||
.ToMilliseconds()));
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_2D,
|
||||
mSpendTimeIn2DView);
|
||||
}
|
||||
mWindow = nullptr;
|
||||
|
||||
|
@ -10,7 +10,14 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor(unsigned long numberOfChannels, unsigned long length, float sampleRate),
|
||||
dictionary OfflineAudioContextOptions {
|
||||
unsigned long numberOfChannels = 1;
|
||||
required unsigned long length;
|
||||
required float sampleRate;
|
||||
};
|
||||
|
||||
[Constructor (OfflineAudioContextOptions contextOptions),
|
||||
Constructor(unsigned long numberOfChannels, unsigned long length, float sampleRate),
|
||||
Pref="dom.webaudio.enabled"]
|
||||
interface OfflineAudioContext : BaseAudioContext {
|
||||
|
||||
|
@ -198,8 +198,7 @@ CompositionTransaction::SetIMESelection(EditorBase& aEditorBase,
|
||||
RefPtr<Selection> selection = aEditorBase.GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv = selection->StartBatchChanges();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
SelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// First, remove all selections of IME composition.
|
||||
static const RawSelectionType kIMESelections[] = {
|
||||
@ -213,6 +212,7 @@ CompositionTransaction::SetIMESelection(EditorBase& aEditorBase,
|
||||
aEditorBase.GetSelectionController(getter_AddRefs(selCon));
|
||||
NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
for (uint32_t i = 0; i < ArrayLength(kIMESelections); ++i) {
|
||||
nsCOMPtr<nsISelection> selectionOfIME;
|
||||
if (NS_FAILED(selCon->GetSelection(kIMESelections[i],
|
||||
@ -335,9 +335,6 @@ CompositionTransaction::SetIMESelection(EditorBase& aEditorBase,
|
||||
}
|
||||
}
|
||||
|
||||
rv = selection->EndBatchChangesInternal();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to end batch changes");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -724,7 +724,7 @@ EditorBase::DoTransaction(Selection* aSelection, nsITransaction* aTxn)
|
||||
RefPtr<Selection> selection = aSelection ? aSelection : GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
|
||||
selection->StartBatchChanges();
|
||||
SelectionBatcher selectionBatcher(selection);
|
||||
|
||||
nsresult rv;
|
||||
if (mTxnMgr) {
|
||||
@ -733,14 +733,11 @@ EditorBase::DoTransaction(Selection* aSelection, nsITransaction* aTxn)
|
||||
} else {
|
||||
rv = aTxn->DoTransaction();
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DoAfterDoTransaction(aTxn);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// no need to check rv here, don't lose result of operation
|
||||
selection->EndBatchChanges();
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
DoAfterDoTransaction(aTxn);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1261,7 +1261,13 @@ DrawTargetSkia::FillGlyphsWithCG(ScaledFont *aFont,
|
||||
return false;
|
||||
}
|
||||
|
||||
SetFontSmoothingBackgroundColor(cgContext, mColorSpace, aRenderingOptions);
|
||||
if (mPushedLayers.empty()) {
|
||||
// Respect the font smoothing background color, but only if no layer is
|
||||
// currently pushed, because this color usually describes what's under this
|
||||
// DrawTarget, and not what's within this DrawTarget under the currently
|
||||
// pushed layer.
|
||||
SetFontSmoothingBackgroundColor(cgContext, mColorSpace, aRenderingOptions);
|
||||
}
|
||||
SetFontColor(cgContext, mColorSpace, aPattern);
|
||||
|
||||
ScaledFontMac* macFont = static_cast<ScaledFontMac*>(aFont);
|
||||
|
@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
|
||||
the need to run the cargo update command in js/src as well. Hopefully this will
|
||||
be resolved soon.
|
||||
|
||||
Latest Commit: 0748e02d1be5f889fc17de2eb81c0c363ee3aa80
|
||||
Latest Commit: e68c8acb021656440d26ac46e705e7ceb31891e6
|
||||
|
@ -463,6 +463,9 @@ CompositorBridgeParent::StopAndClearResources()
|
||||
});
|
||||
mWrBridge->Destroy();
|
||||
mWrBridge = nullptr;
|
||||
mAsyncImageManager->Destroy();
|
||||
// WebRenderAPI should be already destructed
|
||||
mAsyncImageManager = nullptr;
|
||||
}
|
||||
|
||||
if (mCompositor) {
|
||||
@ -1654,8 +1657,9 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
|
||||
ScheduleComposition();
|
||||
}
|
||||
if (mWrBridge && sIndirectLayerTrees[child].mWrBridge) {
|
||||
RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI()->Clone();
|
||||
sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
|
||||
mWrBridge->GetWebRenderAPI(),
|
||||
api,
|
||||
mWrBridge->AsyncImageManager(),
|
||||
GetAnimationStorage());
|
||||
// Pretend we composited, since parent CompositorBridgeParent was replaced.
|
||||
@ -1695,8 +1699,6 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
|
||||
RefPtr<widget::CompositorWidget> widget = mWidget;
|
||||
RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(
|
||||
gfxPrefs::WebRenderProfilerEnabled(), this, Move(widget), aSize);
|
||||
RefPtr<AsyncImagePipelineManager> asyncMgr =
|
||||
new AsyncImagePipelineManager(WebRenderBridgeParent::AllocIdNameSpace());
|
||||
if (!api) {
|
||||
mWrBridge = WebRenderBridgeParent::CreateDestroyed();
|
||||
mWrBridge.get()->AddRef(); // IPDL reference
|
||||
@ -1704,6 +1706,8 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
|
||||
*aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
|
||||
return mWrBridge;
|
||||
}
|
||||
mAsyncImageManager = new AsyncImagePipelineManager(api->Clone());
|
||||
RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager;
|
||||
api->SetRootPipeline(aPipelineId);
|
||||
RefPtr<CompositorAnimationStorage> animStorage = GetAnimationStorage();
|
||||
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(asyncMgr), Move(animStorage));
|
||||
@ -1953,10 +1957,10 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
|
||||
void
|
||||
CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
|
||||
{
|
||||
if (!mWrBridge) {
|
||||
if (!mWrBridge || !mAsyncImageManager) {
|
||||
return;
|
||||
}
|
||||
mWrBridge->AsyncImageManager()->Update(aPipelineId, aEpoch);
|
||||
mAsyncImageManager->Update(aPipelineId, aEpoch);
|
||||
|
||||
if (mPaused) {
|
||||
return;
|
||||
|
@ -65,6 +65,7 @@ namespace layers {
|
||||
class APZCTreeManager;
|
||||
class APZCTreeManagerParent;
|
||||
class AsyncCompositionManager;
|
||||
class AsyncImagePipelineManager;
|
||||
class Compositor;
|
||||
class CompositorAnimationStorage;
|
||||
class CompositorBridgeParent;
|
||||
@ -580,6 +581,7 @@ protected:
|
||||
RefPtr<HostLayerManager> mLayerManager;
|
||||
RefPtr<Compositor> mCompositor;
|
||||
RefPtr<AsyncCompositionManager> mCompositionManager;
|
||||
RefPtr<AsyncImagePipelineManager> mAsyncImageManager;
|
||||
RefPtr<WebRenderBridgeParent> mWrBridge;
|
||||
widget::CompositorWidget* mWidget;
|
||||
TimeStamp mTestTime;
|
||||
|
@ -225,7 +225,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
|
||||
}
|
||||
WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
|
||||
|
||||
RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
|
||||
RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI()->Clone();
|
||||
RefPtr<AsyncImagePipelineManager> holder = root->AsyncImageManager();
|
||||
RefPtr<CompositorAnimationStorage> animStorage = cbp->GetAnimationStorage();
|
||||
parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder), Move(animStorage));
|
||||
|
@ -23,8 +23,9 @@ AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
|
||||
, mMixBlendMode(wr::MixBlendMode::Normal)
|
||||
{}
|
||||
|
||||
AsyncImagePipelineManager::AsyncImagePipelineManager(wr::IdNamespace aIdNamespace)
|
||||
: mIdNamespace(aIdNamespace)
|
||||
AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi)
|
||||
: mApi(aApi)
|
||||
, mIdNamespace(mApi->GetNamespace())
|
||||
, mResourceId(0)
|
||||
, mAsyncImageEpoch(0)
|
||||
, mDestroyed(false)
|
||||
@ -38,9 +39,11 @@ AsyncImagePipelineManager::~AsyncImagePipelineManager()
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::Destroy(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::Destroy()
|
||||
{
|
||||
DeleteOldAsyncImages(aApi);
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
DeleteOldAsyncImages();
|
||||
mApi = nullptr;
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
@ -51,10 +54,11 @@ AsyncImagePipelineManager::HasKeysToDelete()
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::DeleteOldAsyncImages(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::DeleteOldAsyncImages()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
for (wr::ImageKey key : mKeysToDelete) {
|
||||
aApi->DeleteImage(key);
|
||||
mApi->DeleteImage(key);
|
||||
}
|
||||
mKeysToDelete.Clear();
|
||||
}
|
||||
@ -111,7 +115,7 @@ AsyncImagePipelineManager::AddAsyncImagePipeline(const wr::PipelineId& aPipeline
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId)
|
||||
AsyncImagePipelineManager::RemoveAsyncImagePipeline(const wr::PipelineId& aPipelineId)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
@ -121,9 +125,9 @@ AsyncImagePipelineManager::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, cons
|
||||
if (auto entry = mAsyncImagePipelines.Lookup(id)) {
|
||||
AsyncImagePipeline* holder = entry.Data();
|
||||
++mAsyncImageEpoch; // Update webrender epoch
|
||||
aApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
|
||||
mApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
|
||||
for (wr::ImageKey key : holder->mKeys) {
|
||||
aApi->DeleteImage(key);
|
||||
mApi->DeleteImage(key);
|
||||
}
|
||||
entry.Remove();
|
||||
RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
|
||||
@ -155,7 +159,7 @@ AsyncImagePipelineManager::UpdateAsyncImagePipeline(const wr::PipelineId& aPipel
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
|
||||
AsyncImagePipelineManager::GenerateImageKeyForTextureHost(TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
|
||||
{
|
||||
MOZ_ASSERT(aKeys.IsEmpty());
|
||||
MOZ_ASSERT(aTexture);
|
||||
@ -166,7 +170,7 @@ AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi
|
||||
wrTexture->GetWRImageKeys(aKeys, std::bind(&AsyncImagePipelineManager::GenerateImageKey, this));
|
||||
MOZ_ASSERT(!aKeys.IsEmpty());
|
||||
Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
|
||||
wrTexture->AddWRImage(aApi, keys, wrTexture->GetExternalImageKey());
|
||||
wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey());
|
||||
return true;
|
||||
} else {
|
||||
RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
|
||||
@ -185,15 +189,14 @@ AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi
|
||||
|
||||
wr::ImageKey key = GenerateImageKey();
|
||||
aKeys.AppendElement(key);
|
||||
aApi->AddImage(key, descriptor, slice);
|
||||
mApi->AddImage(key, descriptor, slice);
|
||||
dSurf->Unmap();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
bool& aUseExternalImage,
|
||||
AsyncImagePipelineManager::UpdateImageKeys(bool& aUseExternalImage,
|
||||
AsyncImagePipeline* aImageMgr,
|
||||
nsTArray<wr::ImageKey>& aKeys,
|
||||
nsTArray<wr::ImageKey>& aKeysToDelete)
|
||||
@ -231,7 +234,7 @@ AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
return true;
|
||||
}
|
||||
|
||||
aUseExternalImage = aImageMgr->mUseExternalImage = GenerateImageKeyForTextureHost(aApi, texture, aKeys);
|
||||
aUseExternalImage = aImageMgr->mUseExternalImage = GenerateImageKeyForTextureHost(texture, aKeys);
|
||||
MOZ_ASSERT(!aKeys.IsEmpty());
|
||||
aImageMgr->mKeys.AppendElements(aKeys);
|
||||
aImageMgr->mCurrentTexture = texture;
|
||||
@ -239,7 +242,7 @@ AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::ApplyAsyncImages()
|
||||
{
|
||||
if (mDestroyed || mAsyncImagePipelines.Count() == 0) {
|
||||
return;
|
||||
@ -255,8 +258,7 @@ AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
|
||||
nsTArray<wr::ImageKey> keys;
|
||||
bool useExternalImage = false;
|
||||
bool updateDisplayList = UpdateImageKeys(aApi,
|
||||
useExternalImage,
|
||||
bool updateDisplayList = UpdateImageKeys(useExternalImage,
|
||||
pipeline,
|
||||
keys,
|
||||
keysToDelete);
|
||||
@ -306,11 +308,11 @@ AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
wr::BuiltDisplayList dl;
|
||||
wr::LayoutSize builderContentSize;
|
||||
builder.Finalize(builderContentSize, dl);
|
||||
aApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.width, pipeline->mScBounds.height),
|
||||
mApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.width, pipeline->mScBounds.height),
|
||||
pipelineId, builderContentSize,
|
||||
dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
|
||||
}
|
||||
DeleteOldAsyncImages(aApi);
|
||||
DeleteOldAsyncImages();
|
||||
mKeysToDelete.SwapElements(keysToDelete);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
@ -34,13 +35,13 @@ class AsyncImagePipelineManager final
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncImagePipelineManager)
|
||||
|
||||
explicit AsyncImagePipelineManager(wr::IdNamespace aIdNamespace);
|
||||
explicit AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi);
|
||||
|
||||
protected:
|
||||
~AsyncImagePipelineManager();
|
||||
|
||||
public:
|
||||
void Destroy(wr::WebRenderAPI* aApi);
|
||||
void Destroy();
|
||||
bool HasKeysToDelete();
|
||||
|
||||
void AddPipeline(const wr::PipelineId& aPipelineId);
|
||||
@ -70,7 +71,7 @@ public:
|
||||
}
|
||||
|
||||
void AddAsyncImagePipeline(const wr::PipelineId& aPipelineId, WebRenderImageHost* aImageHost);
|
||||
void RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId);
|
||||
void RemoveAsyncImagePipeline(const wr::PipelineId& aPipelineId);
|
||||
|
||||
void UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
|
||||
const LayerRect& aScBounds,
|
||||
@ -78,7 +79,7 @@ public:
|
||||
const gfx::MaybeIntSize& aScaleToSize,
|
||||
const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode);
|
||||
void ApplyAsyncImages(wr::WebRenderAPI* aApi);
|
||||
void ApplyAsyncImages();
|
||||
|
||||
void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
|
||||
{
|
||||
@ -91,7 +92,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void DeleteOldAsyncImages(wr::WebRenderAPI* aApi);
|
||||
void DeleteOldAsyncImages();
|
||||
|
||||
uint32_t GetNextResourceId() { return ++mResourceId; }
|
||||
wr::IdNamespace GetNamespace() { return mIdNamespace; }
|
||||
@ -102,7 +103,7 @@ private:
|
||||
key.mHandle = GetNextResourceId();
|
||||
return key;
|
||||
}
|
||||
bool GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys);
|
||||
bool GenerateImageKeyForTextureHost(TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys);
|
||||
|
||||
struct ForwardingTextureHost {
|
||||
ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
|
||||
@ -135,12 +136,12 @@ private:
|
||||
nsTArray<wr::ImageKey> mKeys;
|
||||
};
|
||||
|
||||
bool UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
bool& aUseExternalImage,
|
||||
bool UpdateImageKeys(bool& aUseExternalImage,
|
||||
AsyncImagePipeline* aImageMgr,
|
||||
nsTArray<wr::ImageKey>& aKeys,
|
||||
nsTArray<wr::ImageKey>& aKeysToDelete);
|
||||
|
||||
RefPtr<wr::WebRenderAPI> mApi;
|
||||
wr::IdNamespace mIdNamespace;
|
||||
uint32_t mResourceId;
|
||||
|
||||
|
@ -21,6 +21,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
|
||||
: mLayer(aLayer)
|
||||
, mBuilder(&aBuilder)
|
||||
, mPushedLayerLocalClip(false)
|
||||
, mClipsPushed(0)
|
||||
{
|
||||
if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
|
||||
// If APZ is disabled then we don't need to push the scrolling clips. We
|
||||
@ -107,6 +108,60 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
|
||||
}
|
||||
}
|
||||
|
||||
ScrollingLayersHelper::ScrollingLayersHelper(nsDisplayItem* aItem,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aStackingContext,
|
||||
WebRenderLayerManager::ClipIdMap& aCache)
|
||||
: mLayer(nullptr)
|
||||
, mBuilder(&aBuilder)
|
||||
, mPushedLayerLocalClip(false)
|
||||
, mClipsPushed(0)
|
||||
{
|
||||
DefineAndPushChain(aItem->GetClipChain(), aBuilder, aStackingContext,
|
||||
aItem->Frame()->PresContext()->AppUnitsPerDevPixel(), aCache);
|
||||
}
|
||||
|
||||
void
|
||||
ScrollingLayersHelper::DefineAndPushChain(const DisplayItemClipChain* aChain,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aStackingContext,
|
||||
int32_t aAppUnitsPerDevPixel,
|
||||
WebRenderLayerManager::ClipIdMap& aCache)
|
||||
{
|
||||
if (!aChain) {
|
||||
return;
|
||||
}
|
||||
auto it = aCache.find(aChain);
|
||||
Maybe<wr::WrClipId> clipId = (it != aCache.end() ? Some(it->second) : Nothing());
|
||||
if (clipId && clipId == aBuilder.TopmostClipId()) {
|
||||
// it was already in the cache and pushed on the WR clip stack, so we don't
|
||||
// need to recurse any further.
|
||||
return;
|
||||
}
|
||||
// Recurse up the clip chain to make sure all ancestor clips are defined and
|
||||
// pushed onto the WR clip stack. Note that the recursion can invalidate the
|
||||
// iterator `it`.
|
||||
DefineAndPushChain(aChain->mParent, aBuilder, aStackingContext, aAppUnitsPerDevPixel, aCache);
|
||||
|
||||
if (!aChain->mClip.HasClip()) {
|
||||
// This item in the chain is a no-op, skip over it
|
||||
return;
|
||||
}
|
||||
if (!clipId) {
|
||||
// If we don't have a clip id for this chain item yet, define the clip in WR
|
||||
// and save the id
|
||||
LayoutDeviceRect clip = LayoutDeviceRect::FromAppUnits(
|
||||
aChain->mClip.GetClipRect(), aAppUnitsPerDevPixel);
|
||||
// TODO: deal with rounded corners here
|
||||
clipId = Some(aBuilder.DefineClip(aStackingContext.ToRelativeLayoutRect(clip)));
|
||||
aCache[aChain] = clipId.value();
|
||||
}
|
||||
// Finally, push the clip onto the WR stack
|
||||
MOZ_ASSERT(clipId);
|
||||
aBuilder.PushClip(clipId.value());
|
||||
mClipsPushed++;
|
||||
}
|
||||
|
||||
void
|
||||
ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStackingContext)
|
||||
{
|
||||
@ -123,7 +178,8 @@ ScrollingLayersHelper::PushLayerLocalClip(const StackingContextHelper& aStacking
|
||||
Maybe<wr::WrImageMask> mask = mLayer->BuildWrMaskLayer(aStackingContext);
|
||||
LayerRect clipRect = ViewAs<LayerPixel>(clip.ref(),
|
||||
PixelCastJustification::MovingDownToChildren);
|
||||
mBuilder->PushClip(aStackingContext.ToRelativeLayoutRect(clipRect), mask.ptrOr(nullptr));
|
||||
mBuilder->PushClip(mBuilder->DefineClip(
|
||||
aStackingContext.ToRelativeLayoutRect(clipRect), nullptr, mask.ptrOr(nullptr)));
|
||||
mPushedLayerLocalClip = true;
|
||||
}
|
||||
}
|
||||
@ -141,11 +197,21 @@ ScrollingLayersHelper::PushLayerClip(const LayerClip& aClip,
|
||||
// TODO: check this transform is correct in all cases
|
||||
mask = maskWrLayer->RenderMaskLayer(aSc, maskLayer->GetTransform());
|
||||
}
|
||||
mBuilder->PushClip(aSc.ToRelativeLayoutRect(clipRect), mask.ptrOr(nullptr));
|
||||
mBuilder->PushClip(mBuilder->DefineClip(
|
||||
aSc.ToRelativeLayoutRect(clipRect), nullptr, mask.ptrOr(nullptr)));
|
||||
}
|
||||
|
||||
ScrollingLayersHelper::~ScrollingLayersHelper()
|
||||
{
|
||||
if (!mLayer) {
|
||||
// For layers-free mode
|
||||
while (mClipsPushed > 0) {
|
||||
mBuilder->PopClip();
|
||||
mClipsPushed--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Layer* layer = mLayer->GetLayer();
|
||||
if (!mLayer->WrManager()->AsyncPanZoomEnabled()) {
|
||||
if (mPushedLayerLocalClip) {
|
||||
|
@ -7,9 +7,12 @@
|
||||
#define GFX_SCROLLINGLAYERSHELPER_H
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/layers/WebRenderLayerManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct DisplayItemClipChain;
|
||||
|
||||
namespace wr {
|
||||
class DisplayListBuilder;
|
||||
}
|
||||
@ -26,9 +29,18 @@ public:
|
||||
ScrollingLayersHelper(WebRenderLayer* aLayer,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aSc);
|
||||
ScrollingLayersHelper(nsDisplayItem* aItem,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aStackingContext,
|
||||
WebRenderLayerManager::ClipIdMap& aCache);
|
||||
~ScrollingLayersHelper();
|
||||
|
||||
private:
|
||||
void DefineAndPushChain(const DisplayItemClipChain* aChain,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
const StackingContextHelper& aStackingContext,
|
||||
int32_t aAppUnitsPerDevPixel,
|
||||
WebRenderLayerManager::ClipIdMap& aCache);
|
||||
void PushLayerLocalClip(const StackingContextHelper& aStackingContext);
|
||||
void PushLayerClip(const LayerClip& aClip,
|
||||
const StackingContextHelper& aSc);
|
||||
@ -36,6 +48,7 @@ private:
|
||||
WebRenderLayer* mLayer;
|
||||
wr::DisplayListBuilder* mBuilder;
|
||||
bool mPushedLayerLocalClip;
|
||||
int mClipsPushed;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -112,8 +112,6 @@ private:
|
||||
InfallibleTArray<OpDestroy>* mActorsToDestroy;
|
||||
};
|
||||
|
||||
/* static */ uint32_t WebRenderBridgeParent::sIdNameSpace = 0;
|
||||
|
||||
WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
|
||||
const wr::PipelineId& aPipelineId,
|
||||
widget::CompositorWidget* aWidget,
|
||||
@ -131,7 +129,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompos
|
||||
, mChildLayerObserverEpoch(0)
|
||||
, mParentLayerObserverEpoch(0)
|
||||
, mWrEpoch(0)
|
||||
, mIdNamespace(AllocIdNameSpace())
|
||||
, mIdNamespace(aApi->GetNamespace())
|
||||
, mPaused(false)
|
||||
, mDestroyed(false)
|
||||
, mForceRendering(false)
|
||||
@ -150,7 +148,7 @@ WebRenderBridgeParent::WebRenderBridgeParent()
|
||||
, mChildLayerObserverEpoch(0)
|
||||
, mParentLayerObserverEpoch(0)
|
||||
, mWrEpoch(0)
|
||||
, mIdNamespace(AllocIdNameSpace())
|
||||
, mIdNamespace{0}
|
||||
, mPaused(false)
|
||||
, mDestroyed(true)
|
||||
, mForceRendering(false)
|
||||
@ -794,7 +792,7 @@ WebRenderBridgeParent::RecvRemovePipelineIdForCompositable(const wr::PipelineId&
|
||||
}
|
||||
|
||||
wrHost->ClearWrBridge();
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(mApi, aPipelineId);
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId);
|
||||
mAsyncCompositables.Remove(wr::AsUint64(aPipelineId));
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -886,7 +884,7 @@ WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
|
||||
|
||||
// Update id name space to identify obsoleted keys.
|
||||
// Since usage of invalid keys could cause crash in webrender.
|
||||
mIdNamespace = AllocIdNameSpace();
|
||||
mIdNamespace = aApi->GetNamespace();
|
||||
// XXX Remove it when webrender supports sharing/moving Keys between different webrender instances.
|
||||
// XXX It requests client to update/reallocate webrender related resources,
|
||||
// but parent side does not wait end of the update.
|
||||
@ -1118,7 +1116,7 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
|
||||
nsTArray<wr::WrTransformProperty> transformArray;
|
||||
|
||||
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
|
||||
mAsyncImageManager->ApplyAsyncImages(mApi);
|
||||
mAsyncImageManager->ApplyAsyncImages();
|
||||
|
||||
SampleAnimations(opacityArray, transformArray);
|
||||
if (!transformArray.IsEmpty() || !opacityArray.IsEmpty()) {
|
||||
@ -1315,7 +1313,7 @@ WebRenderBridgeParent::ClearResources()
|
||||
wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
|
||||
RefPtr<WebRenderImageHost> host = iter.Data();
|
||||
host->ClearWrBridge();
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(mApi, pipelineId);
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(pipelineId);
|
||||
}
|
||||
mAsyncCompositables.Clear();
|
||||
|
||||
@ -1331,6 +1329,7 @@ WebRenderBridgeParent::ClearResources()
|
||||
}
|
||||
mAnimStorage = nullptr;
|
||||
mCompositorScheduler = nullptr;
|
||||
mAsyncImageManager = nullptr;
|
||||
mApi = nullptr;
|
||||
mCompositorBridge = nullptr;
|
||||
}
|
||||
@ -1454,6 +1453,9 @@ void
|
||||
WebRenderBridgeParent::ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
mAsyncImageManager->FlushImageNotifications(aNotifications);
|
||||
}
|
||||
|
||||
|
@ -187,10 +187,6 @@ public:
|
||||
void UpdateAPZ();
|
||||
const WebRenderScrollData& GetScrollData() const;
|
||||
|
||||
static wr::IdNamespace AllocIdNameSpace() {
|
||||
return wr::IdNamespace { ++sIdNameSpace };
|
||||
}
|
||||
|
||||
void FlushRendering(bool aIsSync);
|
||||
|
||||
void ScheduleComposition();
|
||||
@ -296,8 +292,6 @@ private:
|
||||
|
||||
// Can only be accessed on the compositor thread.
|
||||
WebRenderScrollData mScrollData;
|
||||
|
||||
static uint32_t sIdNameSpace;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -264,11 +264,15 @@ WebRenderLayerManager::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDi
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this call to CreateWebRenderCommands can recurse back into
|
||||
// this function if the |item| is a wrapper for a sublist.
|
||||
if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
|
||||
aDisplayListBuilder)) {
|
||||
PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
|
||||
{ // scope the ScrollingLayersHelper
|
||||
ScrollingLayersHelper clip(item, aBuilder, aSc, mClipIdCache);
|
||||
|
||||
// Note: this call to CreateWebRenderCommands can recurse back into
|
||||
// this function if the |item| is a wrapper for a sublist.
|
||||
if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
|
||||
aDisplayListBuilder)) {
|
||||
PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
if (apzEnabled && forceNewLayerData) {
|
||||
@ -624,6 +628,7 @@ WebRenderLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback
|
||||
mScrollData.AddLayerData(*i);
|
||||
}
|
||||
mLayerScrollData.clear();
|
||||
mClipIdCache.clear();
|
||||
} else {
|
||||
for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
|
||||
RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
|
||||
|
@ -273,6 +273,21 @@ private:
|
||||
// tree don't duplicate scroll metadata that their ancestors already have.
|
||||
std::vector<const ActiveScrolledRoot*> mAsrStack;
|
||||
|
||||
public:
|
||||
// Note: two DisplayItemClipChain* A and B might actually be "equal" (as per
|
||||
// DisplayItemClipChain::Equal(A, B)) even though they are not the same pointer
|
||||
// (A != B). In this hopefully-rare case, they will get separate entries
|
||||
// in this map when in fact we could collapse them. However, to collapse
|
||||
// them involves writing a custom hash function for the pointer type such that
|
||||
// A and B hash to the same things whenever DisplayItemClipChain::Equal(A, B)
|
||||
// is true, and that will incur a performance penalty for all the hashmap
|
||||
// operations, so is probably not worth it. With the current code we might
|
||||
// end up creating multiple clips in WR that are effectively identical but
|
||||
// have separate clip ids. Hopefully this won't happen very often.
|
||||
typedef std::unordered_map<const DisplayItemClipChain*, wr::WrClipId> ClipIdMap;
|
||||
private:
|
||||
ClipIdMap mClipIdCache;
|
||||
|
||||
// Layers that have been mutated. If we have an empty transaction
|
||||
// then a display item layer will no longer be valid
|
||||
// if it was a mutated layers.
|
||||
|