merge autoland to mozilla-central. r=merge a=merge

MozReview-Commit-ID: mN7ThnGN3X
This commit is contained in:
Sebastian Hengst 2017-08-10 17:20:12 +02:00
commit 4b79f3b23a
399 changed files with 10772 additions and 7101 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@ XPCOMUtils.defineLazyGetter(this, "extensionNameFromURI", () => {
CastingApps:false, CharsetMenu:false, Color:false, ContentSearch:false,
CustomizableUI: false, DownloadsCommon: false,
Deprecated:false, E10SUtils:false, ExtensionsUI: false, FormValidationHandler:false,
GMPInstallManager:false, LightweightThemeManager:false, Log:false,
LightweightThemeManager:false, Log:false,
LoginManagerParent:false, NewTabUtils:false, PageThumbs:false,
PluralForm:false, PrivateBrowsingUtils:false,
ProcessHangMonitor:false, PromiseUtils:false, ReaderMode:false,
@ -61,7 +61,6 @@ XPCOMUtils.defineLazyGetter(this, "extensionNameFromURI", () => {
["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"],
@ -1629,34 +1628,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();
@ -1680,27 +1652,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;
@ -1718,23 +1675,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) {
@ -1747,21 +1687,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();
});
@ -1776,10 +1701,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
@ -1895,10 +1886,6 @@ var gBrowserInit = {
Cu.reportError(ex);
}
if (this.gmpInstallManager) {
this.gmpInstallManager.uninit();
}
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
MenuTouchModeObserver.uninit();
}
@ -4982,14 +4969,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() {
@ -5026,16 +5005,12 @@ 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;
@ -5043,7 +5018,6 @@ var CombinedStopReload = {
Services.prefs.getBoolPref("browser.stopReloadAnimation.enabled");
Services.prefs.addObserver("toolkit.cosmeticAnimations.enabled", this);
this.stopReloadContainer.addEventListener("animationend", this);
});
},
onTabSwitch() {

View File

@ -1116,7 +1116,7 @@
flex="1"/>
<toolbarbutton type="menu"
id="PlacesChevron"
class="chevron"
class="toolbarbutton-1"
mousethrough="never"
collapsed="true"
tooltiptext="&bookmarksToolbarChevron.tooltip;"

View File

@ -5944,6 +5944,8 @@
Services.prefs.addObserver("privacy.userContext", this);
this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
this._setPositionalAttributes();
]]>
</constructor>

View File

@ -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"],
},
{

View File

@ -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",
]
},
];

View File

@ -234,8 +234,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 = {
@ -576,9 +578,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");
@ -890,17 +896,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();
@ -973,27 +968,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;
},
/**
@ -1060,10 +1040,6 @@ BrowserGlue.prototype = {
BrowserUsageTelemetry.init();
BrowserUITelemetry.init();
if (AppConstants.MOZ_DEV_EDITION) {
this._createExtraDefaultProfile();
}
this._initServiceDiscovery();
// Show update notification, if needed.
@ -1098,99 +1074,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() {
@ -2106,6 +2126,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
// ------------------------------

View File

@ -232,6 +232,10 @@ this.SessionStore = {
return SessionStoreInternal.promiseInitialized;
},
get promiseAllWindowsRestored() {
return SessionStoreInternal.promiseAllWindowsRestored;
},
get canRestoreLastSession() {
return SessionStoreInternal.canRestoreLastSession;
},
@ -550,6 +554,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,
@ -1147,6 +1167,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;
@ -1165,6 +1186,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)) {
@ -4468,8 +4490,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;

View File

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

View File

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

View File

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

View File

@ -1375,11 +1375,26 @@ 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]) {
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;
}
}

View File

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

View File

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

View File

@ -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: [],
},
},
},

View File

@ -399,8 +399,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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
%include ../../../toolkit/themes/osx/global/shared.inc
%include ../shared/browser.inc
%filter substitution

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()");
await Promise.all([
// Wait the initial frame update (which list the background page).
return waitForFrameListUpdate;
})
.then((console) => {
waitForFrameListUpdate,
// Wait the new frame update (once the extension popup has been opened).
return popupFramePromise;
})
.then(() => {
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");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@
DIRS += [
'highlighters',
'utils',
'webconsole',
]
DevToolsModules(

View File

@ -15,7 +15,4 @@ DevToolsModules(
'stack.js',
'TabSources.js',
'walker-search.js',
'webconsole-listeners.js',
'webconsole-utils.js',
'webconsole-worker-listeners.js',
)

View File

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

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

View File

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

View 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',
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -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
@ -3549,4 +3561,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

View File

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

View File

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

View File

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

View File

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

View File

@ -2124,14 +2124,6 @@ MediaCacheStream::Close()
mMediaCache->QueueUpdate();
}
void
MediaCacheStream::EnsureCacheUpdate()
{
if (mHasHadUpdate)
return;
mMediaCache->Update();
}
void
MediaCacheStream::CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor)
{

View File

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

View File

@ -814,9 +814,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
@ -825,10 +822,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) {

View File

@ -456,6 +456,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.
******/
@ -496,12 +502,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();

View File

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

View File

@ -975,12 +975,6 @@ ChannelMediaResource::IsDataCachedToEndOfResource(int64_t aOffset)
return mCacheStream.IsDataCachedToEndOfStream(aOffset);
}
void
ChannelMediaResource::EnsureCacheUpToDate()
{
mCacheStream.EnsureCacheUpdate();
}
bool
ChannelMediaResource::IsSuspendedByCache()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -219,6 +219,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,

View File

@ -8,6 +8,7 @@
#define AudioContext_h_
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/dom/OfflineAudioContextBinding.h"
#include "MediaBufferDecoder.h"
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
@ -154,6 +155,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,

View File

@ -31,7 +31,13 @@ function setOrCompareRenderedBuffer(aRenderedBuffer) {
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var ctx = new OfflineAudioContext(2, 100, 22050);
let ctxs = [
new OfflineAudioContext(2, 100, 22050),
new OfflineAudioContext({length: 100, sampleRate: 22050}),
new OfflineAudioContext({channels: 2, length: 100, sampleRate: 22050}),
];
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.");
@ -41,6 +47,11 @@ addLoadEvent(function() {
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);
@ -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;

View File

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

View File

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

View File

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

View File

@ -723,7 +723,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) {
@ -732,14 +732,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;

View File

@ -1261,7 +1261,13 @@ DrawTargetSkia::FillGlyphsWithCG(ScaledFont *aFont,
return false;
}
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -264,12 +264,16 @@ WebRenderLayerManager::CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDi
}
}
{ // 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) {
// Pop the thing we pushed before the recursion, so the topmost item on
@ -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();

View File

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

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