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

This commit is contained in:
Sebastian Hengst 2017-07-22 12:43:58 +02:00
commit 943e69c7fa
210 changed files with 5991 additions and 1511 deletions

View File

@ -33,11 +33,11 @@ jobs:
mozilla-central: [{hour: 10, minute: 0}]
# No default
- name: nightly-desktop-win64
- name: nightly-desktop-win
job:
type: decision-task
treeherder-symbol: Nd-Win64
target-tasks-method: nightly_win64
treeherder-symbol: Nd-Win
target-tasks-method: nightly_win
run-on-projects:
- date
when: [] # never (hook only)

View File

@ -4988,16 +4988,6 @@ var CombinedStopReload = {
});
},
/* This function is necessary to correctly vertically center the animation
within the toolbar, which uses -moz-pack-align:stretch; and thus a height
which is dependant on the font-size. */
setAnimationImageHeightRelativeToToolbarButtonHeight() {
let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
let toolbarItem = this.stopReloadContainer.closest(".customization-target > toolbaritem");
let bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
toolbarItem.style.setProperty("--toolbarbutton-height", bounds.height + "px");
},
switchToStop(aRequest, aWebProgress) {
if (!this._initialized || !this._shouldSwitch(aRequest))
return;
@ -5010,7 +5000,7 @@ var CombinedStopReload = {
this._cancelTransition();
if (shouldAnimate) {
this.setAnimationImageHeightRelativeToToolbarButtonHeight();
BrowserUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
this.stopReloadContainer.setAttribute("animate", "true");
} else {
this.stopReloadContainer.removeAttribute("animate");
@ -5030,7 +5020,7 @@ var CombinedStopReload = {
this.animate;
if (shouldAnimate) {
this.setAnimationImageHeightRelativeToToolbarButtonHeight();
BrowserUtils.setToolbarButtonHeightProperty(this.stopReloadContainer);
this.stopReloadContainer.setAttribute("animate", "true");
} else {
this.stopReloadContainer.removeAttribute("animate");

View File

@ -1220,7 +1220,11 @@
<toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
oncommand="PanelUI.showSubView('appMenu-libraryView', this, null, event);"
closemenu="none"
label="&places.library.title;"/>
label="&places.library.title;">
<box class="toolbarbutton-animatable-box">
<image class="toolbarbutton-animatable-image"/>
</box>
</toolbarbutton>
#endif
</toolbarpalette>
</toolbox>

View File

@ -12,6 +12,7 @@ support-files =
[browser_aboutCertError.js]
[browser_aboutStopReload.js]
run-if = nightly_build # Photon only
[browser_aboutNetError.js]
[browser_aboutSupport.js]
[browser_aboutSupport_newtab_security_state.js]

View File

@ -2,6 +2,7 @@
support-files =
head.js
[browser_appmenu_reflows.js]
skip-if = (os == 'mac' || os == 'win') && debug # Bug 1382809
[browser_startup.js]
[browser_startup_content.js]
skip-if = !e10s
@ -15,3 +16,4 @@ skip-if = !debug
[browser_toolbariconcolor_restyles.js]
[browser_windowclose_reflows.js]
[browser_windowopen_reflows.js]
skip-if = os == 'linux' # Disabled due to frequent failures. Bug 1380465.

View File

@ -118,7 +118,7 @@ add_task(async function() {
BrowserTestUtils.waitForEvent(PanelUI.panel, "popuppositioned");
await PanelUI.show();
await popupPositioned;
}, EXPECTED_APPMENU_OPEN_REFLOWS, window, PanelUI.panel);
}, EXPECTED_APPMENU_OPEN_REFLOWS);
// Now open a series of subviews, and then close the appmenu. We
// should not reflow during any of this.
@ -160,5 +160,5 @@ add_task(async function() {
let hidden = BrowserTestUtils.waitForEvent(PanelUI.panel, "popuphidden");
PanelUI.hide();
await hidden;
}, EXPECTED_APPMENU_SUBVIEW_REFLOWS, window, PanelUI.panel);
}, EXPECTED_APPMENU_SUBVIEW_REFLOWS);
});

View File

@ -36,12 +36,6 @@ add_task(async function() {
const TAB_COUNT_FOR_GROWTH = computeMaxTabCount();
await createTabs(TAB_COUNT_FOR_GROWTH);
// Because the tab strip is a scrollable frame, we can't use the
// default dirtying function from withReflowObserver and reliably
// get reflows for the strip. Instead, we provide a node that's
// already in the scrollable frame to dirty - in this case, the
// original tab.
let origTab = gBrowser.selectedTab;
let lastTab = gBrowser.tabs[gBrowser.tabs.length - 1];
await BrowserTestUtils.switchTab(gBrowser, lastTab);
@ -52,7 +46,7 @@ add_task(async function() {
await BrowserTestUtils.waitForEvent(tab, "transitionend",
false, e => e.propertyName === "max-width");
await switchDone;
}, EXPECTED_REFLOWS, window, origTab);
}, EXPECTED_REFLOWS);
await removeAllButFirstTab();
});

View File

@ -22,13 +22,6 @@ const EXPECTED_REFLOWS = [
add_task(async function() {
await ensureNoPreloadedBrowser();
// Because the tab strip is a scrollable frame, we can't use the
// default dirtying function from withReflowObserver and reliably
// get reflows for the strip. Instead, we provide a node that's
// already in the scrollable frame to dirty - in this case, the
// original tab.
let origTab = gBrowser.selectedTab;
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.waitForCondition(() => tab._fullyOpen);
@ -39,6 +32,6 @@ add_task(async function() {
await BrowserTestUtils.waitForEvent(tab, "transitionend",
false, e => e.propertyName === "max-width");
await switchDone;
}, EXPECTED_REFLOWS, window, origTab);
}, EXPECTED_REFLOWS);
is(EXPECTED_REFLOWS.length, 0, "No reflows are expected when closing a tab");
});

View File

@ -27,13 +27,6 @@ const EXPECTED_REFLOWS = [
add_task(async function() {
await ensureNoPreloadedBrowser();
// Because the tab strip is a scrollable frame, we can't use the
// default dirtying function from withReflowObserver and reliably
// get reflows for the strip. Instead, we provide a node that's
// already in the scrollable frame to dirty - in this case, the
// original tab.
let origTab = gBrowser.selectedTab;
// Add a reflow observer and open a new tab.
await withReflowObserver(async function() {
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
@ -41,7 +34,7 @@ add_task(async function() {
await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
false, e => e.propertyName === "max-width");
await switchDone;
}, EXPECTED_REFLOWS, window, origTab);
}, EXPECTED_REFLOWS);
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);

View File

@ -33,20 +33,13 @@ add_task(async function() {
await createTabs(TAB_COUNT_FOR_SQUEEZE);
// Because the tab strip is a scrollable frame, we can't use the
// default dirtying function from withReflowObserver and reliably
// get reflows for the strip. Instead, we provide a node that's
// already in the scrollable frame to dirty - in this case, the
// original tab.
let origTab = gBrowser.selectedTab;
await withReflowObserver(async function() {
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
BrowserOpenTab();
await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
false, e => e.propertyName === "max-width");
await switchDone;
}, EXPECTED_REFLOWS, window, origTab);
}, EXPECTED_REFLOWS);
await removeAllButFirstTab();
});

View File

@ -32,13 +32,7 @@ add_task(async function() {
Assert.equal(EXPECTED_REFLOWS.length, 0,
"We shouldn't have added any new expected reflows.");
// Because the tab strip is a scrollable frame, we can't use the
// default dirtying function from withReflowObserver and reliably
// get reflows for the strip. Instead, we provide a node that's
// already in the scrollable frame to dirty - in this case, the
// original tab.
let origTab = gBrowser.selectedTab;
let firstSwitchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
let otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await firstSwitchDone;
@ -47,7 +41,7 @@ add_task(async function() {
let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
gBrowser.selectedTab = origTab;
await switchDone;
}, EXPECTED_REFLOWS, window, origTab);
}, EXPECTED_REFLOWS);
await BrowserTestUtils.removeTab(otherTab);
});

View File

@ -20,21 +20,26 @@ const EXPECTED_REFLOWS = [
],
];
if (Services.appinfo.OS == "Darwin") {
// TabsInTitlebar._update causes a reflow on OS X trying to do calculations
// since layout info is already dirty. This doesn't seem to happen before
// MozAfterPaint on Linux.
if (Services.appinfo.OS == "Linux") {
if (gMultiProcessBrowser) {
EXPECTED_REFLOWS.push(
[
"rect@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
],
);
} else {
EXPECTED_REFLOWS.push(
[
"handleEvent@chrome://browser/content/tabbrowser.xml",
"inferFromText@chrome://browser/content/browser.js",
"handleEvent@chrome://browser/content/browser.js",
],
);
}
}
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
if (Services.appinfo.OS == "Darwin") {
EXPECTED_REFLOWS.push(
[
"handleEvent@chrome://browser/content/tabbrowser.xml",
@ -44,11 +49,99 @@ if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
);
}
if (Services.appinfo.OS == "WINNT") {
EXPECTED_REFLOWS.push(
[
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"handleEvent@chrome://browser/content/tabbrowser.xml",
"inferFromText@chrome://browser/content/browser.js",
"handleEvent@chrome://browser/content/browser.js",
],
[
"handleEvent@chrome://browser/content/tabbrowser.xml",
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
],
);
}
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
EXPECTED_REFLOWS.push(
[
"rect@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"rect@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"rect@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"rect@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
[
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
"_update@chrome://browser/content/browser-tabsintitlebar.js",
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
"handleEvent@chrome://browser/content/tabbrowser.xml",
],
);
}
/*
* This test ensures that there are no unexpected
* uninterruptible reflows when opening new windows.
*/
add_task(async function() {
const IS_WIN8 = (navigator.userAgent.indexOf("Windows NT 6.2") != -1);
if (IS_WIN8) {
ok(true, "Skipping this test because of perma-failures on Windows 8 x64 (bug 1381521)");
return;
}
// Flushing all caches helps to ensure that we get consistent
// behaviour when opening a new window, even if windows have been
// opened in previous tests.
Services.obs.notifyObservers(null, "startupcache-invalidate");
Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
Services.obs.notifyObservers(null, "chrome-flush-caches");
let win = OpenBrowserWindow();
await withReflowObserver(async function() {

View File

@ -65,20 +65,17 @@
* it defaults to the empty Array, meaning no reflows are expected.
* @param window (browser window, optional)
* The browser window to monitor. Defaults to the current window.
* @param elemToDirty (DOM node, optional)
* Callers can provide a custom DOM node to change some layout style
* on in the event that the action being tested is occurring within
* a scrollable frame. Otherwise, withReflowObserver defaults to dirtying
* the first element child of the window.
*/
async function withReflowObserver(testFn, expectedStacks = [], win = window, elemToDirty) {
if (!elemToDirty) {
elemToDirty = win.document.firstElementChild;
async function withReflowObserver(testFn, expectedStacks = [], win = window) {
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let dirtyFrameFn = () => {
try {
dwu.ensureDirtyRootFrame();
} catch (e) {
// If this fails, we should probably make note of it, but it's not fatal.
info("Note: ensureDirtyRootFrame threw an exception.");
}
let i = 0;
let dirtyFrameFn = (e) => {
elemToDirty.style.margin = (++i % 4) + "px";
};
let els = Cc["@mozilla.org/eventlistenerservice;1"]
@ -120,7 +117,9 @@ async function withReflowObserver(testFn, expectedStacks = [], win = window, ele
},
reflowInterruptible(start, end) {
// We're not interested in interruptible reflows.
// We're not interested in interruptible reflows, but might as well take the
// opportuntiy to dirty the root frame.
dirtyFrameFn();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
@ -148,8 +147,6 @@ async function withReflowObserver(testFn, expectedStacks = [], win = window, ele
els.removeListenerForAllEvents(win, dirtyFrameFn, true);
docShell.removeWeakReflowObserver(observer);
elemToDirty.style.margin = "";
}
}

View File

@ -1449,29 +1449,29 @@ CustomizeMode.prototype = {
let gUIDensity = win.gUIDensity;
let currentDensity = gUIDensity.getCurrentDensity();
let normalButton = doc.getElementById("customization-uidensity-menu-button-normal");
normalButton.mode = gUIDensity.MODE_NORMAL;
let normalItem = doc.getElementById("customization-uidensity-menuitem-normal");
normalItem.mode = gUIDensity.MODE_NORMAL;
let compactButton = doc.getElementById("customization-uidensity-menu-button-compact");
compactButton.mode = gUIDensity.MODE_COMPACT;
let compactItem = doc.getElementById("customization-uidensity-menuitem-compact");
compactItem.mode = gUIDensity.MODE_COMPACT;
let buttons = [normalButton, compactButton];
let items = [normalItem, compactItem];
let touchButton = doc.getElementById("customization-uidensity-menu-button-touch");
let touchItem = doc.getElementById("customization-uidensity-menuitem-touch");
// Touch mode can not be enabled in OSX right now.
if (touchButton) {
touchButton.mode = gUIDensity.MODE_TOUCH;
buttons.push(touchButton);
if (touchItem) {
touchItem.mode = gUIDensity.MODE_TOUCH;
items.push(touchItem);
}
// Mark the active mode button.
for (let button of buttons) {
if (button.mode == currentDensity.mode) {
button.setAttribute("aria-checked", "true");
button.setAttribute("active", "true");
// Mark the active mode menuitem.
for (let item of items) {
if (item.mode == currentDensity.mode) {
item.setAttribute("aria-checked", "true");
item.setAttribute("active", "true");
} else {
button.removeAttribute("aria-checked");
button.removeAttribute("active");
item.removeAttribute("aria-checked");
item.removeAttribute("active");
}
}
@ -1486,10 +1486,10 @@ CustomizeMode.prototype = {
// Show a hint that the UI density was overridden automatically.
if (currentDensity.overridden) {
let sb = Services.strings.createBundle("chrome://browser/locale/uiDensity.properties");
touchButton.setAttribute("acceltext",
sb.GetStringFromName("uiDensity.menu-button-touch.acceltext"));
touchItem.setAttribute("acceltext",
sb.GetStringFromName("uiDensity.menuitem-touch.acceltext"));
} else {
touchButton.removeAttribute("acceltext");
touchItem.removeAttribute("acceltext");
}
let autoTouchMode = Services.prefs.getBoolPref(win.gUIDensity.autoTouchModePref);

View File

@ -61,8 +61,8 @@
position="topcenter bottomleft"
flip="none"
role="menu">
<menuitem id="customization-uidensity-menu-button-compact"
class="menuitem-iconic customization-uidensity-menu-button"
<menuitem id="customization-uidensity-menuitem-compact"
class="menuitem-iconic customization-uidensity-menuitem"
role="menuitemradio"
label="&customizeMode.uidensity.menuCompact.label;"
accesskey="&customizeMode.uidensity.menuCompact.accessKey;"
@ -73,8 +73,8 @@
onblur="gCustomizeMode.resetUIDensity();"
onmouseout="gCustomizeMode.resetUIDensity();"
oncommand="gCustomizeMode.setUIDensity(this.mode);" />
<menuitem id="customization-uidensity-menu-button-normal"
class="menuitem-iconic customization-uidensity-menu-button"
<menuitem id="customization-uidensity-menuitem-normal"
class="menuitem-iconic customization-uidensity-menuitem"
role="menuitemradio"
label="&customizeMode.uidensity.menuNormal.label;"
accesskey="&customizeMode.uidensity.menuNormal.accessKey;"
@ -86,8 +86,8 @@
onmouseout="gCustomizeMode.resetUIDensity();"
oncommand="gCustomizeMode.setUIDensity(this.mode);" />
#ifndef XP_MACOSX
<menuitem id="customization-uidensity-menu-button-touch"
class="menuitem-iconic customization-uidensity-menu-button"
<menuitem id="customization-uidensity-menuitem-touch"
class="menuitem-iconic customization-uidensity-menuitem"
role="menuitemradio"
label="&customizeMode.uidensity.menuTouch.label;"
accesskey="&customizeMode.uidensity.menuTouch.accessKey;"

View File

@ -7,7 +7,7 @@
const PREF_UI_DENSITY = "browser.uidensity";
const PREF_AUTO_TOUCH_MODE = "browser.touchmode.auto";
async function testModeButton(mode, modePref) {
async function testModeMenuitem(mode, modePref) {
await startCustomizing();
let win = document.getElementById("main-window");
@ -19,54 +19,54 @@ async function testModeButton(mode, modePref) {
EventUtils.synthesizeMouseAtCenter(popupButton, {});
await popupShownPromise;
let button = document.getElementById("customization-uidensity-menu-button-" + mode);
let normalButton = document.getElementById("customization-uidensity-menu-button-normal");
let item = document.getElementById("customization-uidensity-menuitem-" + mode);
let normalItem = document.getElementById("customization-uidensity-menuitem-normal");
is(normalButton.getAttribute("active"), "true",
"Normal mode button should be active by default.");
is(normalItem.getAttribute("active"), "true",
"Normal mode menuitem should be active by default");
// Hover over the mode button and wait until the UI density is updated.
EventUtils.synthesizeMouseAtCenter(button, { type: "mouseover" });
// Hover over the mode menuitem and wait until the UI density is updated.
EventUtils.synthesizeMouseAtCenter(item, { type: "mouseover" });
await BrowserTestUtils.waitForAttribute("uidensity", win, mode);
is(win.getAttribute("uidensity"), mode,
`UI Density should be set to ${mode} on ${mode} button hover.`);
`UI Density should be set to ${mode} on ${mode} menuitem hover`);
is(Services.prefs.getIntPref(PREF_UI_DENSITY), window.gUIDensity.MODE_NORMAL,
`UI Density pref should still be set to normal on ${mode} button hover.`);
`UI Density pref should still be set to normal on ${mode} menuitem hover`);
// Hover the normal button again and check that the UI density reset to normal.
EventUtils.synthesizeMouseAtCenter(normalButton, { type: "mouseover" });
// Hover the normal menuitem again and check that the UI density reset to normal.
EventUtils.synthesizeMouseAtCenter(normalItem, { type: "mouseover" });
await BrowserTestUtils.waitForCondition(() => !win.hasAttribute("uidensity"));
ok(!win.hasAttribute("uidensity"),
`UI Density should be reset when no longer hovering the ${mode} button.`);
`UI Density should be reset when no longer hovering the ${mode} menuitem`);
// Select the custom UI density and wait for the popup to be hidden.
let popupHiddenPromise = popupHidden(popup);
EventUtils.synthesizeMouseAtCenter(button, {});
EventUtils.synthesizeMouseAtCenter(item, {});
await popupHiddenPromise;
// Check that the click permanently changed the UI density.
is(win.getAttribute("uidensity"), mode,
`UI Density should be set to ${mode} on ${mode} button click.`);
`UI Density should be set to ${mode} on ${mode} menuitem click`);
is(Services.prefs.getIntPref(PREF_UI_DENSITY), modePref,
`UI Density pref should be set to ${mode} when clicking the ${mode} button.`);
`UI Density pref should be set to ${mode} when clicking the ${mode} menuitem`);
// Open the popup again.
popupShownPromise = popupShown(popup);
EventUtils.synthesizeMouseAtCenter(popupButton, {});
await popupShownPromise;
// Check that the button is still active after opening and closing the popup.
is(button.getAttribute("active"), "true", `${mode} mode button should be active.`);
// Check that the menuitem is still active after opening and closing the popup.
is(item.getAttribute("active"), "true", `${mode} mode menuitem should be active`);
// Hide the popup again.
popupHiddenPromise = popupHidden(popup);
EventUtils.synthesizeMouseAtCenter(popupButton, {});
await popupHiddenPromise;
// Check that the button is still active after re-opening customize mode.
// Check that the menuitem is still active after re-opening customize mode.
await endCustomizing();
await startCustomizing();
@ -74,40 +74,40 @@ async function testModeButton(mode, modePref) {
EventUtils.synthesizeMouseAtCenter(popupButton, {});
await popupShownPromise;
is(button.getAttribute("active"), "true",
`${mode} mode button should be active after entering and exiting customize mode.`);
is(item.getAttribute("active"), "true",
`${mode} mode menuitem should be active after entering and exiting customize mode`);
// Click the normal button and check that the density is reset.
// Click the normal menuitem and check that the density is reset.
popupHiddenPromise = popupHidden(popup);
EventUtils.synthesizeMouseAtCenter(normalButton, {});
EventUtils.synthesizeMouseAtCenter(normalItem, {});
await popupHiddenPromise;
ok(!win.hasAttribute("uidensity"),
"UI Density should be reset when clicking the normal button.");
"UI Density should be reset when clicking the normal menuitem");
is(Services.prefs.getIntPref(PREF_UI_DENSITY), window.gUIDensity.MODE_NORMAL,
"UI Density pref should be set to normal.");
// Show the popup and click on the mode button again to test the
// Show the popup and click on the mode menuitem again to test the
// reset default feature.
popupShownPromise = popupShown(popup);
EventUtils.synthesizeMouseAtCenter(popupButton, {});
await popupShownPromise;
popupHiddenPromise = popupHidden(popup);
EventUtils.synthesizeMouseAtCenter(button, {});
EventUtils.synthesizeMouseAtCenter(item, {});
await popupHiddenPromise;
is(win.getAttribute("uidensity"), mode,
`UI Density should be set to ${mode} on ${mode} button click.`);
`UI Density should be set to ${mode} on ${mode} menuitem click`);
is(Services.prefs.getIntPref(PREF_UI_DENSITY), modePref,
`UI Density pref should be set to ${mode} when clicking the ${mode} button.`);
`UI Density pref should be set to ${mode} when clicking the ${mode} menuitem`);
await gCustomizeMode.reset();
ok(!win.hasAttribute("uidensity"),
"UI Density should be reset when clicking the normal button.");
"UI Density should be reset when clicking the normal menuitem");
is(Services.prefs.getIntPref(PREF_UI_DENSITY), window.gUIDensity.MODE_NORMAL,
"UI Density pref should be set to normal.");
@ -115,16 +115,16 @@ async function testModeButton(mode, modePref) {
await endCustomizing();
}
add_task(async function test_compact_mode_button() {
add_task(async function test_compact_mode_menuitem() {
if (!AppConstants.MOZ_PHOTON_THEME) {
ok(true, "Skipping test because Photon is not enabled.");
return;
}
await testModeButton("compact", window.gUIDensity.MODE_COMPACT);
await testModeMenuitem("compact", window.gUIDensity.MODE_COMPACT);
});
add_task(async function test_touch_mode_button() {
add_task(async function test_touch_mode_menuitem() {
if (!AppConstants.MOZ_PHOTON_THEME) {
ok(true, "Skipping test because Photon is not enabled.");
return;
@ -132,12 +132,12 @@ add_task(async function test_touch_mode_button() {
// OSX doesn't get touch mode for now.
if (AppConstants.platform == "macosx") {
is(document.getElementById("customization-uidensity-menu-button-touch"), null,
is(document.getElementById("customization-uidensity-menuitem-touch"), null,
"There's no touch option on Mac OSX");
return;
}
await testModeButton("touch", window.gUIDensity.MODE_TOUCH);
await testModeMenuitem("touch", window.gUIDensity.MODE_TOUCH);
// Test the checkbox for automatic Touch Mode transition
// in Windows 10 Tablet Mode.

View File

@ -9,6 +9,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
@ -92,6 +93,13 @@ function CreatePocketWidget(reason) {
label: gPocketBundle.GetStringFromName("pocket-button.label"),
tooltiptext: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
// Use forwarding functions here to avoid loading Pocket.jsm on startup:
onBeforeCommand() {
// We need to use onBeforeCommand to calculate the height
// of the pocket-button before it is opened since we need
// the height of the button to perform the animation that is
// triggered off of [open="true"].
return Pocket.onBeforeCommand.apply(this, arguments);
},
onViewShowing() {
return Pocket.onPanelViewShowing.apply(this, arguments);
},
@ -108,7 +116,20 @@ function CreatePocketWidget(reason) {
panel.setAttribute("class", "panel-subview-body");
view.appendChild(panel);
doc.getElementById("PanelUI-multiView").appendChild(view);
},
onCreated(node) {
if (Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
AppConstants.MOZ_PHOTON_ANIMATIONS) {
let doc = node.ownerDocument;
let box = doc.createElement("box");
box.classList.add("toolbarbutton-animatable-box");
let image = doc.createElement("image");
image.classList.add("toolbarbutton-animatable-image");
box.appendChild(image);
node.appendChild(box);
node.setAttribute("animationsenabled", "true");
}
},
};
CustomizableUI.createWidget(pocketButton);

View File

@ -10,6 +10,8 @@ this.EXPORTED_SYMBOLS = ["Pocket"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
@ -22,11 +24,18 @@ var Pocket = {
/**
* Functions related to the Pocket panel UI.
*/
onBeforeCommand(event) {
BrowserUtils.setToolbarButtonHeightProperty(event.target);
},
onPanelViewShowing(event) {
let document = event.target.ownerDocument;
let window = document.defaultView;
let iframe = window.pktUI.getPanelFrame();
let libraryButton = document.getElementById("library-button");
BrowserUtils.setToolbarButtonHeightProperty(libraryButton);
let urlToSave = Pocket._urlToSave;
let titleToSave = Pocket._titleToSave;
Pocket._urlToSave = null;

View File

@ -68,6 +68,8 @@ var pktUI = (function() {
var savePanelWidth = 350;
var savePanelHeights = {collapsed: 153, expanded: 272};
var _lastAddSucceeded = false;
// -- Event Handling -- //
/**
@ -88,8 +90,34 @@ var pktUI = (function() {
// clear the panel
getPanelFrame().setAttribute("src", "about:blank");
if (_lastAddSucceeded) {
var libraryButton = document.getElementById("library-button");
if (!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") ||
!libraryButton ||
libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
libraryButton.getAttribute("overflowedItem") == "true" ||
!libraryButton.closest("toolbar") ||
libraryButton.closest("toolbar").id != "nav-bar") {
return;
}
libraryButton.removeAttribute("fade");
libraryButton.setAttribute("animate", "pocket");
libraryButton.addEventListener("animationend", onLibraryButtonAnimationEnd);
}
}
function onLibraryButtonAnimationEnd(event) {
let doc = event.target.ownerDocument;
let libraryButton = doc.getElementById("library-button");
if (event.animationName.startsWith("library-pocket-animation")) {
libraryButton.setAttribute("fade", "true");
} else if (event.animationName == "library-pocket-fade") {
libraryButton.removeEventListener("animationend", onLibraryButtonAnimationEnd);
libraryButton.removeAttribute("animate");
libraryButton.removeAttribute("fade");
}
}
// -- Communication to API -- //
@ -197,6 +225,7 @@ var pktUI = (function() {
var panelId = showPanel("about:pocket-saved?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? "1" : "0") + "&inoverflowmenu=" + inOverflowMenu + "&locale=" + getUILocale(), {
onShow() {
var saveLinkMessageId = "saveLink";
_lastAddSucceeded = false;
// Send error message for invalid url
if (!isValidURL) {
@ -228,6 +257,7 @@ var pktUI = (function() {
item
};
pktUIMessaging.sendMessageToPanel(panelId, saveLinkMessageId, successResponse);
_lastAddSucceeded = true;
},
error(error, request) {
// If user is not authorized show singup page

View File

@ -0,0 +1,986 @@
<!-- 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="1078" height="54">
<svg x="0">
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
</svg>
<svg x="22">
<defs>
<mask id="a" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="b" mask-type="alpha">
<g opacity=".055">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#b)">
<path fill="#EF3F56" fill-opacity="1" d="M8.913 13.992c-3.55 -1.232 -5.428 -5.108 -4.197 -8.657l1.116 -3.214a1.7 1.7 0 0 1 2.164 -1.05l9.64 3.347a1.7 1.7 0 0 1 1.05 2.164l-1.116 3.214c-1.231 3.549 -5.108 5.428 -8.657 4.196z" opacity="1"/>
</g>
<g mask="url(#a)">
<path fill="#FFF" fill-opacity="1" d="M14.831 7.252a0.84 0.84 0 0 0 -0.671 0.054l-3.552 1.723 -1.688 -3.497a0.838 0.838 0 0 0 -0.504 -0.506 0.85 0.85 0 0 0 -1.047 1.166l-0.016 0.005 1.723 3.574 0.371 0.765a0.851 0.851 0 0 0 1.136 0.394l0.765 -0.37 3.58 -1.734a0.851 0.851 0 0 0 0.483 -0.82 0.851 0.851 0 0 0 -0.58 -0.754z" opacity=".043"/>
</g>
</svg>
<svg x="44">
<defs>
<mask id="d" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="c" mask-type="alpha">
<g opacity=".198">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#c)">
<path fill="#EF3F56" fill-opacity="1" d="M9.209 14.005c-3.574 -1.084 -5.593 -4.86 -4.509 -8.434l0.982 -3.235a1.69 1.69 0 0 1 2.108 -1.128l9.707 2.945a1.69 1.69 0 0 1 1.127 2.108l-0.981 3.236c-1.084 3.573 -4.86 5.592 -8.434 4.508z" opacity="1"/>
</g>
<g mask="url(#d)">
<path fill="#FFF" fill-opacity="1" d="M14.822 7.078a0.836 0.836 0 0 0 -0.665 0.08l-3.46 1.85 -1.814 -3.406a0.833 0.833 0 0 0 -0.52 -0.483 0.846 0.846 0 0 0 -0.995 1.2l-0.015 0.005 1.852 3.482 0.399 0.745a0.846 0.846 0 0 0 1.143 0.347l0.746 -0.398 3.487 -1.862a0.846 0.846 0 0 0 0.448 -0.834 0.846 0.846 0 0 0 -0.606 -0.726z" opacity=".156"/>
</g>
</svg>
<svg x="66">
<defs>
<mask id="f" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="e" mask-type="alpha">
<g opacity=".394">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#e)">
<path fill="#EF3F56" fill-opacity="1" d="M9.627 14.025c-3.598 -0.875 -5.805 -4.501 -4.93 -8.1l0.792 -3.257a1.676 1.676 0 0 1 2.025 -1.232l9.773 2.377a1.676 1.676 0 0 1 1.232 2.024l-0.792 3.258c-0.875 3.598 -4.502 5.805 -8.1 4.93z" opacity="1"/>
</g>
<g mask="url(#f)">
<path fill="#FFF" fill-opacity="1" d="M14.8 6.857a0.829 0.829 0 0 0 -0.653 0.116l-3.323 2.023 -1.984 -3.272a0.826 0.826 0 0 0 -0.542 -0.449 0.838 0.838 0 0 0 -0.919 1.243l-0.015 0.006 2.027 3.345 0.436 0.715a0.839 0.839 0 0 0 1.151 0.28l0.716 -0.435 3.35 -2.037a0.839 0.839 0 0 0 0.396 -0.85 0.839 0.839 0 0 0 -0.64 -0.685z" opacity=".316"/>
</g>
</svg>
<svg x="88">
<defs>
<mask id="h" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="g" mask-type="alpha">
<g opacity=".606">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#g)">
<path fill="#EF3F56" fill-opacity="1" d="M10.107 14.027c-3.611 -0.637 -6.022 -4.08 -5.386 -7.691l0.577 -3.27a1.66 1.66 0 0 1 1.922 -1.346l9.808 1.73a1.66 1.66 0 0 1 1.346 1.922l-0.576 3.27c-0.637 3.61 -4.08 6.021 -7.691 5.385z" opacity="1"/>
</g>
<g mask="url(#h)">
<path fill="#FFF" fill-opacity="1" d="M14.764 6.615a0.82 0.82 0 0 0 -0.639 0.157l-3.155 2.21 -2.168 -3.108a0.818 0.818 0 0 0 -0.564 -0.41 0.83 0.83 0 0 0 -0.829 1.287l-0.014 0.007 2.215 3.176 0.476 0.68a0.83 0.83 0 0 0 1.155 0.204l0.68 -0.476 3.18 -2.225a0.83 0.83 0 0 0 0.339 -0.865 0.83 0.83 0 0 0 -0.676 -0.637z" opacity=".5"/>
</g>
</svg>
<svg x="110">
<defs>
<mask id="j" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="i" mask-type="alpha">
<g opacity=".802">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#i)">
<path fill="#EF3F56" fill-opacity="1" d="M10.583 13.998c-3.608 -0.4 -6.208 -3.65 -5.808 -7.258l0.362 -3.266a1.643 1.643 0 0 1 1.815 -1.452l9.8 1.087a1.643 1.643 0 0 1 1.451 1.814l-0.362 3.267c-0.4 3.608 -3.65 6.208 -7.258 5.808z" opacity="1"/>
</g>
<g mask="url(#j)">
<path fill="#FFF" fill-opacity="1" d="M14.715 6.38a0.812 0.812 0 0 0 -0.62 0.195l-2.978 2.384 -2.34 -2.933a0.81 0.81 0 0 0 -0.583 -0.37 0.822 0.822 0 0 0 -0.737 1.324l-0.014 0.008 2.39 2.998 0.513 0.641a0.822 0.822 0 0 0 1.155 0.129l0.641 -0.514 3.002 -2.4a0.822 0.822 0 0 0 0.28 -0.876 0.822 0.822 0 0 0 -0.709 -0.586z" opacity=".684"/>
</g>
</svg>
<svg x="132">
<defs>
<mask id="l" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="k" mask-type="alpha">
<g opacity=".945">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#k)">
<path fill="#EF3F56" fill-opacity="1" d="M10.996 13.943c-3.593 -0.196 -6.347 -3.268 -6.15 -6.861l0.177 -3.253a1.628 1.628 0 0 1 1.715 -1.538l9.76 0.533a1.628 1.628 0 0 1 1.537 1.716l-0.178 3.253c-0.196 3.592 -3.268 6.346 -6.861 6.15z" opacity="1"/>
</g>
<g mask="url(#l)">
<path fill="#FFF" fill-opacity="1" d="M14.663 6.175a0.805 0.805 0 0 0 -0.603 0.227l-2.815 2.524 -2.478 -2.773a0.803 0.803 0 0 0 -0.597 -0.333 0.815 0.815 0 0 0 -0.657 1.35l-0.013 0.009 2.531 2.835 0.544 0.606a0.815 0.815 0 0 0 1.15 0.063l0.606 -0.543 2.838 -2.542a0.815 0.815 0 0 0 0.228 -0.882 0.815 0.815 0 0 0 -0.734 -0.541z" opacity=".844"/>
</g>
</svg>
<svg x="154">
<defs>
<mask id="n" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="m" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#m)">
<path fill="#EF3F56" fill-opacity="1" d="M11.285 13.878c-3.575 -0.054 -6.43 -2.996 -6.377 -6.571l0.049 -3.237a1.618 1.618 0 0 1 1.643 -1.595l9.711 0.146a1.618 1.618 0 0 1 1.594 1.643l-0.048 3.237c-0.054 3.576 -2.996 6.43 -6.572 6.377z" opacity="1"/>
</g>
<g mask="url(#n)">
<path fill="#FFF" fill-opacity="1" d="M14.622 6.02a0.8 0.8 0 0 0 -0.591 0.25l-2.696 2.617 -2.569 -2.657a0.798 0.798 0 0 0 -0.607 -0.307 0.81 0.81 0 0 0 -0.598 1.367l-0.013 0.009 2.625 2.715 0.563 0.581a0.81 0.81 0 0 0 1.145 0.017l0.58 -0.563 2.719 -2.635a0.81 0.81 0 0 0 0.19 -0.886 0.81 0.81 0 0 0 -0.748 -0.508z" opacity=".957"/>
</g>
</svg>
<svg x="176">
<defs>
<mask id="p" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="o" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#o)">
<path fill="#EF3F56" fill-opacity="1" d="M11.395 13.825c-3.568 0 -6.46 -2.893 -6.46 -6.46v-3.23a1.614 1.614 0 0 1 1.615 -1.615h9.69a1.614 1.614 0 0 1 1.614 1.615v3.23c0 3.567 -2.892 6.46 -6.46 6.46z" opacity="1"/>
</g>
<g mask="url(#p)">
<path fill="#FFF" fill-opacity="1" d="M14.605 5.936a0.798 0.798 0 0 0 -0.585 0.258l-2.65 2.65 -2.603 -2.61a0.796 0.796 0 0 0 -0.61 -0.298 0.808 0.808 0 0 0 -0.576 1.373l-0.013 0.009 2.659 2.67 0.57 0.57a0.808 0.808 0 0 0 1.143 0l0.57 -0.57 2.672 -2.67a0.808 0.808 0 0 0 0.178 -0.886 0.808 0.808 0 0 0 -0.755 -0.496z" opacity="1"/>
</g>
</svg>
<svg x="198">
<defs>
<mask id="r" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="q" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#q)">
<path fill="#EF3F56" fill-opacity="1" d="M11.453 13.875c-3.567 0.03 -6.483 -2.839 -6.512 -6.406l-0.027 -3.23a1.614 1.614 0 0 1 1.602 -1.628l9.69 -0.08a1.614 1.614 0 0 1 1.627 1.602l0.027 3.23c0.029 3.567 -2.84 6.483 -6.407 6.512z" opacity="1"/>
</g>
<g mask="url(#r)">
<path fill="#FFF" fill-opacity="1" d="M14.599 5.96a0.798 0.798 0 0 0 -0.583 0.263l-2.629 2.673 -2.623 -2.59a0.796 0.796 0 0 0 -0.612 -0.292 0.808 0.808 0 0 0 -0.566 1.377l-0.012 0.009 2.68 2.648 0.576 0.566a0.808 0.808 0 0 0 1.142 -0.01l0.566 -0.575 2.65 -2.691a0.808 0.808 0 0 0 0.17 -0.888 0.808 0.808 0 0 0 -0.759 -0.49z" opacity="1"/>
</g>
</svg>
<svg x="220">
<defs>
<mask id="t" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="s" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#s)">
<path fill="#EF3F56" fill-opacity="1" d="M11.535 13.94c-3.567 0.07 -6.515 -2.766 -6.585 -6.332l-0.063 -3.23a1.614 1.614 0 0 1 1.582 -1.646l9.688 -0.19a1.614 1.614 0 0 1 1.646 1.583l0.064 3.23c0.07 3.566 -2.765 6.514 -6.332 6.584z" opacity="1"/>
</g>
<g mask="url(#t)">
<path fill="#FFF" fill-opacity="1" d="M14.59 5.99a0.798 0.798 0 0 0 -0.58 0.269l-2.598 2.702 -2.653 -2.56a0.796 0.796 0 0 0 -0.615 -0.285 0.808 0.808 0 0 0 -0.55 1.384l-0.012 0.009 2.71 2.617 0.582 0.56a0.808 0.808 0 0 0 1.142 -0.023l0.56 -0.582 2.618 -2.721a0.808 0.808 0 0 0 0.16 -0.89 0.808 0.808 0 0 0 -0.764 -0.48z" opacity="1"/>
</g>
</svg>
<svg x="242">
<defs>
<mask id="v" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="u" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#u)">
<path fill="#EF3F56" fill-opacity="1" d="M11.63 14.017c-3.566 0.117 -6.551 -2.678 -6.669 -6.244l-0.106 -3.228a1.614 1.614 0 0 1 1.561 -1.667l9.684 -0.319a1.614 1.614 0 0 1 1.667 1.561l0.107 3.228c0.117 3.566 -2.679 6.552 -6.244 6.669z" opacity="1"/>
</g>
<g mask="url(#v)">
<path fill="#FFF" fill-opacity="1" d="M14.58 6.027a0.798 0.798 0 0 0 -0.577 0.277l-2.562 2.737 -2.687 -2.525a0.796 0.796 0 0 0 -0.619 -0.277 0.808 0.808 0 0 0 -0.53 1.391l-0.013 0.01 2.745 2.58 0.59 0.552a0.808 0.808 0 0 0 1.14 -0.038l0.552 -0.59 2.583 -2.755a0.808 0.808 0 0 0 0.148 -0.891 0.808 0.808 0 0 0 -0.77 -0.47z" opacity="1"/>
</g>
</svg>
<svg x="264">
<defs>
<mask id="x" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="w" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#w)">
<path fill="#EF3F56" fill-opacity="1" d="M11.733 14.108c-3.563 0.17 -6.589 -2.583 -6.758 -6.146l-0.153 -3.226a1.614 1.614 0 0 1 1.537 -1.69l9.678 -0.459a1.614 1.614 0 0 1 1.69 1.537l0.153 3.226c0.169 3.563 -2.583 6.59 -6.147 6.758z" opacity="1"/>
</g>
<g mask="url(#x)">
<path fill="#FFF" fill-opacity="1" d="M14.567 6.077a0.798 0.798 0 0 0 -0.573 0.285l-2.521 2.773 -2.724 -2.485a0.796 0.796 0 0 0 -0.623 -0.268 0.808 0.808 0 0 0 -0.51 1.399l-0.013 0.01 2.782 2.54 0.598 0.543a0.808 0.808 0 0 0 1.14 -0.054l0.543 -0.598 2.543 -2.792a0.808 0.808 0 0 0 0.135 -0.894 0.808 0.808 0 0 0 -0.777 -0.46z" opacity="1"/>
</g>
</svg>
<svg x="286">
<defs>
<mask id="z" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="y" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#y)">
<path fill="#EF3F56" fill-opacity="1" d="M11.843 14.215c-3.56 0.223 -6.628 -2.482 -6.852 -6.042l-0.203 -3.224a1.614 1.614 0 0 1 1.51 -1.713l9.671 -0.607a1.614 1.614 0 0 1 1.713 1.51l0.203 3.224c0.223 3.56 -2.482 6.628 -6.042 6.852z" opacity="1"/>
</g>
<g mask="url(#z)">
<path fill="#FFF" fill-opacity="1" d="M14.552 6.14a0.798 0.798 0 0 0 -0.568 0.294l-2.478 2.812 -2.761 -2.443a0.796 0.796 0 0 0 -0.627 -0.258 0.808 0.808 0 0 0 -0.49 1.406l-0.012 0.01 2.821 2.497 0.606 0.534a0.808 0.808 0 0 0 1.14 -0.072l0.533 -0.605 2.5 -2.832a0.808 0.808 0 0 0 0.121 -0.895 0.808 0.808 0 0 0 -0.785 -0.448z" opacity="1"/>
</g>
</svg>
<svg x="308">
<defs>
<mask id="B" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="A" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#A)">
<path fill="#EF3F56" fill-opacity="1" d="M11.957 14.336c-3.556 0.281 -6.667 -2.375 -6.948 -5.93l-0.254 -3.22a1.614 1.614 0 0 1 1.483 -1.738l9.66 -0.762a1.614 1.614 0 0 1 1.736 1.483l0.254 3.22c0.281 3.556 -2.375 6.667 -5.931 6.947z" opacity="1"/>
</g>
<g mask="url(#B)">
<path fill="#FFF" fill-opacity="1" d="M14.537 6.22a0.798 0.798 0 0 0 -0.563 0.303l-2.434 2.85 -2.8 -2.398a0.796 0.796 0 0 0 -0.63 -0.248 0.808 0.808 0 0 0 -0.467 1.414l-0.013 0.01 2.861 2.452 0.614 0.524a0.808 0.808 0 0 0 1.138 -0.09l0.525 -0.614 2.453 -2.871a0.808 0.808 0 0 0 0.107 -0.897 0.808 0.808 0 0 0 -0.791 -0.435z" opacity="1"/>
</g>
</svg>
<svg x="330">
<defs>
<mask id="D" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="C" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#C)">
<path fill="#EF3F56" fill-opacity="1" d="M12.074 14.475c-3.55 0.34 -6.705 -2.265 -7.044 -5.816l-0.308 -3.215a1.614 1.614 0 0 1 1.454 -1.761l9.646 -0.922a1.614 1.614 0 0 1 1.76 1.454l0.308 3.215c0.34 3.551 -2.264 6.706 -5.816 7.045z" opacity="1"/>
</g>
<g mask="url(#D)">
<path fill="#FFF" fill-opacity="1" d="M14.52 6.317a0.798 0.798 0 0 0 -0.558 0.312l-2.386 2.891 -2.84 -2.352a0.796 0.796 0 0 0 -0.634 -0.238 0.808 0.808 0 0 0 -0.444 1.422l-0.012 0.01 2.901 2.404 0.623 0.514a0.808 0.808 0 0 0 1.136 -0.109l0.514 -0.622 2.406 -2.912a0.808 0.808 0 0 0 0.093 -0.898 0.808 0.808 0 0 0 -0.8 -0.422z" opacity="1"/>
</g>
</svg>
<svg x="352">
<defs>
<mask id="F" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="E" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#E)">
<path fill="#EF3F56" fill-opacity="1" d="M12.194 14.632c-3.545 0.4 -6.742 -2.15 -7.142 -5.696l-0.361 -3.21a1.614 1.614 0 0 1 1.424 -1.785l9.628 -1.085a1.614 1.614 0 0 1 1.786 1.424l0.361 3.21c0.4 3.545 -2.15 6.743 -5.696 7.142z" opacity="1"/>
</g>
<g mask="url(#F)">
<path fill="#FFF" fill-opacity="1" d="M14.502 6.434a0.798 0.798 0 0 0 -0.553 0.321l-2.337 2.931 -2.878 -2.303a0.796 0.796 0 0 0 -0.64 -0.227 0.808 0.808 0 0 0 -0.419 1.428l-0.011 0.01 2.94 2.355 0.632 0.504a0.808 0.808 0 0 0 1.134 -0.128l0.504 -0.631 2.356 -2.952a0.808 0.808 0 0 0 0.077 -0.9 0.808 0.808 0 0 0 -0.805 -0.408z" opacity="1"/>
</g>
</svg>
<svg x="374">
<defs>
<mask id="H" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="G" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#G)">
<path fill="#EF3F56" fill-opacity="1" d="M12.316 14.809c-3.537 0.46 -6.779 -2.035 -7.239 -5.572l-0.417 -3.203a1.614 1.614 0 0 1 1.393 -1.81l9.609 -1.25a1.614 1.614 0 0 1 1.81 1.393l0.416 3.203c0.46 3.537 -2.034 6.779 -5.572 7.239z" opacity="1"/>
</g>
<g mask="url(#H)">
<path fill="#FFF" fill-opacity="1" d="M14.482 6.572a0.798 0.798 0 0 0 -0.547 0.331l-2.286 2.97 -2.918 -2.253a0.796 0.796 0 0 0 -0.643 -0.216 0.808 0.808 0 0 0 -0.394 1.436l-0.012 0.01 2.981 2.304 0.64 0.493a0.808 0.808 0 0 0 1.132 -0.148l0.493 -0.64 2.305 -2.991a0.808 0.808 0 0 0 0.061 -0.902 0.808 0.808 0 0 0 -0.812 -0.394z" opacity="1"/>
</g>
</svg>
<svg x="396">
<defs>
<mask id="J" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="I" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#I)">
<path fill="#EF3F56" fill-opacity="1" d="M12.44 15.008c-3.53 0.522 -6.814 -1.916 -7.336 -5.445l-0.473 -3.195a1.614 1.614 0 0 1 1.361 -1.834l9.585 -1.418a1.614 1.614 0 0 1 1.834 1.361l0.473 3.195c0.522 3.53 -1.916 6.814 -5.445 7.336z" opacity="1"/>
</g>
<g mask="url(#J)">
<path fill="#FFF" fill-opacity="1" d="M14.46 6.734a0.798 0.798 0 0 0 -0.54 0.341l-2.234 3.01 -2.957 -2.202a0.796 0.796 0 0 0 -0.646 -0.205 0.808 0.808 0 0 0 -0.37 1.442l-0.011 0.011 3.02 2.252 0.649 0.48a0.808 0.808 0 0 0 1.13 -0.166l0.48 -0.649 2.253 -3.031a0.808 0.808 0 0 0 0.046 -0.903 0.808 0.808 0 0 0 -0.82 -0.38z" opacity="1"/>
</g>
</svg>
<svg x="418">
<defs>
<mask id="L" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="K" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#K)">
<path fill="#EF3F56" fill-opacity="1" d="M12.563 15.231c-3.519 0.584 -6.846 -1.795 -7.43 -5.314l-0.53 -3.187a1.614 1.614 0 0 1 1.33 -1.857l9.558 -1.587a1.614 1.614 0 0 1 1.858 1.328l0.529 3.187c0.584 3.519 -1.796 6.846 -5.315 7.43z" opacity="1"/>
</g>
<g mask="url(#L)">
<path fill="#FFF" fill-opacity="1" d="M14.438 6.923a0.798 0.798 0 0 0 -0.535 0.35l-2.18 3.05 -2.995 -2.15a0.796 0.796 0 0 0 -0.65 -0.194 0.808 0.808 0 0 0 -0.344 1.449l-0.011 0.01 3.06 2.199 0.657 0.47a0.808 0.808 0 0 0 1.126 -0.188l0.47 -0.656 2.198 -3.071a0.808 0.808 0 0 0 0.03 -0.903 0.808 0.808 0 0 0 -0.826 -0.366z" opacity="1"/>
</g>
</svg>
<svg x="440">
<defs>
<mask id="N" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="M" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#M)">
<path fill="#EF3F56" fill-opacity="1" d="M12.688 15.481c-3.509 0.647 -6.877 -1.673 -7.524 -5.181l-0.586 -3.176a1.614 1.614 0 0 1 1.296 -1.881l9.528 -1.757a1.614 1.614 0 0 1 1.881 1.295l0.586 3.177c0.647 3.508 -1.673 6.877 -5.181 7.523z" opacity="1"/>
</g>
<g mask="url(#N)">
<path fill="#FFF" fill-opacity="1" d="M14.415 7.142a0.798 0.798 0 0 0 -0.53 0.359l-2.125 3.087 -3.033 -2.096a0.796 0.796 0 0 0 -0.653 -0.181 0.808 0.808 0 0 0 -0.318 1.454l-0.011 0.011 3.099 2.143 0.665 0.458a0.808 0.808 0 0 0 1.122 -0.207l0.458 -0.665 2.144 -3.11a0.808 0.808 0 0 0 0.014 -0.903 0.808 0.808 0 0 0 -0.832 -0.35z" opacity="1"/>
</g>
</svg>
<svg x="462">
<defs>
<mask id="P" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="O" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#O)">
<path fill="#EF3F56" fill-opacity="1" d="M12.812 15.762c-3.496 0.71 -6.906 -1.55 -7.615 -5.046l-0.642 -3.165a1.614 1.614 0 0 1 1.261 -1.904l9.496 -1.927a1.614 1.614 0 0 1 1.904 1.261l0.642 3.166c0.71 3.496 -1.55 6.905 -5.046 7.615z" opacity="1"/>
</g>
<g mask="url(#P)">
<path fill="#FFF" fill-opacity="1" d="M14.39 7.393a0.798 0.798 0 0 0 -0.523 0.369l-2.07 3.124 -3.07 -2.041a0.796 0.796 0 0 0 -0.656 -0.17 0.808 0.808 0 0 0 -0.292 1.46l-0.01 0.011 3.136 2.087 0.673 0.446a0.808 0.808 0 0 0 1.119 -0.227l0.446 -0.673 2.087 -3.147a0.808 0.808 0 0 0 -0.002 -0.904 0.808 0.808 0 0 0 -0.838 -0.335z" opacity="1"/>
</g>
</svg>
<svg x="484">
<defs>
<mask id="R" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="Q" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#Q)">
<path fill="#EF3F56" fill-opacity="1" d="M12.937 16.077c-3.483 0.772 -6.933 -1.425 -7.705 -4.908l-0.7 -3.153a1.614 1.614 0 0 1 1.228 -1.927l9.46 -2.097a1.614 1.614 0 0 1 1.925 1.227l0.7 3.153c0.772 3.483 -1.426 6.933 -4.908 7.705z" opacity="1"/>
</g>
<g mask="url(#R)">
<path fill="#FFF" fill-opacity="1" d="M14.363 7.68a0.798 0.798 0 0 0 -0.515 0.379l-2.014 3.162 -3.106 -1.986a0.796 0.796 0 0 0 -0.66 -0.159 0.808 0.808 0 0 0 -0.265 1.465l-0.01 0.012 3.173 2.03 0.68 0.434a0.808 0.808 0 0 0 1.116 -0.247l0.433 -0.681 2.031 -3.185a0.808 0.808 0 0 0 -0.018 -0.903 0.808 0.808 0 0 0 -0.845 -0.32z" opacity="1"/>
</g>
</svg>
<svg x="506">
<defs>
<mask id="T" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="S" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#S)">
<path fill="#EF3F56" fill-opacity="1" d="M13.06 16.431c-3.468 0.835 -6.957 -1.3 -7.792 -4.768l-0.755 -3.14a1.614 1.614 0 0 1 1.192 -1.948l9.42 -2.268a1.614 1.614 0 0 1 1.948 1.192l0.756 3.14c0.835 3.468 -1.3 6.957 -4.769 7.792z" opacity="1"/>
</g>
<g mask="url(#T)">
<path fill="#FFF" fill-opacity="1" d="M14.336 8.01a0.798 0.798 0 0 0 -0.51 0.388l-1.955 3.197 -3.142 -1.93a0.796 0.796 0 0 0 -0.662 -0.146 0.808 0.808 0 0 0 -0.24 1.47l-0.01 0.011 3.21 1.974 0.689 0.42a0.808 0.808 0 0 0 1.11 -0.266l0.421 -0.689 1.973 -3.22a0.808 0.808 0 0 0 -0.034 -0.903 0.808 0.808 0 0 0 -0.85 -0.306z" opacity="1"/>
</g>
</svg>
<svg x="528">
<defs>
<mask id="V" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="U" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#U)">
<path fill="#EF3F56" fill-opacity="1" d="M13.183 16.83c-3.452 0.897 -6.979 -1.174 -7.876 -4.627l-0.813 -3.126a1.614 1.614 0 0 1 1.157 -1.97l9.378 -2.436a1.614 1.614 0 0 1 1.97 1.157l0.812 3.126c0.897 3.452 -1.175 6.979 -4.628 7.876z" opacity="1"/>
</g>
<g mask="url(#V)">
<path fill="#FFF" fill-opacity="1" d="M14.307 8.388a0.798 0.798 0 0 0 -0.502 0.396l-1.898 3.233 -3.176 -1.873a0.796 0.796 0 0 0 -0.665 -0.134 0.808 0.808 0 0 0 -0.212 1.473l-0.01 0.012 3.244 1.915 0.696 0.409a0.808 0.808 0 0 0 1.105 -0.287l0.41 -0.696 1.914 -3.256a0.808 0.808 0 0 0 -0.051 -0.902 0.808 0.808 0 0 0 -0.855 -0.29z" opacity="1"/>
</g>
</svg>
<svg x="550">
<defs>
<mask id="X" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="W" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#W)">
<path fill="#EF3F56" fill-opacity="1" d="M13.305 17.282c-3.436 0.959 -7 -1.049 -7.959 -4.485l-0.868 -3.11a1.614 1.614 0 0 1 1.121 -1.99l9.333 -2.606a1.614 1.614 0 0 1 1.99 1.121l0.868 3.11c0.96 3.437 -1.049 7 -4.485 7.96z" opacity="1"/>
</g>
<g mask="url(#X)">
<path fill="#FFF" fill-opacity="1" d="M14.276 8.82a0.798 0.798 0 0 0 -0.494 0.406l-1.84 3.266 -3.209 -1.815a0.796 0.796 0 0 0 -0.667 -0.123 0.808 0.808 0 0 0 -0.186 1.477l-0.01 0.013 3.279 1.856 0.703 0.396a0.808 0.808 0 0 0 1.1 -0.307l0.396 -0.703 1.856 -3.29a0.808 0.808 0 0 0 -0.067 -0.901 0.808 0.808 0 0 0 -0.86 -0.274z" opacity="1"/>
</g>
</svg>
<svg x="572">
<defs>
<mask id="Z" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="Y" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#Y)">
<path fill="#EF3F56" fill-opacity="1" d="M13.426 17.795c-3.419 1.02 -7.018 -0.923 -8.038 -4.341l-0.925 -3.095a1.614 1.614 0 0 1 1.085 -2.01l9.285 -2.772a1.614 1.614 0 0 1 2.009 1.085l0.924 3.095c1.021 3.418 -0.922 7.017 -4.34 8.038z" opacity="1"/>
</g>
<g mask="url(#Z)">
<path fill="#FFF" fill-opacity="1" d="M14.244 9.318a0.798 0.798 0 0 0 -0.487 0.414l-1.78 3.298 -3.241 -1.757a0.796 0.796 0 0 0 -0.67 -0.11 0.808 0.808 0 0 0 -0.16 1.48l-0.009 0.012 3.312 1.797 0.71 0.384a0.808 0.808 0 0 0 1.094 -0.327l0.384 -0.71 1.796 -3.323a0.808 0.808 0 0 0 -0.083 -0.9 0.808 0.808 0 0 0 -0.866 -0.258z" opacity="1"/>
</g>
</svg>
<svg x="594">
<defs>
<mask id="ab" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aa" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#aa)">
<path fill="#EF3F56" fill-opacity="1" d="M13.544 18.382c-3.4 1.081 -7.032 -0.797 -8.114 -4.197l-0.98 -3.077a1.614 1.614 0 0 1 1.05 -2.029l9.232 -2.939a1.614 1.614 0 0 1 2.029 1.05l0.98 3.077c1.081 3.4 -0.798 7.033 -4.197 8.115z" opacity="1"/>
</g>
<g mask="url(#ab)">
<path fill="#FFF" fill-opacity="1" d="M14.21 9.891a0.798 0.798 0 0 0 -0.479 0.423l-1.721 3.33 -3.272 -1.7a0.796 0.796 0 0 0 -0.67 -0.097 0.808 0.808 0 0 0 -0.134 1.482l-0.01 0.013 3.344 1.737 0.717 0.37a0.808 0.808 0 0 0 1.088 -0.345l0.37 -0.718 1.737 -3.354a0.808 0.808 0 0 0 -0.1 -0.898 0.808 0.808 0 0 0 -0.87 -0.243z" opacity="1"/>
</g>
</svg>
<svg x="616">
<defs>
<mask id="ad" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ac" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#ac)">
<path fill="#EF3F56" fill-opacity="1" d="M13.66 19.058c-3.38 1.143 -7.045 -0.671 -8.187 -4.05l-1.035 -3.06a1.614 1.614 0 0 1 1.013 -2.047l9.18 -3.103a1.614 1.614 0 0 1 2.046 1.013l1.034 3.06c1.143 3.379 -0.671 7.045 -4.05 8.187z" opacity="1"/>
</g>
<g mask="url(#ad)">
<path fill="#FFF" fill-opacity="1" d="M14.176 10.557a0.798 0.798 0 0 0 -0.472 0.432l-1.662 3.36 -3.301 -1.64a0.796 0.796 0 0 0 -0.673 -0.087 0.808 0.808 0 0 0 -0.107 1.485l-0.01 0.012 3.375 1.678 0.723 0.358a0.808 0.808 0 0 0 1.082 -0.366l0.358 -0.723 1.676 -3.385a0.808 0.808 0 0 0 -0.115 -0.896 0.808 0.808 0 0 0 -0.874 -0.228z" opacity="1"/>
</g>
</svg>
<svg x="638">
<defs>
<mask id="af" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ae" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5166 0 0 .5 13.667 28.016)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5166 0 0 .5 13.667 28.016)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.985 22.141c-0.57 0 -1.033 0.448 -1.033 1v10c0 0.552 0.463 1 1.033 1 0.57 0 1.033 -0.448 1.033 -1v-10c0 -0.552 -0.462 -1 -1.033 -1zm3.1 -1c-0.57 0 -1.033 0.448 -1.033 1v11c0 0.552 0.462 1 1.033 1 0.57 0 1.033 -0.448 1.033 -1v-11c0 -0.552 -0.463 -1 -1.033 -1zm8.202 11.658l-4.132 -11c-0.185 -0.523 -0.772 -0.8 -1.313 -0.622 -0.539 0.178 -0.827 0.747 -0.642 1.27a0.509 0.509 0 0 0 0.013 0.036l4.133 11c0.185 0.523 0.772 0.801 1.312 0.622 0.54 -0.178 0.828 -0.747 0.643 -1.27 -0.004 -0.012 -0.008 -0.024 -0.014 -0.036zm-14.401 -12.658c-0.57 0 -1.034 0.448 -1.034 1v12c0 0.552 0.463 1 1.034 1 0.57 0 1.033 -0.448 1.033 -1v-12c0 -0.552 -0.463 -1 -1.033 -1z" opacity="1"/>
<g mask="url(#ae)">
<path fill="#EF3F56" fill-opacity="1" d="M13.774 19.847c-3.359 1.202 -7.056 -0.547 -8.258 -3.905l-1.088 -3.041a1.614 1.614 0 0 1 0.976 -2.065l9.123 -3.264a1.614 1.614 0 0 1 2.065 0.976l1.088 3.041c1.202 3.36 -0.547 7.057 -3.906 8.258z" opacity="1"/>
</g>
<g mask="url(#af)">
<path fill="#FFF" fill-opacity="1" d="M14.14 11.339a0.798 0.798 0 0 0 -0.465 0.44l-1.602 3.388 -3.33 -1.582a0.796 0.796 0 0 0 -0.674 -0.074 0.808 0.808 0 0 0 -0.08 1.486l-0.01 0.013 3.403 1.618 0.73 0.345a0.808 0.808 0 0 0 1.075 -0.385l0.345 -0.73 1.616 -3.413a0.808 0.808 0 0 0 -0.13 -0.894 0.808 0.808 0 0 0 -0.879 -0.212z" opacity="1"/>
</g>
</svg>
<svg x="660">
<defs>
<mask id="ah" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ag" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5332 0 0 .5 13.9 28.407)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5332 0 0 .5 13.9 28.407)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.035 22.532c-0.589 0 -1.066 0.448 -1.066 1v10c0 0.552 0.477 1 1.066 1 0.589 0 1.066 -0.448 1.066 -1v-10c0 -0.552 -0.477 -1 -1.066 -1zm3.2 -1c-0.59 0 -1.067 0.448 -1.067 1v11c0 0.552 0.478 1 1.066 1 0.589 0 1.067 -0.448 1.067 -1v-11c0 -0.552 -0.478 -1 -1.067 -1zm8.465 11.658l-4.265 -11c-0.191 -0.523 -0.797 -0.8 -1.355 -0.622 -0.556 0.178 -0.854 0.747 -0.663 1.27l0.014 0.036 4.266 11c0.19 0.523 0.796 0.801 1.354 0.622 0.557 -0.178 0.854 -0.747 0.663 -1.27 -0.004 -0.012 -0.008 -0.024 -0.014 -0.036zm-14.864 -12.658c-0.589 0 -1.067 0.448 -1.067 1v12c0 0.552 0.478 1 1.067 1 0.588 0 1.066 -0.448 1.066 -1v-12c0 -0.552 -0.478 -1 -1.066 -1z" opacity="1"/>
<g mask="url(#ag)">
<path fill="#EF3F56" fill-opacity="1" d="M13.884 20.78c-3.337 1.261 -7.065 -0.423 -8.325 -3.76l-1.141 -3.021a1.614 1.614 0 0 1 0.94 -2.082l9.064 -3.423a1.614 1.614 0 0 1 2.082 0.94l1.14 3.022c1.261 3.337 -0.423 7.065 -3.76 8.325z" opacity="1"/>
</g>
<g mask="url(#ah)">
<path fill="#FFF" fill-opacity="1" d="M14.1 12.267a0.798 0.798 0 0 0 -0.456 0.448l-1.543 3.416 -3.357 -1.523a0.796 0.796 0 0 0 -0.675 -0.063 0.808 0.808 0 0 0 -0.054 1.488l-0.01 0.013 3.431 1.557 0.736 0.333a0.808 0.808 0 0 0 1.068 -0.404l0.332 -0.735 1.557 -3.442a0.808 0.808 0 0 0 -0.147 -0.89 0.808 0.808 0 0 0 -0.881 -0.198z" opacity="1"/>
</g>
</svg>
<svg x="682">
<defs>
<mask id="aj" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ai" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.54974 0 0 .5 14.157 28.922)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.54974 0 0 .5 14.157 28.922)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.11 23.047c-0.606 0 -1.099 0.448 -1.099 1v10c0 0.552 0.493 1 1.1 1 0.607 0 1.1 -0.448 1.1 -1v-10c0 -0.552 -0.493 -1 -1.1 -1zm3.3 -1c-0.608 0 -1.1 0.448 -1.1 1v11c0 0.552 0.492 1 1.1 1 0.606 0 1.099 -0.448 1.099 -1v-11c0 -0.552 -0.493 -1 -1.1 -1zm8.728 11.658l-4.398 -11c-0.197 -0.523 -0.821 -0.8 -1.396 -0.622 -0.574 0.178 -0.881 0.747 -0.684 1.27l0.014 0.036 4.398 11c0.197 0.523 0.821 0.801 1.396 0.622 0.574 -0.178 0.881 -0.747 0.684 -1.27l-0.014 -0.036zm-15.326 -12.658c-0.607 0 -1.1 0.448 -1.1 1v12c0 0.552 0.493 1 1.1 1 0.607 0 1.1 -0.448 1.1 -1v-12c0 -0.552 -0.493 -1 -1.1 -1z" opacity="1"/>
<g mask="url(#ai)">
<path fill="#EF3F56" fill-opacity="1" d="M13.99 21.907c-3.315 1.318 -7.07 -0.301 -8.389 -3.616l-1.193 -3.001a1.614 1.614 0 0 1 0.904 -2.098l9.004 -3.58a1.614 1.614 0 0 1 2.097 0.905l1.193 3.001c1.318 3.315 -0.3 7.071 -3.616 8.39z" opacity="1"/>
</g>
<g mask="url(#aj)">
<path fill="#FFF" fill-opacity="1" d="M14.06 13.39a0.798 0.798 0 0 0 -0.45 0.456l-1.483 3.443 -3.383 -1.465a0.796 0.796 0 0 0 -0.676 -0.051 0.808 0.808 0 0 0 -0.029 1.488l-0.008 0.013 3.457 1.499 0.741 0.32a0.808 0.808 0 0 0 1.061 -0.423l0.32 -0.741 1.496 -3.468a0.808 0.808 0 0 0 -0.162 -0.888 0.808 0.808 0 0 0 -0.885 -0.182z" opacity="1"/>
</g>
</svg>
<svg x="704">
<defs>
<mask id="al" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ak" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.56608 0 0 .5 14.405 29.44)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.56608 0 0 .5 14.405 29.44)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.18 23.565c-0.626 0 -1.133 0.448 -1.133 1v10c0 0.552 0.507 1 1.132 1 0.625 0 1.133 -0.448 1.133 -1v-10c0 -0.552 -0.508 -1 -1.133 -1zm3.396 -1c-0.625 0 -1.132 0.448 -1.132 1v11c0 0.552 0.507 1 1.132 1 0.625 0 1.132 -0.448 1.132 -1v-11c0 -0.552 -0.507 -1 -1.132 -1zm8.988 11.658l-4.529 -11c-0.202 -0.523 -0.845 -0.8 -1.437 -0.622 -0.591 0.178 -0.907 0.747 -0.705 1.27a0.481 0.481 0 0 0 0.015 0.036l4.529 11c0.202 0.523 0.846 0.801 1.438 0.622 0.59 -0.178 0.907 -0.747 0.704 -1.27a0.481 0.481 0 0 0 -0.015 -0.036zm-15.781 -12.658c-0.625 0 -1.132 0.448 -1.132 1v12c0 0.552 0.507 1 1.132 1 0.625 0 1.132 -0.448 1.132 -1v-12c0 -0.552 -0.507 -1 -1.132 -1z" opacity="1"/>
<g mask="url(#ak)">
<path fill="#EF3F56" fill-opacity="1" d="M14.091 23.304c-3.292 1.374 -7.075 -0.181 -8.45 -3.473l-1.243 -2.98a1.614 1.614 0 0 1 0.868 -2.113l8.941 -3.732a1.614 1.614 0 0 1 2.113 0.868l1.244 2.98c1.374 3.292 -0.18 7.076 -3.473 8.45z" opacity="1"/>
</g>
<g mask="url(#al)">
<path fill="#FFF" fill-opacity="1" d="M14.015 14.788a0.798 0.798 0 0 0 -0.44 0.463l-1.425 3.467 -3.408 -1.407a0.796 0.796 0 0 0 -0.677 -0.04 0.808 0.808 0 0 0 -0.003 1.489l-0.009 0.013 3.483 1.44 0.746 0.306a0.808 0.808 0 0 0 1.054 -0.44l0.307 -0.746 1.437 -3.493a0.808 0.808 0 0 0 -0.177 -0.886 0.808 0.808 0 0 0 -0.888 -0.166z" opacity="1"/>
</g>
</svg>
<svg x="726">
<defs>
<mask id="an" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="am" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.58198 0 0 .5 14.61 29.84)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.58198 0 0 .5 14.61 29.84)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.209 23.965c-0.643 0 -1.164 0.448 -1.164 1v10c0 0.552 0.521 1 1.164 1 0.642 0 1.164 -0.448 1.164 -1v-10c0 -0.552 -0.522 -1 -1.164 -1zm3.492 -1c-0.643 0 -1.164 0.448 -1.164 1v11c0 0.552 0.521 1 1.164 1 0.642 0 1.164 -0.448 1.164 -1v-11c0 -0.552 -0.522 -1 -1.164 -1zm9.24 11.658l-4.655 -11c-0.209 -0.523 -0.87 -0.801 -1.479 -0.622 -0.607 0.178 -0.932 0.747 -0.724 1.27a0.474 0.474 0 0 0 0.016 0.036l4.655 11c0.209 0.523 0.87 0.8 1.479 0.622 0.607 -0.178 0.932 -0.747 0.724 -1.27l-0.016 -0.036zm-16.224 -12.658c-0.642 0 -1.164 0.448 -1.164 1v12c0 0.552 0.522 1 1.164 1 0.643 0 1.164 -0.448 1.164 -1v-12c0 -0.552 -0.521 -1 -1.164 -1z" opacity="1"/>
<g mask="url(#am)">
<path fill="#EF3F56" fill-opacity="1" d="M14.185 25.102c-3.269 1.429 -7.077 -0.063 -8.506 -3.331l-1.294 -2.96a1.614 1.614 0 0 1 0.833 -2.126l8.878 -3.882a1.614 1.614 0 0 1 2.126 0.833l1.294 2.96c1.429 3.268 -0.062 7.077 -3.331 8.506z" opacity="1"/>
</g>
<g mask="url(#an)">
<path fill="#FFF" fill-opacity="1" d="M13.967 16.588a0.798 0.798 0 0 0 -0.434 0.47l-1.366 3.49 -3.43 -1.35a0.796 0.796 0 0 0 -0.678 -0.028 0.808 0.808 0 0 0 0.022 1.49l-0.009 0.012 3.506 1.381 0.752 0.295a0.808 0.808 0 0 0 1.046 -0.458l0.294 -0.752 1.379 -3.516a0.808 0.808 0 0 0 -0.192 -0.882 0.808 0.808 0 0 0 -0.89 -0.152z" opacity="1"/>
</g>
</svg>
<svg x="748">
<defs>
<mask id="ap" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ao" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5969 0 0 .5 14.733 30)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5969 0 0 .5 14.733 30)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.169 24.125c-0.66 0 -1.194 0.448 -1.194 1v10c0 0.552 0.535 1 1.194 1 0.659 0 1.193 -0.448 1.193 -1v-10c0 -0.552 -0.534 -1 -1.193 -1zm3.581 -1c-0.659 0 -1.194 0.448 -1.194 1v11c0 0.552 0.535 1 1.194 1 0.659 0 1.194 -0.448 1.194 -1v-11c0 -0.552 -0.535 -1 -1.194 -1zm9.478 11.658l-4.776 -11c-0.213 -0.523 -0.891 -0.801 -1.516 -0.622 -0.623 0.178 -0.956 0.747 -0.742 1.27a0.467 0.467 0 0 0 0.015 0.036l4.775 11c0.214 0.523 0.892 0.801 1.517 0.622 0.623 -0.178 0.956 -0.747 0.742 -1.27l-0.015 -0.036zm-16.64 -12.658c-0.66 0 -1.195 0.448 -1.195 1v12c0 0.552 0.535 1 1.194 1 0.66 0 1.194 -0.448 1.194 -1v-12c0 -0.552 -0.535 -1 -1.194 -1z" opacity="1"/>
<g mask="url(#ao)">
<path fill="#EF3F56" fill-opacity="1" d="M14.27 27.514c-3.246 1.482 -7.078 0.053 -8.56 -3.191l-1.342 -2.938a1.614 1.614 0 0 1 0.797 -2.14l8.814 -4.026a1.614 1.614 0 0 1 2.14 0.798l1.342 2.938c1.482 3.244 0.053 7.077 -3.192 8.56z" opacity="1"/>
</g>
<g mask="url(#ap)">
<path fill="#FFF" fill-opacity="1" d="M13.912 19.005a0.798 0.798 0 0 0 -0.426 0.478l-1.309 3.512 -3.452 -1.294a0.796 0.796 0 0 0 -0.678 -0.017 0.808 0.808 0 0 0 0.046 1.488l-0.008 0.014 3.528 1.323 0.756 0.282a0.808 0.808 0 0 0 1.039 -0.475l0.282 -0.756 1.32 -3.538a0.808 0.808 0 0 0 -0.206 -0.88 0.808 0.808 0 0 0 -0.892 -0.137z" opacity="1"/>
</g>
</svg>
<svg x="770">
<defs>
<mask id="ar" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aq" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.60979 0 0 .5 14.812 29.779)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.60979 0 0 .5 14.812 29.779)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.105 23.904c-0.673 0 -1.22 0.448 -1.22 1v10c0 0.552 0.547 1 1.22 1 0.674 0 1.22 -0.448 1.22 -1v-10c0 -0.552 -0.546 -1 -1.22 -1zm3.659 -1c-0.673 0 -1.22 0.448 -1.22 1v11c0 0.552 0.547 1 1.22 1 0.673 0 1.22 -0.448 1.22 -1v-11c0 -0.552 -0.547 -1 -1.22 -1zm9.682 11.658l-4.878 -11c-0.218 -0.523 -0.911 -0.801 -1.549 -0.622 -0.637 0.178 -0.977 0.747 -0.758 1.27a0.462 0.462 0 0 0 0.015 0.036l4.879 11c0.218 0.523 0.91 0.8 1.549 0.622 0.636 -0.178 0.976 -0.747 0.758 -1.27l-0.016 -0.036zm-17 -12.658c-0.673 0 -1.219 0.448 -1.219 1v12c0 0.552 0.546 1 1.22 1 0.673 0 1.22 -0.448 1.22 -1v-12c0 -0.552 -0.547 -1 -1.22 -1z" opacity="1"/>
<g mask="url(#aq)">
<path fill="#EF3F56" fill-opacity="1" d="M14.342 30.655c-3.22 1.534 -7.075 0.166 -8.61 -3.055l-1.388 -2.916a1.614 1.614 0 0 1 0.764 -2.152l8.748 -4.166a1.614 1.614 0 0 1 2.153 0.764l1.388 2.916c1.534 3.22 0.166 7.075 -3.055 8.61z" opacity="1"/>
</g>
<g mask="url(#ar)">
<path fill="#FFF" fill-opacity="1" d="M13.85 22.153a0.798 0.798 0 0 0 -0.418 0.484l-1.253 3.533 -3.473 -1.24a0.796 0.796 0 0 0 -0.678 -0.005 0.808 0.808 0 0 0 0.07 1.487l-0.008 0.013 3.548 1.267 0.761 0.27a0.808 0.808 0 0 0 1.03 -0.49l0.27 -0.761 1.266 -3.56a0.808 0.808 0 0 0 -0.22 -0.875 0.808 0.808 0 0 0 -0.896 -0.123z" opacity="1"/>
</g>
</svg>
<svg x="792">
<defs>
<mask id="at" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="as" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.61897 0 0 .5 14.884 29.251)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.61897 0 0 .5 14.884 29.251)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.076 23.376c-0.683 0 -1.237 0.448 -1.237 1v10c0 0.552 0.554 1 1.237 1 0.684 0 1.238 -0.448 1.238 -1v-10c0 -0.552 -0.554 -1 -1.238 -1zm3.714 -1c-0.683 0 -1.238 0.448 -1.238 1v11c0 0.552 0.555 1 1.238 1 0.684 0 1.238 -0.448 1.238 -1v-11c0 -0.552 -0.554 -1 -1.238 -1zm9.828 11.658l-4.951 -11c-0.222 -0.523 -0.925 -0.801 -1.573 -0.622 -0.646 0.178 -0.991 0.747 -0.77 1.27a0.459 0.459 0 0 0 0.016 0.036l4.952 11c0.222 0.523 0.925 0.801 1.572 0.622 0.647 -0.178 0.992 -0.747 0.77 -1.27a0.459 0.459 0 0 0 -0.016 -0.036zm-17.255 -12.658c-0.684 0 -1.238 0.448 -1.238 1v12c0 0.552 0.554 1 1.238 1 0.683 0 1.238 -0.448 1.238 -1v-12c0 -0.552 -0.555 -1 -1.238 -1z" opacity="1"/>
<g mask="url(#as)">
<path fill="#EF3F56" fill-opacity="1" d="M14.412 33.611c-3.196 1.583 -7.072 0.274 -8.655 -2.923l-1.433 -2.894a1.614 1.614 0 0 1 0.73 -2.164l8.684 -4.3a1.614 1.614 0 0 1 2.164 0.731l1.433 2.895c1.583 3.197 0.274 7.072 -2.923 8.655z" opacity="1"/>
</g>
<g mask="url(#at)">
<path fill="#FFF" fill-opacity="1" d="M13.79 25.117a0.798 0.798 0 0 0 -0.411 0.49l-1.199 3.552 -3.49 -1.185a0.796 0.796 0 0 0 -0.679 0.004 0.808 0.808 0 0 0 0.093 1.486l-0.008 0.014 3.567 1.212 0.765 0.258a0.808 0.808 0 0 0 1.023 -0.506l0.259 -0.765 1.21 -3.578a0.808 0.808 0 0 0 -0.234 -0.873 0.808 0.808 0 0 0 -0.897 -0.109z" opacity="1"/>
</g>
</svg>
<svg x="814">
<defs>
<mask id="av" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="au" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.62351 0 0 .5 14.922 28.62)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.62351 0 0 .5 14.922 28.62)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.064 22.746c-0.688 0 -1.247 0.448 -1.247 1v10c0 0.552 0.56 1 1.247 1 0.689 0 1.247 -0.448 1.247 -1v-10c0 -0.552 -0.558 -1 -1.247 -1zm3.741 -1c-0.688 0 -1.247 0.448 -1.247 1v11c0 0.552 0.56 1 1.247 1 0.689 0 1.247 -0.448 1.247 -1v-11c0 -0.552 -0.558 -1 -1.247 -1zm9.9 11.658l-4.988 -11c-0.223 -0.523 -0.931 -0.801 -1.583 -0.622 -0.651 0.178 -1 0.747 -0.776 1.27l0.016 0.036 4.988 11c0.224 0.523 0.932 0.8 1.584 0.622 0.651 -0.178 0.999 -0.747 0.776 -1.27a0.457 0.457 0 0 0 -0.016 -0.036zm-17.382 -12.658c-0.688 0 -1.247 0.448 -1.247 1v12c0 0.552 0.559 1 1.247 1 0.689 0 1.247 -0.448 1.247 -1v-12c0 -0.552 -0.558 -1 -1.247 -1z" opacity="1"/>
<g mask="url(#au)">
<path fill="#EF3F56" fill-opacity="1" d="M14.489 35.462c-3.174 1.63 -7.068 0.378 -8.697 -2.796l-1.475 -2.873a1.614 1.614 0 0 1 0.698 -2.174l8.62 -4.426a1.614 1.614 0 0 1 2.174 0.699l1.475 2.873c1.63 3.173 0.378 7.067 -2.795 8.697z" opacity="1"/>
</g>
<g mask="url(#av)">
<path fill="#FFF" fill-opacity="1" d="M13.741 26.978a0.798 0.798 0 0 0 -0.403 0.497l-1.146 3.568 -3.508 -1.134a0.796 0.796 0 0 0 -0.678 0.014 0.808 0.808 0 0 0 0.114 1.485l-0.007 0.013 3.584 1.16 0.769 0.248a0.808 0.808 0 0 0 1.016 -0.522l0.247 -0.769 1.157 -3.595a0.808 0.808 0 0 0 -0.247 -0.869 0.808 0.808 0 0 0 -0.898 -0.096z" opacity="1"/>
</g>
</svg>
<svg x="836">
<defs>
<mask id="ax" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aw" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.62484 0 0 .5 14.911 28.093)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.62484 0 0 .5 14.911 28.093)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.04 22.218c-0.69 0 -1.25 0.448 -1.25 1v10c0 0.552 0.56 1 1.25 1s1.249 -0.448 1.249 -1v-10c0 -0.552 -0.56 -1 -1.25 -1zm3.748 -1c-0.69 0 -1.25 0.448 -1.25 1v11c0 0.552 0.56 1 1.25 1s1.25 -0.448 1.25 -1v-11c0 -0.552 -0.56 -1 -1.25 -1zm9.922 11.658l-5 -11c-0.223 -0.523 -0.933 -0.801 -1.586 -0.622 -0.653 0.178 -1.001 0.747 -0.778 1.27a0.457 0.457 0 0 0 0.017 0.036l4.998 11c0.224 0.523 0.934 0.801 1.588 0.622 0.652 -0.178 1 -0.747 0.777 -1.27a0.457 0.457 0 0 0 -0.016 -0.036zm-17.42 -12.658c-0.69 0 -1.25 0.448 -1.25 1v12c0 0.552 0.56 1 1.25 1s1.25 -0.448 1.25 -1v-12c0 -0.552 -0.56 -1 -1.25 -1z" opacity="1"/>
<g mask="url(#aw)">
<path fill="#EF3F56" fill-opacity="1" d="M14.567 36.513c-3.15 1.673 -7.061 0.475 -8.734 -2.676l-1.515 -2.852a1.614 1.614 0 0 1 0.669 -2.184l8.558 -4.544a1.614 1.614 0 0 1 2.183 0.669l1.515 2.852c1.673 3.151 0.475 7.062 -2.676 8.735z" opacity="1"/>
</g>
<g mask="url(#ax)">
<path fill="#FFF" fill-opacity="1" d="M13.703 28.04a0.798 0.798 0 0 0 -0.396 0.502l-1.097 3.584 -3.523 -1.085a0.796 0.796 0 0 0 -0.678 0.023 0.808 0.808 0 0 0 0.134 1.483l-0.007 0.014 3.6 1.11 0.772 0.237a0.808 0.808 0 0 0 1.009 -0.536l0.236 -0.772 1.108 -3.61a0.808 0.808 0 0 0 -0.258 -0.866 0.808 0.808 0 0 0 -0.9 -0.084z" opacity="1"/>
</g>
</svg>
<svg x="858">
<defs>
<mask id="az" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="ay" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.625 0 0 .5 14.874 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.625 0 0 .5 14.874 27.875)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22c-0.69 0 -1.25 0.448 -1.25 1v10c0 0.552 0.56 1 1.25 1s1.25 -0.448 1.25 -1v-10c0 -0.552 -0.56 -1 -1.25 -1zm3.75 -1c-0.69 0 -1.25 0.448 -1.25 1v11c0 0.552 0.56 1 1.25 1s1.25 -0.448 1.25 -1v-11c0 -0.552 -0.56 -1 -1.25 -1zm9.924 11.658l-5 -11c-0.224 -0.523 -0.934 -0.801 -1.588 -0.622 -0.652 0.178 -1.001 0.747 -0.777 1.27l0.016 0.036 5 11c0.224 0.523 0.934 0.801 1.587 0.622 0.653 -0.178 1.002 -0.747 0.778 -1.27a0.457 0.457 0 0 0 -0.016 -0.036zm-17.424 -12.658c-0.69 0 -1.25 0.448 -1.25 1v12c0 0.552 0.56 1 1.25 1s1.25 -0.448 1.25 -1v-12c0 -0.552 -0.56 -1 -1.25 -1z" opacity="1"/>
<g mask="url(#ay)">
<path fill="#EF3F56" fill-opacity="1" d="M14.642 37.113c-3.13 1.713 -7.055 0.564 -8.768 -2.566l-1.55 -2.833a1.614 1.614 0 0 1 0.642 -2.192l8.5 -4.651a1.614 1.614 0 0 1 2.192 0.641l1.55 2.834c1.712 3.13 0.563 7.055 -2.566 8.767z" opacity="1"/>
</g>
<g mask="url(#az)">
<path fill="#FFF" fill-opacity="1" d="M13.672 28.652a0.798 0.798 0 0 0 -0.39 0.507l-1.052 3.597 -3.537 -1.041a0.796 0.796 0 0 0 -0.677 0.032 0.808 0.808 0 0 0 0.153 1.48l-0.007 0.015 3.614 1.065 0.774 0.227a0.808 0.808 0 0 0 1.002 -0.548l0.227 -0.775 1.062 -3.624a0.808 0.808 0 0 0 -0.269 -0.863 0.808 0.808 0 0 0 -0.9 -0.072z" opacity="1"/>
</g>
</svg>
<svg x="880">
<defs>
<mask id="aB" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aA" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.61111 0 0 .5 14.775 27.817)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.61111 0 0 .5 14.775 27.817)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.054 21.942c-0.674 0 -1.222 0.448 -1.222 1v10c0 0.552 0.548 1 1.222 1 0.675 0 1.223 -0.448 1.223 -1v-10c0 -0.552 -0.548 -1 -1.223 -1zm3.667 -1c-0.675 0 -1.222 0.448 -1.222 1v11c0 0.552 0.547 1 1.222 1 0.675 0 1.222 -0.448 1.222 -1v-11c0 -0.552 -0.547 -1 -1.222 -1zm9.703 11.658l-4.889 -11c-0.218 -0.523 -0.913 -0.8 -1.552 -0.622 -0.638 0.178 -0.979 0.747 -0.76 1.27l0.016 0.036 4.889 11c0.219 0.523 0.913 0.801 1.552 0.622 0.638 -0.178 0.979 -0.747 0.76 -1.27l-0.016 -0.036zm-17.036 -12.658c-0.675 0 -1.222 0.448 -1.222 1v12c0 0.552 0.547 1 1.222 1 0.674 0 1.222 -0.448 1.222 -1v-12c0 -0.552 -0.548 -1 -1.222 -1z" opacity="1"/>
<g mask="url(#aA)">
<path fill="#EF3F56" fill-opacity="1" d="M14.708 37.444c-3.11 1.746 -7.048 0.64 -8.795 -2.47l-1.58 -2.817a1.614 1.614 0 0 1 0.617 -2.199l8.449 -4.743a1.614 1.614 0 0 1 2.199 0.617l1.58 2.817c1.747 3.11 0.64 7.048 -2.47 8.795z" opacity="1"/>
</g>
<g mask="url(#aB)">
<path fill="#FFF" fill-opacity="1" d="M13.646 28.993a0.798 0.798 0 0 0 -0.384 0.512l-1.013 3.608 -3.548 -1.003a0.796 0.796 0 0 0 -0.677 0.04 0.808 0.808 0 0 0 0.17 1.479l-0.008 0.014 3.626 1.026 0.777 0.218a0.808 0.808 0 0 0 0.995 -0.559l0.219 -0.777 1.023 -3.636a0.808 0.808 0 0 0 -0.279 -0.859 0.808 0.808 0 0 0 -0.9 -0.063z" opacity="1"/>
</g>
</svg>
<svg x="902">
<defs>
<mask id="aD" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aC" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.59722 0 0 .5 14.62 27.745)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.59722 0 0 .5 14.62 27.745)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.052 21.87c-0.659 0 -1.194 0.448 -1.194 1v10c0 0.552 0.535 1 1.194 1 0.66 0 1.195 -0.448 1.195 -1v-10c0 -0.552 -0.535 -1 -1.195 -1zm3.584 -1c-0.66 0 -1.195 0.448 -1.195 1v11c0 0.552 0.535 1 1.195 1 0.659 0 1.194 -0.448 1.194 -1v-11c0 -0.552 -0.535 -1 -1.194 -1zm9.482 11.658l-4.777 -11c-0.214 -0.523 -0.893 -0.801 -1.517 -0.622 -0.624 0.178 -0.957 0.747 -0.743 1.27a0.467 0.467 0 0 0 0.015 0.036l4.778 11c0.214 0.523 0.892 0.8 1.517 0.622 0.623 -0.178 0.957 -0.747 0.743 -1.27a0.467 0.467 0 0 0 -0.016 -0.036zm-16.649 -12.658c-0.66 0 -1.194 0.448 -1.194 1v12c0 0.552 0.535 1 1.194 1 0.66 0 1.194 -0.448 1.194 -1v-12c0 -0.552 -0.535 -1 -1.194 -1z" opacity="1"/>
<g mask="url(#aC)">
<path fill="#EF3F56" fill-opacity="1" d="M14.76 37.601c-3.096 1.772 -7.043 0.7 -8.815 -2.397l-1.605 -2.803a1.614 1.614 0 0 1 0.6 -2.204l8.409 -4.813a1.614 1.614 0 0 1 2.204 0.6l1.604 2.802c1.772 3.096 0.699 7.043 -2.397 8.815z" opacity="1"/>
</g>
<g mask="url(#aD)">
<path fill="#FFF" fill-opacity="1" d="M13.627 29.16a0.798 0.798 0 0 0 -0.38 0.515l-0.983 3.617 -3.556 -0.974a0.796 0.796 0 0 0 -0.676 0.045 0.808 0.808 0 0 0 0.181 1.478l-0.007 0.014 3.634 0.996 0.78 0.212a0.808 0.808 0 0 0 0.99 -0.567l0.212 -0.78 0.993 -3.643a0.808 0.808 0 0 0 -0.286 -0.857 0.808 0.808 0 0 0 -0.902 -0.056z" opacity="1"/>
</g>
</svg>
<svg x="924">
<defs>
<mask id="aF" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aE" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.58333 0 0 .5 14.429 27.718)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.58333 0 0 .5 14.429 27.718)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8.013 21.843c-0.644 0 -1.166 0.448 -1.166 1v10c0 0.552 0.522 1 1.166 1 0.644 0 1.167 -0.448 1.167 -1v-10c0 -0.552 -0.523 -1 -1.167 -1zm3.5 -1c-0.644 0 -1.166 0.448 -1.166 1v11c0 0.552 0.522 1 1.166 1 0.644 0 1.167 -0.448 1.167 -1v-11c0 -0.552 -0.523 -1 -1.167 -1zm9.262 11.658l-4.666 -11c-0.21 -0.523 -0.872 -0.801 -1.482 -0.622 -0.609 0.178 -0.934 0.747 -0.726 1.27a0.473 0.473 0 0 0 0.016 0.036l4.666 11c0.21 0.523 0.872 0.8 1.482 0.622 0.609 -0.178 0.934 -0.747 0.726 -1.27l-0.016 -0.036zm-16.262 -12.658c-0.644 0 -1.166 0.448 -1.166 1v12c0 0.552 0.522 1 1.166 1 0.644 0 1.167 -0.448 1.167 -1v-12c0 -0.552 -0.523 -1 -1.167 -1z" opacity="1"/>
<g mask="url(#aE)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aF)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.62 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.048 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.982 0.78 0.21a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.052z" opacity="1"/>
</g>
</svg>
<svg x="946">
<defs>
<mask id="aH" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aG" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.56944 0 0 .5 14.233 27.728)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.56944 0 0 .5 14.233 27.728)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.97 21.853c-0.629 0 -1.139 0.448 -1.139 1v10c0 0.552 0.51 1 1.139 1s1.139 -0.448 1.139 -1v-10c0 -0.552 -0.51 -1 -1.139 -1zm3.417 -1c-0.629 0 -1.14 0.448 -1.14 1v11c0 0.552 0.511 1 1.14 1 0.628 0 1.139 -0.448 1.139 -1v-11c0 -0.552 -0.51 -1 -1.14 -1zm9.041 11.658l-4.555 -11c-0.204 -0.523 -0.851 -0.8 -1.447 -0.622 -0.594 0.178 -0.912 0.747 -0.708 1.27a0.48 0.48 0 0 0 0.015 0.036l4.555 11c0.204 0.523 0.851 0.801 1.447 0.622 0.594 -0.178 0.912 -0.747 0.708 -1.27a0.48 0.48 0 0 0 -0.015 -0.036zm-15.875 -12.658c-0.628 0 -1.139 0.448 -1.139 1v12c0 0.552 0.51 1 1.14 1 0.628 0 1.138 -0.448 1.138 -1v-12c0 -0.552 -0.51 -1 -1.139 -1z" opacity="1"/>
<g mask="url(#aG)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aH)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="968">
<defs>
<mask id="aJ" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aI" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.55556 0 0 .5 14.046 27.757)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.55556 0 0 .5 14.046 27.757)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.936 21.882c-0.614 0 -1.112 0.448 -1.112 1v10c0 0.552 0.498 1 1.112 1 0.613 0 1.11 -0.448 1.11 -1v-10c0 -0.552 -0.497 -1 -1.11 -1zm3.333 -1c-0.613 0 -1.111 0.448 -1.111 1v11c0 0.552 0.498 1 1.11 1 0.614 0 1.112 -0.448 1.112 -1v-11c0 -0.552 -0.498 -1 -1.111 -1zm8.821 11.658l-4.444 -11c-0.2 -0.523 -0.83 -0.8 -1.412 -0.622 -0.58 0.178 -0.89 0.747 -0.69 1.27a0.487 0.487 0 0 0 0.014 0.036l4.444 11c0.2 0.523 0.83 0.801 1.411 0.622 0.58 -0.178 0.89 -0.747 0.691 -1.27a0.487 0.487 0 0 0 -0.014 -0.036zm-15.488 -12.658c-0.613 0 -1.11 0.448 -1.11 1v12c0 0.552 0.497 1 1.11 1 0.614 0 1.111 -0.448 1.111 -1v-12c0 -0.552 -0.497 -1 -1.11 -1z" opacity="1"/>
<g mask="url(#aI)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aJ)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="990">
<defs>
<mask id="aL" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aK" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.54167 0 0 .5 13.872 27.794)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.54167 0 0 .5 13.872 27.794)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.915 21.919c-0.598 0 -1.083 0.448 -1.083 1v10c0 0.552 0.485 1 1.083 1s1.084 -0.448 1.084 -1v-10c0 -0.552 -0.486 -1 -1.084 -1zm3.25 -1c-0.598 0 -1.083 0.448 -1.083 1v11c0 0.552 0.485 1 1.083 1s1.084 -0.448 1.084 -1v-11c0 -0.552 -0.486 -1 -1.084 -1zm8.6 11.658l-4.333 -11c-0.193 -0.523 -0.809 -0.801 -1.375 -0.622 -0.566 0.178 -0.868 0.747 -0.674 1.27a0.494 0.494 0 0 0 0.014 0.036l4.333 11c0.194 0.523 0.81 0.8 1.376 0.622 0.566 -0.178 0.868 -0.747 0.674 -1.27a0.494 0.494 0 0 0 -0.014 -0.036zm-15.1 -12.658c-0.598 0 -1.083 0.448 -1.083 1v12c0 0.552 0.485 1 1.083 1s1.084 -0.448 1.084 -1v-12c0 -0.552 -0.486 -1 -1.084 -1z" opacity="1"/>
<g mask="url(#aK)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aL)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="1012">
<defs>
<mask id="aN" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aM" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.52778 0 0 .5 13.719 27.83)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.52778 0 0 .5 13.719 27.83)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.914 21.956c-0.583 0 -1.056 0.448 -1.056 1v10c0 0.552 0.473 1 1.056 1 0.583 0 1.056 -0.448 1.056 -1v-10c0 -0.552 -0.473 -1 -1.056 -1zm3.167 -1c-0.583 0 -1.056 0.448 -1.056 1v11c0 0.552 0.473 1 1.056 1 0.582 0 1.055 -0.448 1.055 -1v-11c0 -0.552 -0.473 -1 -1.055 -1zm8.38 11.658l-4.222 -11c-0.19 -0.523 -0.789 -0.801 -1.341 -0.622 -0.551 0.178 -0.846 0.747 -0.657 1.27l0.014 0.036 4.222 11c0.19 0.523 0.789 0.8 1.34 0.622 0.552 -0.178 0.846 -0.747 0.657 -1.27l-0.013 -0.036zm-14.714 -12.658c-0.582 0 -1.055 0.448 -1.055 1v12c0 0.552 0.473 1 1.055 1 0.583 0 1.056 -0.448 1.056 -1v-12c0 -0.552 -0.473 -1 -1.056 -1z" opacity="1"/>
<g mask="url(#aM)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aN)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="1034">
<defs>
<mask id="aP" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aO" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.51389 0 0 .5 13.59 27.86)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.51389 0 0 .5 13.59 27.86)"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M7.938 21.986c-0.567 0 -1.027 0.448 -1.027 1v10c0 0.552 0.46 1 1.027 1 0.568 0 1.028 -0.448 1.028 -1v-10c0 -0.552 -0.46 -1 -1.028 -1zm3.084 -1c-0.568 0 -1.028 0.448 -1.028 1v11c0 0.552 0.46 1 1.028 1 0.567 0 1.028 -0.448 1.028 -1v-11c0 -0.552 -0.46 -1 -1.028 -1zm8.16 11.658l-4.112 -11c-0.184 -0.523 -0.768 -0.801 -1.305 -0.622 -0.537 0.178 -0.823 0.747 -0.64 1.27a0.51 0.51 0 0 0 0.014 0.036l4.111 11c0.184 0.523 0.768 0.8 1.305 0.622 0.537 -0.178 0.824 -0.747 0.64 -1.27l-0.014 -0.036zm-14.327 -12.658c-0.567 0 -1.028 0.448 -1.028 1v12c0 0.552 0.46 1 1.028 1 0.567 0 1.028 -0.448 1.028 -1v-12c0 -0.552 -0.46 -1 -1.028 -1z" opacity="1"/>
<g mask="url(#aO)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aP)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="1056">
<defs>
<mask id="aR" mask-type="alpha">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.658 0.5 2.375 5.876 8.467 -1.751 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" opacity="1" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
</mask>
<mask id="aQ" mask-type="alpha">
<g opacity="1">
<path fill="#11DBEA" fill-opacity="1" d="M-29.125 -76.875l-15.5 48.625 21.375 12 5.5 -0.75 3 -0.25 2.25 3.75 5.5 1 0.75 -2.25 3.25 -0.125 6.229 0.505 4.259 11.371 7.012 -7.251 2.75 -18.125 6 -25.25 -0.75 -22.25 -51.625 -1z" transform="matrix(.5 0 0 .5 13.499 27.875)"/>
<path fill-opacity="0" stroke="#871111" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" stroke-opacity="1" stroke-width="0" d="M-1.063 -10.563l-7.75 24.313 10.687 6 2.75 -0.375 1.5 -0.125 1.125 1.875 2.75 0.5 0.375 -1.125 1.625 -0.063 3.115 0.253 2.129 5.685 3.506 -3.625 1.375 -9.062 3 -12.625 -0.375 -11.125 -25.812 -0.5z"/>
</g>
</mask>
</defs>
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#aQ)">
<path fill="#EF3F56" fill-opacity="1" d="M14.783 37.647c-3.09 1.784 -7.04 0.725 -8.824 -2.364l-1.615 -2.797a1.614 1.614 0 0 1 0.591 -2.206l8.391 -4.845a1.614 1.614 0 0 1 2.206 0.591l1.615 2.797c1.784 3.09 0.725 7.04 -2.364 8.824z" opacity="1"/>
</g>
<g mask="url(#aR)">
<path fill="#FFF" fill-opacity="1" d="M13.62 29.21a0.798 0.798 0 0 0 -0.379 0.516l-0.97 3.621 -3.559 -0.96a0.796 0.796 0 0 0 -0.677 0.047 0.808 0.808 0 0 0 0.188 1.477l-0.007 0.014 3.637 0.983 0.78 0.209a0.808 0.808 0 0 0 0.989 -0.571l0.209 -0.78 0.979 -3.648a0.808 0.808 0 0 0 -0.29 -0.856 0.808 0.808 0 0 0 -0.9 -0.051z" opacity="1"/>
</g>
</svg>
<svg x="1078">
<path fill="context-fill" fill-opacity="1" d="M8 22a1 1 0 0 0 -1 1v10a1 1 0 0 0 2 0v-10a1 1 0 0 0 -1 -1zm3 -1a1 1 0 0 0 -1 1v11a1 1 0 0 0 2 0v-11a1 1 0 0 0 -1 -1zm7.939 11.658l-4 -11a1 1 0 1 0 -1.879 0.684l4 11a1 1 0 1 0 1.892 -0.648l-0.013 -0.036zm-13.939 -12.658a1 1 0 0 0 -1 1v12a1 1 0 0 0 2 0v-12a1 1 0 0 0 -1 -1z" opacity="1"/>
<g mask="url(#bS)">
<path fill="#EF3F56" fill-opacity="1" d="M8.8 14.017c-3.538 -1.288 -5.363 -5.201 -4.075 -8.74l1.166 -3.203a1.704 1.704 0 0 1 2.185 -1.02l9.611 3.499a1.704 1.704 0 0 1 1.019 2.185l-1.166 3.203c-1.288 3.539 -5.201 5.364 -8.74 4.076z" opacity="1"/>
</g>
</svg>
</svg>

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -0,0 +1,157 @@
<!-- 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="240" height="18" fill="context-fill">
<svg width="20" height="18">
<defs>
<filter id="a" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<g>
<g fill-opacity=".25">
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
</g>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#a)" transform="translate(10.005 9.286) scale(1.02438)"/>
</g>
</svg>
<svg width="20" height="18" x="20">
<defs>
<filter id="b" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<g>
<g fill-opacity=".25">
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
<path d="M10 16.41c-4.527 0 -8.179 -3.826 -8.179 -8.352v-4.097a2.05 2.05 0 0 1 2.05 -2.05h12.253a2.05 2.05 0 0 1 2.049 2.05v4.097c0 4.526 -3.648 8.352 -8.174 8.352z"/>
</g>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#b)" transform="translate(10.005 9.286) scale(1.02438)"/>
</g>
</svg>
<svg width="20" height="18" x="40">
<defs>
<filter id="c" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#c)" transform="translate(10.005 10.054) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="60">
<defs>
<filter id="d" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#d)" transform="translate(10.009 10.057) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="80">
<defs>
<filter id="e" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#e)" transform="translate(10.005 10.054) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="100">
<defs>
<filter id="f" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#f)" transform="translate(10.005 10.016) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="120">
<defs>
<filter id="g" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#g)" transform="translate(10.005 9.925) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="140">
<defs>
<filter id="h" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#h)" transform="translate(10.005 9.802) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="160">
<defs>
<filter id="i" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill-opacity=".25" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path fill="#EE4055" d="M9.997 16.955c-4.978 0 -8.995 -4.208 -8.995 -9.187v-4.507a2.253 2.253 0 0 1 2.254 -2.254h13.479a2.253 2.253 0 0 1 2.253 2.254v4.507c0 4.979 -4.012 9.187 -8.99 9.187z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#i)" transform="translate(10.005 9.66) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="180">
<defs>
<filter id="j" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.997 16.924c-4.958 0 -8.96 -4.192 -8.96 -9.151v-4.49a2.244 2.244 0 0 1 2.245 -2.245h13.426a2.244 2.244 0 0 1 2.245 2.245v4.49c0 4.959 -3.997 9.15 -8.956 9.15z"/>
<path fill-opacity=".25" d="M9.997 16.924c-4.958 0 -8.96 -4.192 -8.96 -9.151v-4.49a2.244 2.244 0 0 1 2.245 -2.245h13.426a2.244 2.244 0 0 1 2.245 2.245v4.49c0 4.959 -3.997 9.15 -8.956 9.15z"/>
<path fill-opacity=".25" d="M9.997 16.924c-4.958 0 -8.96 -4.192 -8.96 -9.151v-4.49a2.244 2.244 0 0 1 2.245 -2.245h13.426a2.244 2.244 0 0 1 2.245 2.245v4.49c0 4.959 -3.997 9.15 -8.956 9.15z"/>
<path fill="#EE4055" d="M9.997 16.924c-4.958 0 -8.96 -4.192 -8.96 -9.151v-4.49a2.244 2.244 0 0 1 2.245 -2.245h13.426a2.244 2.244 0 0 1 2.245 2.245v4.49c0 4.959 -3.997 9.15 -8.956 9.15z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#j)" transform="translate(10.005 9.512) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="200">
<defs>
<filter id="k" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.998 16.84c-4.908 0 -8.868 -4.148 -8.868 -9.056v-4.443a2.222 2.222 0 0 1 2.222 -2.222h13.287a2.222 2.222 0 0 1 2.222 2.222v4.443c0 4.908 -3.956 9.057 -8.863 9.057z"/>
<path fill-opacity=".25" d="M9.998 16.84c-4.908 0 -8.868 -4.148 -8.868 -9.056v-4.443a2.222 2.222 0 0 1 2.222 -2.222h13.287a2.222 2.222 0 0 1 2.222 2.222v4.443c0 4.908 -3.956 9.057 -8.863 9.057z"/>
<path fill-opacity=".25" d="M9.998 16.84c-4.908 0 -8.868 -4.148 -8.868 -9.056v-4.443a2.222 2.222 0 0 1 2.222 -2.222h13.287a2.222 2.222 0 0 1 2.222 2.222v4.443c0 4.908 -3.956 9.057 -8.863 9.057z"/>
<path fill="#EE4055" d="M9.998 16.84c-4.908 0 -8.868 -4.148 -8.868 -9.056v-4.443a2.222 2.222 0 0 1 2.222 -2.222h13.287a2.222 2.222 0 0 1 2.222 2.222v4.443c0 4.908 -3.956 9.057 -8.863 9.057z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#k)" transform="translate(10.005 9.372) scale(1.02438)"/>
</svg>
<svg width="20" height="18" x="220">
<defs>
<filter id="l" width="100%" height="100%" x="0%" y="0%" filterUnits="objectBoundingBox">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
</defs>
<path fill-opacity=".25" d="M9.998 16.723c-4.835 0 -8.737 -4.087 -8.737 -8.922v-4.378a2.189 2.189 0 0 1 2.19 -2.189h13.09a2.19 2.19 0 0 1 2.19 2.19v4.376c0 4.835 -3.898 8.922 -8.733 8.922z"/>
<path fill-opacity=".25" d="M9.998 16.723c-4.835 0 -8.737 -4.087 -8.737 -8.922v-4.378a2.189 2.189 0 0 1 2.19 -2.189h13.09a2.19 2.19 0 0 1 2.19 2.19v4.376c0 4.835 -3.898 8.922 -8.733 8.922z"/>
<path fill-opacity=".25" d="M9.998 16.723c-4.835 0 -8.737 -4.087 -8.737 -8.922v-4.378a2.189 2.189 0 0 1 2.19 -2.189h13.09a2.19 2.19 0 0 1 2.19 2.19v4.376c0 4.835 -3.898 8.922 -8.733 8.922z"/>
<path fill="#EE4055" d="M9.998 16.723c-4.835 0 -8.737 -4.087 -8.737 -8.922v-4.378a2.189 2.189 0 0 1 2.19 -2.189h13.09a2.19 2.19 0 0 1 2.19 2.19v4.376c0 4.835 -3.898 8.922 -8.733 8.922z"/>
<path d="M3.986 -3.055a0.991 0.991 0 0 0 -0.726 0.319l-3.281 3.284 -3.224 -3.235a0.984 0.984 0 0 0 -0.754 -0.368 1.001 1.001 0 0 0 -0.715 1.7l-0.016 0.011 3.294 3.306 0.706 0.707a1 1 0 0 0 1.414 0l0.707 -0.707 3.31 -3.306a1.001 1.001 0 0 0 -0.715 -1.711z" filter="url(#l)" transform="translate(10.005 9.286) scale(1.02438)"/>
</svg>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -23,6 +23,182 @@ toolbar[brighttext] #pocket-button {
fill: var(--toolbarbutton-icon-fill-inverted);
}
#pocket-button[open="true"][animationsenabled] > .toolbarbutton-icon {
fill: transparent;
}
@keyframes pocket-animation {
from {
transform: translateX(0);
}
to {
transform: translateX(-220px);
}
}
@keyframes pocket-animation-rtl {
from {
transform: scaleX(-1) translateX(0);
}
to {
transform: scaleX(-1) translateX(-220px);
}
}
#pocket-button > .toolbarbutton-animatable-box {
position: absolute;
overflow: hidden;
top: calc(50% - 9px); /* 9px is half the height of the sprite */
/* Since .toolbarbutton-icon uses a different width than the animatable box,
we need to set a padding relative to the difference in widths. */
margin-inline-start: calc((16px + 2 * var(--toolbarbutton-inner-padding) - 20px) / 2);
/* Set the min- and max- width and height of the box equal to that
of each frame of the SVG sprite. Setting the width and height via
the `width` and `height` CSS properties causes an assertion for
`inline-size less than zero: 'aContainingBlockISize >= 0'` (bug 1379332). */
min-width: 20px;
max-width: 20px;
min-height: 18px;
max-height: 18px;
}
#pocket-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
height: var(--toolbarbutton-height); /* Height must be equal to height of toolbarbutton padding-box */
}
#pocket-button[open="true"][animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]) {
position: relative;
}
/* Preload pocket-animation.svg and library-pocket-animation.svg to prevent
a flicker at the start of either animation. The preloading of the library
animation is triggered off of hovering the pocket button since the pocket
button always animates before the library button. */
#pocket-button[animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]):not([open="true"]):hover > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
background-image: url("chrome://pocket-shared/skin/pocket-animation.svg"),
url("chrome://pocket-shared/skin/library-pocket-animation.svg");
background-size: 0, 0;
}
#pocket-button[open="true"][animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
animation-name: pocket-animation;
animation-timing-function: steps(11);
animation-duration: 184ms;
background-image: url("chrome://pocket-shared/skin/pocket-animation.svg");
width: 240px;
}
#pocket-button[open="true"][animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]):-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
animation-name: pocket-animation-rtl;
}
#library-button[animate="pocket"] > .toolbarbutton-icon {
fill: transparent;
}
@keyframes library-pocket-animation {
from {
transform: translateX(0);
fill: inherit;
}
25% {
fill: inherit;
}
50% {
fill: rgb(213,32,20);
}
to {
transform: translateX(-1056px);
fill: rgb(213,32,20);
}
}
@keyframes library-pocket-animation-rtl {
from {
transform: scaleX(-1) translateX(0);
fill: inherit;
}
25% {
fill: inherit;
}
50% {
fill: rgb(213,32,20);
}
to {
transform: scaleX(-1) translateX(-1056px);
fill: rgb(213,32,20);
}
}
/* The animations for the pocket-button and library-button are disabled
outside of the nav-bar due to bug 1382894. */
:-moz-any(#pocket-button, #library-button) > .toolbarbutton-animatable-box {
display: none;
}
#nav-bar :-moz-any(#pocket-button, #library-button) > .toolbarbutton-animatable-box {
display: -moz-box;
}
/* We need to use an animation here instead of a transition
to guarantee that the animation succeeds. With transitions
if the starting value is already equal to the end value
then no transition will occur and thus no transitionend event. */
@keyframes library-pocket-fade {
from {
fill: rgb(213,32,20);
}
to {
fill: inherit;
}
}
#library-button[animate="pocket"] {
position: relative;
}
#library-button[animate="pocket"] > .toolbarbutton-animatable-box {
position: absolute;
overflow: hidden;
top: calc(50% - 27px); /* 27px is half the height of the sprite */
/* Since .toolbarbutton-icon uses a different width than the animatable box,
we need to set a padding relative to the difference in widths. */
margin-inline-start: calc((16px + 2 * var(--toolbarbutton-inner-padding) - 22px) / 2);
/* Set the min- and max- width and height of the box equal to that
of each frame of the SVG sprite. Setting the width and height via
the `width` and `height` CSS properties causes an assertion for
`inline-size less than zero: 'aContainingBlockISize >= 0'` (bug 1379332). */
min-width: 22px;
max-width: 22px;
/* Height of each frame within the SVG sprite. The sprite must have equal amount
of space above and below the icon to allow it to vertically center with the
sprite's icon on top of the toolbar icon when using position:absolute;. */
min-height: 54px;
max-height: 54px;
}
#library-button[animate="pocket"] > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
height: var(--toolbarbutton-height); /* Height must be equal to height of toolbarbutton padding-box */
}
#library-button[animate="pocket"] > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
background-image: url("chrome://pocket-shared/skin/library-pocket-animation.svg");
width: 1078px;
animation-name: library-pocket-animation;
animation-duration: 768ms;
animation-timing-function: steps(48);
}
#library-button[animate="pocket"]:-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
animation-name: library-pocket-animation-rtl;
transform: scaleX(-1);
}
#library-button[animate="pocket"][fade] > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
animation-name: library-pocket-fade;
animation-duration: 2s;
animation-timing-function: ease-out;
}
#pocket-button[cui-areatype="toolbar"][open] {
fill: rgb(213,32,20);
}

View File

@ -12,7 +12,7 @@
</Description>
</em:targetApplication>
<em:type>2</em:type>
<em:version>10.7.0</em:version>
<em:version>10.8.0</em:version>
<em:bootstrap>true</em:bootstrap>
<em:homepageURL>https://pageshot.net/</em:homepageURL>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

View File

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Firefox Screenshots",
"version": "10.7.0",
"version": "10.8.0",
"description": "__MSG_addonDescription__",
"author": "__MSG_addonAuthorsList__",
"homepage_url": "https://github.com/mozilla-services/screenshots",

View File

@ -96,7 +96,7 @@ this.slides = (function() {
};
let linkUrls = {
[termsSentinel]: "https://www.mozilla.org/about/legal/terms/services/",
[privacySentinel]: "https://www.mozilla.org/privacy/firefox-cloud/"
[privacySentinel]: "https://www.mozilla.org/privacy/firefox/"
};
let text = browser.i18n.getMessage(
"termsAndPrivacyNoticeCloudServices",

View File

@ -164,7 +164,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
initSizeWatch() {
this.stopSizeWatch();
this.sizeTracking.timer = setInterval(watchFunction(this.updateElementSize.bind(this)), 2000);
window.addEventListener("resize", watchFunction(assertIsTrusted(this.onResize)), true);
window.addEventListener("resize", this.onResize, true);
},
stopSizeWatch() {
@ -177,7 +177,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
this.sizeTracking.windowDelayer = null;
}
this.sizeTracking.lastHeight = this.sizeTracking.lastWidth = null;
window.removeEventListener("resize", watchFunction(assertIsTrusted(this.onResize)), true);
window.removeEventListener("resize", this.onResize, true);
},
getElementFromPoint(x, y) {
@ -198,7 +198,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
}
};
iframeSelection.onResize = watchFunction(assertIsTrusted(onResize.bind(iframeSelection)));
iframeSelection.onResize = watchFunction(assertIsTrusted(onResize.bind(iframeSelection)), true);
let iframePreSelection = exports.iframePreSelection = {
element: null,
@ -322,7 +322,7 @@ this.ui = (function() { // eslint-disable-line no-unused-vars
}
};
iframePreSelection.onResize = watchFunction(onResize.bind(iframePreSelection));
iframePreSelection.onResize = watchFunction(onResize.bind(iframePreSelection), true);
let iframe = exports.iframe = {
currentIframe: iframePreSelection,

View File

@ -395,7 +395,9 @@
@RESPATH@/components/nsSearchService.js
@RESPATH@/components/nsSearchSuggestions.js
@RESPATH@/components/nsSidebar.js
#if defined(NIGHTLY_BUILD) && defined(MOZ_BUILD_APP_IS_BROWSER)
@RESPATH@/components/payments.manifest
#endif
@RESPATH@/components/passwordmgr.manifest
@RESPATH@/components/nsLoginInfo.js
@RESPATH@/components/nsLoginManager.js

View File

@ -2,4 +2,4 @@
# 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/.
uiDensity.menu-button-touch.acceltext=Tablet Mode Enabled
uiDensity.menuitem-touch.acceltext=Tablet Mode Enabled

View File

@ -457,14 +457,14 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
padding: 5px 10px;
}
.customization-uidensity-menu-button > .menu-iconic-left > .menu-iconic-icon,
.customization-uidensity-menuitem > .menu-iconic-left > .menu-iconic-icon,
.customization-lwtheme-menu-theme > .toolbarbutton-icon {
width: 32px;
height: 32px;
margin: 5px;
}
.customization-uidensity-menu-button,
.customization-uidensity-menuitem,
.customization-lwtheme-menu-theme {
-moz-appearance: none;
border: 1px solid transparent;
@ -475,7 +475,7 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
padding-inline-start: 0;
}
.customization-uidensity-menu-button {
.customization-uidensity-menuitem {
color: inherit;
}
@ -484,35 +484,35 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
}
%ifdef MOZ_PHOTON_THEME
#customization-uidensity-menu-button-normal {
#customization-uidensity-menuitem-normal {
list-style-image: url("chrome://browser/skin/customizableui/density-normal.svg");
}
#customization-uidensity-menu-button-compact {
#customization-uidensity-menuitem-compact {
list-style-image: url("chrome://browser/skin/customizableui/density-compact.svg");
}
#customization-uidensity-menu-button-touch {
#customization-uidensity-menuitem-touch {
list-style-image: url("chrome://browser/skin/customizableui/density-touch.svg");
}
%endif
.customization-uidensity-menu-button[active="true"],
.customization-uidensity-menu-button:hover,
.customization-uidensity-menuitem[active="true"],
.customization-uidensity-menuitem:hover,
.customization-lwtheme-menu-theme[active="true"],
.customization-lwtheme-menu-theme:hover {
background-color: var(--arrowpanel-dimmed);
border-color: var(--panel-separator-color);
}
.customization-uidensity-menu-button[active="true"],
.customization-uidensity-menu-button:hover:active,
.customization-uidensity-menuitem[active="true"],
.customization-uidensity-menuitem:hover:active,
.customization-lwtheme-menu-theme[active="true"],
.customization-lwtheme-menu-theme:hover:active {
background-color: var(--arrowpanel-dimmed-further);
}
.customization-uidensity-menu-button > .menu-iconic-text,
.customization-uidensity-menuitem > .menu-iconic-text,
.customization-lwtheme-menu-theme > .toolbarbutton-text {
text-align: start;
}

View File

@ -17,6 +17,7 @@ toolbar[brighttext] .toolbarbutton-1 {
%ifdef MOZ_PHOTON_THEME
#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#library-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
%endif
#nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
@ -37,6 +38,12 @@ toolbar[brighttext] .toolbarbutton-1 {
%ifdef MOZ_PHOTON_THEME
%ifdef MOZ_PHOTON_ANIMATIONS
.toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
animation-fill-mode: forwards;
animation-iteration-count: 1;
list-style-image: none;
}
#stop-reload-button[animate] > #reload-button > .toolbarbutton-icon,
#stop-reload-button[animate] > #reload-button[displaystop] + #stop-button > .toolbarbutton-icon {
fill: transparent;
@ -104,9 +111,6 @@ toolbar[brighttext] .toolbarbutton-1 {
#reload-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image,
#stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
height: var(--toolbarbutton-height); /* Height must be equal to height of toolbarbutton padding-box */
animation-fill-mode: forwards;
animation-iteration-count: 1;
list-style-image: none;
}
#stop-reload-button[animate] > #reload-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
@ -380,9 +384,6 @@ toolbar:not([brighttext]) #bookmarks-menu-button@attributeSelectorForToolbar@[st
#nav-bar-overflow-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
height: 24px; /* Height of each frame within the SVG sprite */
animation-fill-mode: forwards;
animation-iteration-count: 1;
list-style-image: none;
}
#nav-bar-overflow-button[animate] > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {

View File

@ -16,7 +16,6 @@ struct JSContext;
class JSObject;
class nsIDocument;
class nsStyleContext;
class ServoComputedValues;
struct RawServoDeclarationBlock;
namespace mozilla {
@ -82,7 +81,7 @@ public:
*
* @param aKeyframes The input keyframes.
* @param aElement The context element.
* @param aStyleType The |ServoComputedValues| or |nsStyleContext| to use
* @param aStyleType The |ServoStyleContext| or |GeckoStyleContext| to use
* when computing values.
* @param aEffectComposite The composite operation specified on the effect.
* For any keyframes in |aKeyframes| that do not specify a composite

View File

@ -4467,6 +4467,26 @@ nsDOMWindowUtils::GetDirectionFromText(const nsAString& aString, int32_t* aRetva
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::EnsureDirtyRootFrame()
{
nsIDocument* doc = GetDocument();
nsIPresShell* presShell = doc ? doc->GetShell() : nullptr;
if (!presShell) {
return NS_ERROR_FAILURE;
}
nsIFrame* frame = presShell->GetRootFrame();
if (!frame) {
return NS_ERROR_FAILURE;
}
presShell->FrameNeedsReflow(frame, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetIsStyledByServo(bool* aStyledByServo)
{

View File

@ -8810,11 +8810,8 @@ nsDocument::BlockOnload()
}
// If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
// -- it's not ours. Also, if we're already in the COMPLETE state, that means
// we already had our load event, conceptually, so there's no more need to
// mess about with the load blocker.
if (mOnloadBlockCount == 0 && mScriptGlobalObject &&
GetReadyStateEnum() != READYSTATE_COMPLETE) {
// -- it's not ours.
if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
if (!nsContentUtils::IsSafeToRunScript()) {
// Because AddRequest may lead to OnStateChange calls in chrome,
// block onload only when there are no script blockers.

View File

@ -3053,7 +3053,7 @@ CanvasRenderingContext2D::ParseFilter(const nsAString& aString,
return false;
}
const nsStyleEffects* effects = computedValues->ComputedValues()->GetStyleEffects();
const nsStyleEffects* effects = computedValues->ComputedData()->GetStyleEffects();
// XXX: This mFilters is a one shot object, we probably could avoid copying.
aFilterChain = effects->mFilters;
return true;
@ -3973,7 +3973,7 @@ CanvasRenderingContext2D::SetFontInternal(const nsAString& aFont,
if (!computedValues) {
return false;
}
fontStyle = computedValues->ComputedValues()->GetStyleFont();
fontStyle = computedValues->ComputedData()->GetStyleFont();
} else {
sc = GetFontStyleContext(mCanvasElement,
aFont,

View File

@ -5986,8 +5986,7 @@ bool HTMLMediaElement::CanActivateAutoplay()
bool hasData =
(mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
(mSrcStream && mSrcStream->Active()) ||
mMediaSource;
(mSrcStream && mSrcStream->Active());
return hasData;
}

View File

@ -2023,6 +2023,14 @@ interface nsIDOMWindowUtils : nsISupports {
*/
long getDirectionFromText(in AString aString);
/**
* Calls FrameNeedsReflow on that root frame so that a layout flush
* will be necessary.
*
* This should only be used for testing.
*/
void ensureDirtyRootFrame();
/**
* Whether the current document is styled by Servo's style engine.
*

View File

@ -84,8 +84,8 @@ ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName,
return GMPGenericErr;
}
auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
create(cdm::ContentDecryptionModule::kVersion,
auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_8*>(
create(cdm::ContentDecryptionModule_8::kVersion,
kEMEKeySystemWidevine.get(),
kEMEKeySystemWidevine.Length(),
&ChromiumCdmHost,
@ -126,7 +126,7 @@ ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
int32_t aHostVersion)
{
return aModuleVersion == CDM_MODULE_VERSION &&
aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
aInterfaceVersion == cdm::ContentDecryptionModule_8::kVersion &&
aHostVersion == cdm::Host_8::kVersion;
}

View File

@ -67,6 +67,8 @@ EXPORTS += [
'GMPVideoi420FrameImpl.h',
'GMPVideoPlaneImpl.h',
'widevine-adapter/content_decryption_module.h',
'widevine-adapter/content_decryption_module_export.h',
'widevine-adapter/content_decryption_module_ext.h',
]
UNIFIED_SOURCES += [

View File

@ -97,8 +97,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName,
auto* decryptor = new WidevineDecryptor();
auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
create(cdm::ContentDecryptionModule::kVersion,
auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_8*>(
create(cdm::ContentDecryptionModule_8::kVersion,
kEMEKeySystemWidevine.get(),
kEMEKeySystemWidevine.Length(),
&GetCdmHost,

View File

@ -29,7 +29,7 @@ ToGMPErr(cdm::Status aStatus)
case cdm::kSuccess: return GMPNoErr;
case cdm::kNeedMoreData: return GMPGenericErr;
case cdm::kNoKey: return GMPNoKeyErr;
case cdm::kSessionError: return GMPGenericErr;
case cdm::kInitializationError: return GMPGenericErr;
case cdm::kDecryptError: return GMPCryptoErr;
case cdm::kDecodeError: return GMPDecodeErr;
case cdm::kDeferredInitialization: return GMPGenericErr;

View File

@ -5,6 +5,8 @@
#ifndef CDM_CONTENT_DECRYPTION_MODULE_H_
#define CDM_CONTENT_DECRYPTION_MODULE_H_
#include "content_decryption_module_export.h"
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
@ -14,25 +16,21 @@ typedef __int64 int64_t;
#include <stdint.h>
#endif
// Define CDM_EXPORT so that functionality implemented by the CDM module
// can be exported to consumers.
#if defined(WIN32)
#if defined(CDM_IMPLEMENTATION)
#define CDM_EXPORT __declspec(dllexport)
// Define CDM_CLASS_API to export class types. We have to add visibility
// attributes to make sure virtual tables in CDM consumer and CDM implementation
// are the same. Generally, it was always a good idea, as there're no guarantees
// about that for the internal symbols, but it has only become a practical issue
// after introduction of LTO devirtualization. See more details on
// https://crbug.com/609564#c35
#if defined(_WIN32)
#if defined(__clang__)
#define CDM_CLASS_API [[clang::lto_visibility_public]]
#else
#define CDM_EXPORT __declspec(dllimport)
#endif // defined(CDM_IMPLEMENTATION)
#else // defined(WIN32)
#if defined(CDM_IMPLEMENTATION)
#define CDM_EXPORT __attribute__((visibility("default")))
#else
#define CDM_EXPORT
#define CDM_CLASS_API
#endif
#endif // defined(WIN32)
#else // defined(_WIN32)
#define CDM_CLASS_API __attribute__((visibility("default")))
#endif // defined(_WIN32)
// The version number must be rolled when the exported functions are updated!
// If the CDM and the adapter use different versions of these functions, the
@ -48,9 +46,9 @@ typedef __int64 int64_t;
#define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version
extern "C" {
CDM_EXPORT void INITIALIZE_CDM_MODULE();
CDM_API void INITIALIZE_CDM_MODULE();
CDM_EXPORT void DeinitializeCdmModule();
CDM_API void DeinitializeCdmModule();
// Returns a pointer to the requested CDM Host interface upon success.
// Returns NULL if the requested CDM Host interface is not supported.
@ -65,28 +63,28 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data);
// |cdm_interface_version|.
// Caller retains ownership of arguments and must call Destroy() on the returned
// object.
CDM_EXPORT void* CreateCdmInstance(
CDM_API void* CreateCdmInstance(
int cdm_interface_version,
const char* key_system, uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func, void* user_data);
CDM_EXPORT const char* GetCdmVersion();
CDM_API const char* GetCdmVersion();
}
namespace cdm {
class AudioFrames;
class DecryptedBlock;
class VideoFrame;
class CDM_CLASS_API AudioFrames;
class CDM_CLASS_API DecryptedBlock;
class CDM_CLASS_API VideoFrame;
class Host_7;
class Host_8;
class CDM_CLASS_API Host_8;
class CDM_CLASS_API Host_9;
enum Status {
kSuccess = 0,
kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample.
kNoKey, // The required decryption key is not available.
kSessionError, // Session management error.
kInitializationError, // Initialization error.
kDecryptError, // Decryption failed.
kDecodeError, // Error decoding audio or video.
kDeferredInitialization // Decoder is not ready for initialization.
@ -97,6 +95,7 @@ enum Status {
// The following starts with the list of DOM4 exceptions from:
// http://www.w3.org/TR/dom/#domexception
// Some DOM4 exceptions are not included as they are not expected to be used.
// Should only be used on Host_8 and before.
enum Error {
kNotSupportedError = 9,
kInvalidStateError = 11,
@ -113,8 +112,20 @@ enum Error {
kOutputError = 101
};
// Time is defined as the number of seconds since the
// Epoch (00:00:00 UTC, January 1, 1970).
// Exceptions used by the CDM to reject promises.
// https://w3c.github.io/encrypted-media/#exceptions
enum Exception {
kExceptionTypeError,
kExceptionNotSupportedError,
kExceptionInvalidStateError,
kExceptionQuotaExceededError
};
// Time is defined as the number of seconds since the Epoch
// (00:00:00 UTC, January 1, 1970), not including any added leap second.
// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time
// Note that Time is defined in millisecond accuracy in the spec but in second
// accuracy here.
typedef double Time;
// An input buffer can be split into several continuous subsamples.
@ -151,13 +162,13 @@ struct SubsampleEntry {
// unencrypted.
struct InputBuffer {
InputBuffer()
: data(NULL),
: data(nullptr),
data_size(0),
key_id(NULL),
key_id(nullptr),
key_id_size(0),
iv(NULL),
iv(nullptr),
iv_size(0),
subsamples(NULL),
subsamples(nullptr),
num_subsamples(0),
timestamp(0) {}
@ -188,7 +199,7 @@ struct AudioDecoderConfig {
channel_count(0),
bits_per_channel(0),
samples_per_second(0),
extra_data(NULL),
extra_data(nullptr),
extra_data_size(0) {}
AudioCodec codec;
@ -214,10 +225,25 @@ enum AudioFormat {
};
// Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php
// Values are chosen to be consistent with Chromium's VideoPixelFormat values.
enum VideoFormat {
kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting.
kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples.
kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples.
// In the following formats, each sample uses 16-bit in storage, while the
// sample value is stored in the least significant N bits where N is
// specified by the number after "P". For example, for YUV420P9, each Y, U,
// and V sample is stored in the least significant 9 bits in a 2-byte block.
kYUV420P9 = 16,
kYUV420P10 = 17,
kYUV422P9 = 18,
kYUV422P10 = 19,
kYUV444P9 = 20,
kYUV444P10 = 21,
kYUV420P12 = 22,
kYUV422P12 = 23,
kYUV444P12 = 24,
};
struct Size {
@ -245,14 +271,19 @@ struct VideoDecoderConfig {
kH264ProfileHigh,
kH264ProfileHigh10,
kH264ProfileHigh422,
kH264ProfileHigh444Predictive
kH264ProfileHigh444Predictive,
// VP9 Profiles are only passed in starting from CDM_9.
kVP9Profile0,
kVP9Profile1,
kVP9Profile2,
kVP9Profile3
};
VideoDecoderConfig()
: codec(kUnknownVideoCodec),
profile(kUnknownVideoCodecProfile),
format(kUnknownVideoFormat),
extra_data(NULL),
extra_data(nullptr),
extra_data_size(0) {}
VideoCodec codec;
@ -294,7 +325,7 @@ struct PlatformChallengeResponse {
// Used when passing arrays of binary data. Does not own the referenced data.
struct BinaryData {
BinaryData() : data(NULL), length(0) {}
BinaryData() : data(nullptr), length(0) {}
const uint8_t* data;
uint32_t length;
};
@ -316,7 +347,10 @@ enum KeyStatus {
// should be 0 when |status| == kUsable.
struct KeyInformation {
KeyInformation()
: key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {}
: key_id(nullptr),
key_id_size(0),
status(kInternalError),
system_code(0) {}
const uint8_t* key_id;
uint32_t key_id_size;
KeyStatus status;
@ -372,6 +406,24 @@ enum MessageType {
kLicenseRelease = 2
};
enum HdcpVersion {
kHdcpVersionNone,
kHdcpVersion1_0,
kHdcpVersion1_1,
kHdcpVersion1_2,
kHdcpVersion1_3,
kHdcpVersion1_4,
kHdcpVersion2_0,
kHdcpVersion2_1,
kHdcpVersion2_2
};
struct Policy {
Policy() : min_hdcp_version(kHdcpVersionNone) {}
HdcpVersion min_hdcp_version;
};
// FileIO interface provides a way for the CDM to store data in a file in
// persistent storage. This interface aims only at providing basic read/write
// capabilities and should not be used as a full fledged file IO API.
@ -381,7 +433,7 @@ enum MessageType {
// Note to implementors of this interface:
// Per-origin storage and the ability for users to clear it are important.
// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
class FileIO {
class CDM_CLASS_API FileIO {
public:
// Opens the file with |file_name| for read and write.
// FileIOClient::OnOpenComplete() will be called after the opening
@ -421,7 +473,7 @@ class FileIO {
// When kError is returned, the FileIO object could be in an error state. All
// following calls (other than Close()) could return kError. The CDM should
// still call Close() to destroy the FileIO object.
class FileIOClient {
class CDM_CLASS_API FileIOClient {
public:
enum Status {
kSuccess = 0,
@ -462,186 +514,7 @@ class FileIOClient {
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
class ContentDecryptionModule_7 {
public:
static const int kVersion = 7;
typedef Host_7 Host;
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
// |promise_id|, which must be passed to the completion Host method
// (e.g. Host::OnResolveNewSessionPromise()).
// Provides a server certificate to be used to encrypt messages to the
// license server. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void SetServerCertificate(uint32_t promise_id,
const uint8_t* server_certificate_data,
uint32_t server_certificate_data_size) = 0;
// Creates a session given |session_type|, |init_data_type|, and |init_data|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise().
virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
SessionType session_type,
const char* init_data_type,
uint32_t init_data_type_size,
const uint8_t* init_data,
uint32_t init_data_size) = 0;
// Loads the session of type |session_type| specified by |session_id|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise(). If the session is not found, call
// Host::OnResolveNewSessionPromise() with session_id = NULL.
virtual void LoadSession(uint32_t promise_id,
SessionType session_type,
const char* session_id,
uint32_t session_id_size) = 0;
// Updates the session with |response|. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void UpdateSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// Requests that the CDM close the session. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
// has been processed. This may be before the session is closed. Once the
// session is closed, Host::OnSessionClosed() must also be called.
virtual void CloseSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Removes any stored session data associated with this session. Will only be
// called for persistent sessions. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
// been processed.
virtual void RemoveSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
virtual void TimerExpired(void* context) = 0;
// Decrypts the |encrypted_buffer|.
//
// Returns kSuccess if decryption succeeded, in which case the callee
// should have filled the |decrypted_buffer| and passed the ownership of
// |data| in |decrypted_buffer| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kDecryptError if any other error happened.
// If the return value is not kSuccess, |decrypted_buffer| should be ignored
// by the caller.
virtual Status Decrypt(const InputBuffer& encrypted_buffer,
DecryptedBlock* decrypted_buffer) = 0;
// Initializes the CDM audio decoder with |audio_decoder_config|. This
// function must be called before DecryptAndDecodeSamples() is called.
//
// Returns kSuccess if the |audio_decoder_config| is supported and the CDM
// audio decoder is successfully initialized.
// Returns kSessionError if |audio_decoder_config| is not supported. The CDM
// may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
virtual Status InitializeAudioDecoder(
const AudioDecoderConfig& audio_decoder_config) = 0;
// Initializes the CDM video decoder with |video_decoder_config|. This
// function must be called before DecryptAndDecodeFrame() is called.
//
// Returns kSuccess if the |video_decoder_config| is supported and the CDM
// video decoder is successfully initialized.
// Returns kSessionError if |video_decoder_config| is not supported. The CDM
// may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
virtual Status InitializeVideoDecoder(
const VideoDecoderConfig& video_decoder_config) = 0;
// De-initializes the CDM decoder and sets it to an uninitialized state. The
// caller can initialize the decoder again after this call to re-initialize
// it. This can be used to reconfigure the decoder if the configuration
// changes.
virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
// Resets the CDM decoder to an initialized clean state. All internal buffers
// MUST be flushed.
virtual void ResetDecoder(StreamType decoder_type) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
// |video_frame|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
// |video_frame| (|format| == kEmptyVideoFrame) is produced.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled the |video_frame| and passed the ownership of
// |frame_buffer| in |video_frame| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// a decoded frame (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |video_frame| should be ignored by
// the caller.
virtual Status DecryptAndDecodeFrame(const InputBuffer& encrypted_buffer,
VideoFrame* video_frame) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
// |audio_frames|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
// |audio_frames| is produced.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled |audio_frames| and passed the ownership of
// |data| in |audio_frames| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// audio samples (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |audio_frames| should be ignored by
// the caller.
virtual Status DecryptAndDecodeSamples(const InputBuffer& encrypted_buffer,
AudioFrames* audio_frames) = 0;
// Called by the host after a platform challenge was initiated via
// Host::SendPlatformChallenge().
virtual void OnPlatformChallengeResponse(
const PlatformChallengeResponse& response) = 0;
// Called by the host after a call to Host::QueryOutputProtectionStatus(). The
// |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
// is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
// then |link_mask| and |output_protection_mask| are undefined and should
// be ignored.
virtual void OnQueryOutputProtectionStatus(
QueryResult result,
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
// Destroys the object in the same context as it was created.
virtual void Destroy() = 0;
protected:
ContentDecryptionModule_7() {}
virtual ~ContentDecryptionModule_7() {}
};
// ContentDecryptionModule interface that all CDMs need to implement.
// The interface is versioned for backward compatibility.
// Note: ContentDecryptionModule implementations must use the allocator
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
class ContentDecryptionModule_8 {
class CDM_CLASS_API ContentDecryptionModule_8 {
public:
static const int kVersion = 8;
typedef Host_8 Host;
@ -823,10 +696,210 @@ class ContentDecryptionModule_8 {
virtual ~ContentDecryptionModule_8() {}
};
typedef ContentDecryptionModule_8 ContentDecryptionModule;
// ContentDecryptionModule interface that all CDMs need to implement.
// The interface is versioned for backward compatibility.
// Note: ContentDecryptionModule implementations must use the allocator
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
class CDM_CLASS_API ContentDecryptionModule_9 {
public:
static const int kVersion = 9;
typedef Host_9 Host;
// Initializes the CDM instance, providing information about permitted
// functionalities.
// If |allow_distinctive_identifier| is false, messages from the CDM,
// such as message events, must not contain a Distinctive Identifier,
// even in an encrypted form.
// If |allow_persistent_state| is false, the CDM must not attempt to
// persist state. Calls to CreateFileIO() will fail.
virtual void Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state) = 0;
// Gets the key status if the CDM has a hypothetical key with the |policy|.
// The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
// with the result key status or Host::OnRejectPromise() if an unexpected
// error happened or this method is not supported.
virtual void GetStatusForPolicy(uint32_t promise_id,
const Policy& policy) = 0;
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
// |promise_id|, which must be passed to the completion Host method
// (e.g. Host::OnResolveNewSessionPromise()).
// Provides a server certificate to be used to encrypt messages to the
// license server. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void SetServerCertificate(uint32_t promise_id,
const uint8_t* server_certificate_data,
uint32_t server_certificate_data_size) = 0;
// Creates a session given |session_type|, |init_data_type|, and |init_data|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise().
virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
SessionType session_type,
InitDataType init_data_type,
const uint8_t* init_data,
uint32_t init_data_size) = 0;
// Loads the session of type |session_type| specified by |session_id|.
// The CDM must respond by calling either Host::OnResolveNewSessionPromise()
// or Host::OnRejectPromise(). If the session is not found, call
// Host::OnResolveNewSessionPromise() with session_id = NULL.
virtual void LoadSession(uint32_t promise_id,
SessionType session_type,
const char* session_id,
uint32_t session_id_size) = 0;
// Updates the session with |response|. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise().
virtual void UpdateSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size,
const uint8_t* response,
uint32_t response_size) = 0;
// Requests that the CDM close the session. The CDM must respond by calling
// either Host::OnResolvePromise() or Host::OnRejectPromise() when the request
// has been processed. This may be before the session is closed. Once the
// session is closed, Host::OnSessionClosed() must also be called.
virtual void CloseSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Removes any stored session data associated with this session. Will only be
// called for persistent sessions. The CDM must respond by calling either
// Host::OnResolvePromise() or Host::OnRejectPromise() when the request has
// been processed.
virtual void RemoveSession(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Performs scheduled operation with |context| when the timer fires.
virtual void TimerExpired(void* context) = 0;
// Decrypts the |encrypted_buffer|.
//
// Returns kSuccess if decryption succeeded, in which case the callee
// should have filled the |decrypted_buffer| and passed the ownership of
// |data| in |decrypted_buffer| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kDecryptError if any other error happened.
// If the return value is not kSuccess, |decrypted_buffer| should be ignored
// by the caller.
virtual Status Decrypt(const InputBuffer& encrypted_buffer,
DecryptedBlock* decrypted_buffer) = 0;
// Initializes the CDM audio decoder with |audio_decoder_config|. This
// function must be called before DecryptAndDecodeSamples() is called.
//
// Returns kSuccess if the |audio_decoder_config| is supported and the CDM
// audio decoder is successfully initialized.
// Returns kSessionError if |audio_decoder_config| is not supported. The CDM
// may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
virtual Status InitializeAudioDecoder(
const AudioDecoderConfig& audio_decoder_config) = 0;
// Initializes the CDM video decoder with |video_decoder_config|. This
// function must be called before DecryptAndDecodeFrame() is called.
//
// Returns kSuccess if the |video_decoder_config| is supported and the CDM
// video decoder is successfully initialized.
// Returns kSessionError if |video_decoder_config| is not supported. The CDM
// may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
virtual Status InitializeVideoDecoder(
const VideoDecoderConfig& video_decoder_config) = 0;
// De-initializes the CDM decoder and sets it to an uninitialized state. The
// caller can initialize the decoder again after this call to re-initialize
// it. This can be used to reconfigure the decoder if the configuration
// changes.
virtual void DeinitializeDecoder(StreamType decoder_type) = 0;
// Resets the CDM decoder to an initialized clean state. All internal buffers
// MUST be flushed.
virtual void ResetDecoder(StreamType decoder_type) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a
// |video_frame|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
// |video_frame| (|format| == kEmptyVideoFrame) is produced.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled the |video_frame| and passed the ownership of
// |frame_buffer| in |video_frame| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// a decoded frame (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |video_frame| should be ignored by
// the caller.
virtual Status DecryptAndDecodeFrame(const InputBuffer& encrypted_buffer,
VideoFrame* video_frame) = 0;
// Decrypts the |encrypted_buffer| and decodes the decrypted buffer into
// |audio_frames|. Upon end-of-stream, the caller should call this function
// repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty
// |audio_frames| is produced.
//
// Returns kSuccess if decryption and decoding both succeeded, in which case
// the callee will have filled |audio_frames| and passed the ownership of
// |data| in |audio_frames| to the caller.
// Returns kNoKey if the CDM did not have the necessary decryption key
// to decrypt.
// Returns kNeedMoreData if more data was needed by the decoder to generate
// audio samples (e.g. during initialization and end-of-stream).
// Returns kDecryptError if any decryption error happened.
// Returns kDecodeError if any decoding error happened.
// If the return value is not kSuccess, |audio_frames| should be ignored by
// the caller.
virtual Status DecryptAndDecodeSamples(const InputBuffer& encrypted_buffer,
AudioFrames* audio_frames) = 0;
// Called by the host after a platform challenge was initiated via
// Host::SendPlatformChallenge().
virtual void OnPlatformChallengeResponse(
const PlatformChallengeResponse& response) = 0;
// Called by the host after a call to Host::QueryOutputProtectionStatus(). The
// |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask|
// is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed,
// then |link_mask| and |output_protection_mask| are undefined and should
// be ignored.
virtual void OnQueryOutputProtectionStatus(
QueryResult result,
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
// Called by the host after a call to Host::RequestStorageId(). If the storage
// ID is not available, null/zero will be provided.
virtual void OnStorageId(const uint8_t* storage_id,
uint32_t storage_id_size) = 0;
// Destroys the object in the same context as it was created.
virtual void Destroy() = 0;
protected:
ContentDecryptionModule_9() {}
virtual ~ContentDecryptionModule_9() {}
};
typedef ContentDecryptionModule_9 ContentDecryptionModule;
// Represents a buffer created by Allocator implementations.
class Buffer {
class CDM_CLASS_API Buffer {
public:
// Destroys the buffer in the same context as it was created.
virtual void Destroy() = 0;
@ -845,144 +918,7 @@ class Buffer {
void operator=(const Buffer&);
};
class Host_7 {
public:
static const int kVersion = 7;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
// guaranteed to be zero initialized. The capacity of the allocated Buffer
// is guaranteed to be not less than |capacity|.
virtual Buffer* Allocate(uint32_t capacity) = 0;
// Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
// Returns the current wall time in seconds.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM when a session is created or loaded and the value for the
// MediaKeySession's sessionId attribute is available (|session_id|).
// This must be called before OnSessionMessage() or
// OnSessionKeysChange() is called for the same session. |session_id_size|
// should not include null termination.
// When called in response to LoadSession(), the |session_id| must be the
// same as the |session_id| passed in LoadSession(), or NULL if the
// session could not be loaded.
virtual void OnResolveNewSessionPromise(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Called by the CDM when a session is updated or released.
virtual void OnResolvePromise(uint32_t promise_id) = 0;
// Called by the CDM when an error occurs as a result of one of the
// ContentDecryptionModule calls that accept a |promise_id|.
// |error| must be specified, |error_message| and |system_code|
// are optional. |error_message_size| should not include null termination.
virtual void OnRejectPromise(uint32_t promise_id,
Error error,
uint32_t system_code,
const char* error_message,
uint32_t error_message_size) = 0;
// Called by the CDM when it has a message for session |session_id|.
// Size parameters should not include null termination.
// |legacy_destination_url| is only for supporting the prefixed EME API and
// is ignored by unprefixed EME. It should only be non-null if |message_type|
// is kLicenseRenewal.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type,
const char* message,
uint32_t message_size,
const char* legacy_destination_url,
uint32_t legacy_destination_url_length) = 0;
// Called by the CDM when there has been a change in keys or their status for
// session |session_id|. |has_additional_usable_key| should be set if a
// key is newly usable (e.g. new key available, previously expired key has
// been renewed, etc.) and the browser should attempt to resume playback.
// |key_ids| is the list of key ids for this session along with their
// current status. |key_ids_count| is the number of entries in |key_ids|.
// Size parameter for |session_id| should not include null termination.
virtual void OnSessionKeysChange(const char* session_id,
uint32_t session_id_size,
bool has_additional_usable_key,
const KeyInformation* keys_info,
uint32_t keys_info_count) = 0;
// Called by the CDM when there has been a change in the expiration time for
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
// can be 0 to represent "undefined". Size parameter should not include
// null termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
// Called by the CDM when session |session_id| is closed. Size
// parameter should not include null termination.
virtual void OnSessionClosed(const char* session_id,
uint32_t session_id_size) = 0;
// Called by the CDM when an error occurs in session |session_id|
// unrelated to one of the ContentDecryptionModule calls that accept a
// |promise_id|. |error| must be specified, |error_message| and
// |system_code| are optional. Length parameters should not include null
// termination.
// Note:
// - This method is only for supporting prefixed EME API.
// - This method will be ignored by unprefixed EME. All errors reported
// in this method should probably also be reported by one of other methods.
virtual void OnLegacySessionError(
const char* session_id, uint32_t session_id_length,
Error error,
uint32_t system_code,
const char* error_message, uint32_t error_message_length) = 0;
// The following are optional methods that may not be implemented on all
// platforms.
// Sends a platform challenge for the given |service_id|. |challenge| is at
// most 256 bits of data to be signed. Once the challenge has been completed,
// the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
// with the signed challenge response and platform certificate. Size
// parameters should not include null termination.
virtual void SendPlatformChallenge(const char* service_id,
uint32_t service_id_size,
const char* challenge,
uint32_t challenge_size) = 0;
// Attempts to enable output protection (e.g. HDCP) on the display link. The
// |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
// status callback is issued, the CDM must call QueryOutputProtectionStatus()
// periodically to ensure the desired protections are applied.
virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
// Requests the current output protection status. Once the host has the status
// it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
virtual void QueryOutputProtectionStatus() = 0;
// Must be called by the CDM if it returned kDeferredInitialization during
// InitializeAudioDecoder() or InitializeVideoDecoder().
virtual void OnDeferredInitializationDone(StreamType stream_type,
Status decoder_status) = 0;
// Creates a FileIO object from the host to do file IO operation. Returns NULL
// if a FileIO object cannot be obtained. Once a valid FileIO object is
// returned, |client| must be valid until FileIO::Close() is called. The
// CDM can call this method multiple times to operate on different files.
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
protected:
Host_7() {}
virtual ~Host_7() {}
};
class Host_8 {
class CDM_CLASS_API Host_8 {
public:
static const int kVersion = 8;
@ -996,7 +932,7 @@ class Host_8 {
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
// Returns the current wall time in seconds.
// Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM when a session is created or loaded and the value for the
@ -1054,8 +990,10 @@ class Host_8 {
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
// can be 0 to represent "undefined". Size parameter should not include
// null termination.
// represents the time after which the key(s) in the session will no longer
// be usable for decryption. It can be 0 if no such time exists or if the
// license explicitly never expires. Size parameter should not include null
// termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
@ -1119,8 +1057,138 @@ class Host_8 {
virtual ~Host_8() {}
};
class CDM_CLASS_API Host_9 {
public:
static const int kVersion = 9;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
// guaranteed to be zero initialized. The capacity of the allocated Buffer
// is guaranteed to be not less than |capacity|.
virtual Buffer* Allocate(uint32_t capacity) = 0;
// Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms|
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
// Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM when a key status is available in response to
// GetStatusForPolicy().
virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
KeyStatus key_status) = 0;
// Called by the CDM when a session is created or loaded and the value for the
// MediaKeySession's sessionId attribute is available (|session_id|).
// This must be called before OnSessionMessage() or
// OnSessionKeysChange() is called for the same session. |session_id_size|
// should not include null termination.
// When called in response to LoadSession(), the |session_id| must be the
// same as the |session_id| passed in LoadSession(), or NULL if the
// session could not be loaded.
virtual void OnResolveNewSessionPromise(uint32_t promise_id,
const char* session_id,
uint32_t session_id_size) = 0;
// Called by the CDM when a session is updated or released.
virtual void OnResolvePromise(uint32_t promise_id) = 0;
// Called by the CDM when an error occurs as a result of one of the
// ContentDecryptionModule calls that accept a |promise_id|.
// |exception| must be specified. |error_message| and |system_code|
// are optional. |error_message_size| should not include null termination.
virtual void OnRejectPromise(uint32_t promise_id,
Exception exception,
uint32_t system_code,
const char* error_message,
uint32_t error_message_size) = 0;
// Called by the CDM when it has a message for session |session_id|.
// Size parameters should not include null termination.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type,
const char* message,
uint32_t message_size) = 0;
// Called by the CDM when there has been a change in keys or their status for
// session |session_id|. |has_additional_usable_key| should be set if a
// key is newly usable (e.g. new key available, previously expired key has
// been renewed, etc.) and the browser should attempt to resume playback.
// |key_ids| is the list of key ids for this session along with their
// current status. |key_ids_count| is the number of entries in |key_ids|.
// Size parameter for |session_id| should not include null termination.
virtual void OnSessionKeysChange(const char* session_id,
uint32_t session_id_size,
bool has_additional_usable_key,
const KeyInformation* keys_info,
uint32_t keys_info_count) = 0;
// Called by the CDM when there has been a change in the expiration time for
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
// represents the time after which the key(s) in the session will no longer
// be usable for decryption. It can be 0 if no such time exists or if the
// license explicitly never expires. Size parameter should not include null
// termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
// Called by the CDM when session |session_id| is closed. Size
// parameter should not include null termination.
virtual void OnSessionClosed(const char* session_id,
uint32_t session_id_size) = 0;
// The following are optional methods that may not be implemented on all
// platforms.
// Sends a platform challenge for the given |service_id|. |challenge| is at
// most 256 bits of data to be signed. Once the challenge has been completed,
// the host will call ContentDecryptionModule::OnPlatformChallengeResponse()
// with the signed challenge response and platform certificate. Size
// parameters should not include null termination.
virtual void SendPlatformChallenge(const char* service_id,
uint32_t service_id_size,
const char* challenge,
uint32_t challenge_size) = 0;
// Attempts to enable output protection (e.g. HDCP) on the display link. The
// |desired_protection_mask| is a bit mask of OutputProtectionMethods. No
// status callback is issued, the CDM must call QueryOutputProtectionStatus()
// periodically to ensure the desired protections are applied.
virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0;
// Requests the current output protection status. Once the host has the status
// it will call ContentDecryptionModule::OnQueryOutputProtectionStatus().
virtual void QueryOutputProtectionStatus() = 0;
// Must be called by the CDM if it returned kDeferredInitialization during
// InitializeAudioDecoder() or InitializeVideoDecoder().
virtual void OnDeferredInitializationDone(StreamType stream_type,
Status decoder_status) = 0;
// Creates a FileIO object from the host to do file IO operation. Returns NULL
// if a FileIO object cannot be obtained. Once a valid FileIO object is
// returned, |client| must be valid until FileIO::Close() is called. The
// CDM can call this method multiple times to operate on different files.
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
// Requests the storage ID. The ID will be returned by the host via
// ContentDecryptionModule::OnStorageId(). A storage ID is a stable, device
// specific ID used by the CDM to securely store persistent data. The CDM must
// not expose the ID outside the client device, even in encrypted form.
virtual void RequestStorageId() = 0;
protected:
Host_9() {}
virtual ~Host_9() {}
};
// Represents a decrypted block that has not been decoded.
class DecryptedBlock {
class CDM_CLASS_API DecryptedBlock {
public:
virtual void SetDecryptedBuffer(Buffer* buffer) = 0;
virtual Buffer* DecryptedBuffer() = 0;
@ -1135,7 +1203,7 @@ class DecryptedBlock {
virtual ~DecryptedBlock() {}
};
class VideoFrame {
class CDM_CLASS_API VideoFrame {
public:
enum VideoPlane {
kYPlane = 0,
@ -1178,7 +1246,7 @@ class VideoFrame {
//
// |<----------------- AudioFrames ------------------>|
// | audio buffer 0 | audio buffer 1 | audio buffer 2 |
class AudioFrames {
class CDM_CLASS_API AudioFrames {
public:
virtual void SetFrameBuffer(Buffer* buffer) = 0;
virtual Buffer* FrameBuffer() = 0;

View File

@ -0,0 +1,22 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
// Define CDM_API so that functionality implemented by the CDM module
// can be exported to consumers.
#if defined(_WIN32)
#if defined(CDM_IMPLEMENTATION)
#define CDM_API __declspec(dllexport)
#else
#define CDM_API __declspec(dllimport)
#endif // defined(CDM_IMPLEMENTATION)
#else // defined(_WIN32)
#define CDM_API __attribute__((visibility("default")))
#endif // defined(_WIN32)
#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_

View File

@ -0,0 +1,64 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
#if defined(_WIN32)
#include <windows.h>
#endif
#include "content_decryption_module_export.h"
#if defined(_MSC_VER)
typedef unsigned int uint32_t;
#else
#include <stdint.h>
#endif
namespace cdm {
#if defined(_WIN32)
typedef wchar_t FilePathCharType;
typedef HANDLE PlatformFile;
const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
#else
typedef char FilePathCharType;
typedef int PlatformFile;
const PlatformFile kInvalidPlatformFile = -1;
#endif // defined(_WIN32)
struct HostFile {
HostFile(const FilePathCharType* file_path,
PlatformFile file,
PlatformFile sig_file)
: file_path(file_path), file(file), sig_file(sig_file) {}
// File that is part of the host of the CDM.
const FilePathCharType* file_path = nullptr;
PlatformFile file = kInvalidPlatformFile;
// Signature file for |file|.
PlatformFile sig_file = kInvalidPlatformFile;
};
} // namespace cdm
extern "C" {
// Functions in this file are dynamically retrieved by their versioned function
// names. Increment the version number for any backward incompatible API
// changes.
// Verifies CDM host. All files in |host_files| are opened in read-only mode.
//
// Returns false and closes all files if there is an immediate failure.
// Otherwise returns true as soon as possible and processes the files
// asynchronously. All files MUST be closed by the CDM after this one-time
// processing is finished.
CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files,
uint32_t num_files);
}
#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_

View File

@ -306,12 +306,12 @@ MediaSourceDecoder::CanPlayThrough()
} else if (duration <= currentPosition) {
return true;
}
// If we have data up to the mediasource's duration or 30s ahead, we can
// If we have data up to the mediasource's duration or 10s ahead, we can
// assume that we can play without interruption.
TimeIntervals buffered = GetBuffered();
buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
TimeUnit timeAhead =
std::min(duration, currentPosition + TimeUnit::FromSeconds(30));
std::min(duration, currentPosition + TimeUnit::FromSeconds(10));
TimeInterval interval(currentPosition, timeAhead);
return buffered.ContainsStrict(ClampIntervalToEnd(interval));
}

View File

@ -105,6 +105,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not
skip-if = android_version == '22' # bug 1359010
[test_PlayEvents.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_PlayEventsAutoPlaying.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_ResumeAfterClearing_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_SeekableAfterEndOfStream.html]

View File

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html>
<head>
<title>MSE: basic functionality</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
// This test checks that readyState is properly set and the appropriate events are being fired accordingly:
// 1. Ensure that play/playing aren't fired before any media data been added.
// 2. Load 1.6s of data and ensure that canplay, play and playing events are fired.
runWithMSE(function(ms, el) {
el.controls = true;
el.autoplay = true;
var eventCounts = { play: 0, playing: 0};
function ForbiddenEvents(e) {
var v = e.target;
ok(v.readyState >= v.HAVE_FUTURE_DATA, "Must not have received event too early");
is(eventCounts[e.type], 0, "event should have only be fired once");
eventCounts[e.type]++;
}
once(ms, 'sourceopen').then(function() {
// Log events for debugging.
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
"waiting", "pause", "durationchange", "seeking", "seeked"];
function logEvent(e) {
info("got " + e.type + " event");
}
events.forEach(function(e) {
el.addEventListener(e, logEvent);
});
el.addEventListener("play", ForbiddenEvents);
el.addEventListener("playing", ForbiddenEvents);
ok(true, "Receive a sourceopen event");
var videosb = ms.addSourceBuffer("video/mp4");
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
var promises = [];
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', ['init'], '.mp4'));
promises.push(once(el, 'loadedmetadata'));
Promise.all(promises)
.then(function() {
ok(true, "got loadedmetadata event");
var promises = [];
promises.push(once(el, 'loadeddata'));
promises.push(once(el, 'canplay'));
promises.push(once(el, 'play'));
promises.push(once(el, 'playing'));
promises.push(once(el, 'ended'));
// We're only adding 1.6s worth of data, not enough for readyState to change to HAVE_ENOUGH_DATA
// So we end the media source so that all the playable data is available.
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(1, 3), '.m4s')
.then(() => ms.endOfStream()));
return Promise.all(promises);
})
.then(function() {
ok(true, "got all required event");
SimpleTest.finish();
})
});
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,105 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "cbor-cpp/src/cbor.h"
#include "mozilla/dom/WebAuthnCBORUtil.h"
#include "mozilla/dom/WebAuthnUtil.h"
namespace mozilla {
namespace dom {
nsresult
CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aPubKeyObj)
{
mozilla::dom::CryptoBuffer xBuf, yBuf;
nsresult rv = U2FDecomposeECKey(aPubKeyBuf, xBuf, yBuf);
if (NS_FAILED(rv)) {
return rv;
}
/*
Public Key Object, encoded in CBOR (description is CDDL)
pubKey = $pubKeyFmt
pubKeyFmt /= eccPubKey
eccPubKey = { alg: eccAlgName, x: biguint, y: biguint }
eccAlgName = "ES256" / "ES384" / "ES512"
*/
cbor::output_dynamic cborPubKeyOut;
cbor::encoder encoder(cborPubKeyOut);
encoder.write_map(3);
{
encoder.write_string("alg");
encoder.write_string(JWK_ALG_ECDSA_P_256); // Always ES256 for U2F
encoder.write_string("x");
encoder.write_bytes(xBuf.Elements(), xBuf.Length());
encoder.write_string("y");
encoder.write_bytes(yBuf.Elements(), yBuf.Length());
}
if (!aPubKeyObj.Assign(cborPubKeyOut.data(), cborPubKeyOut.size())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult
CBOREncodeAttestationObj(const CryptoBuffer& aAuthDataBuf,
const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
/* out */ CryptoBuffer& aAttestationObj)
{
/*
Attestation Object, encoded in CBOR (description is CDDL)
attObj = {
authData: bytes,
$$attStmtType
}
$$attStmtType //= (
fmt: "fido-u2f",
attStmt: u2fStmtFormat
)
u2fStmtFormat = {
x5c: [ attestnCert: bytes, * (caCert: bytes) ],
sig: bytes
}
*/
cbor::output_dynamic cborAttOut;
cbor::encoder encoder(cborAttOut);
encoder.write_map(3);
{
encoder.write_string("authData");
encoder.write_bytes(aAuthDataBuf.Elements(), aAuthDataBuf.Length());
encoder.write_string("fmt");
encoder.write_string("fido-u2f");
encoder.write_string("attStmt");
encoder.write_map(2);
{
encoder.write_string("x5c");
// U2F wire protocol can only deliver 1 certificate, so it's never a chain
encoder.write_array(1);
encoder.write_bytes(aAttestationCertBuf.Elements(), aAttestationCertBuf.Length());
encoder.write_string("sig");
encoder.write_bytes(aSignatureBuf.Elements(), aSignatureBuf.Length());
}
}
if (!aAttestationObj.Assign(cborAttOut.data(), cborAttOut.size())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
}
}

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef mozilla_dom_WebAuthnCBORUtil_h
#define mozilla_dom_WebAuthnCBORUtil_h
/*
* Serialize and deserialize CBOR data formats for WebAuthn
*/
#include "mozilla/dom/CryptoBuffer.h"
namespace mozilla {
namespace dom {
nsresult
CBOREncodePublicKeyObj(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aPubKeyObj);
nsresult
CBOREncodeAttestationObj(const CryptoBuffer& aAuthDataBuf,
const CryptoBuffer& aAttestationCertBuf,
const CryptoBuffer& aSignatureBuf,
/* out */ CryptoBuffer& aAttestationObj);
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_WebAuthnCBORUtil_h

View File

@ -12,6 +12,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/AuthenticatorAttestationResponse.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WebAuthnCBORUtil.h"
#include "mozilla/dom/WebAuthnManager.h"
#include "mozilla/dom/WebAuthnUtil.h"
#include "mozilla/dom/PWebAuthnTransaction.h"
@ -25,6 +26,13 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace dom {
/***********************************************************************
* Protocol Constants
**********************************************************************/
const uint8_t FLAG_TUP = 0x01; // Test of User Presence required
const uint8_t FLAG_AT = 0x40; // Authenticator Data is provided
/***********************************************************************
* Statics
**********************************************************************/
@ -54,7 +62,10 @@ GetAlgorithmName(const OOS& aAlgorithm,
// TODO: Coerce to string and extract name. See WebCryptoTask.cpp
}
if (!NormalizeToken(aName, aName)) {
// Only ES256 is currently supported
if (NORMALIZED_EQUALS(aName, JWK_ALG_ECDSA_P_256)) {
aName.AssignLiteral(JWK_ALG_ECDSA_P_256);
} else {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -393,7 +404,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
if (normalizedParams[a].mType == PublicKeyCredentialType::Public_key &&
normalizedParams[a].mAlgorithm.IsString() &&
normalizedParams[a].mAlgorithm.GetAsString().EqualsLiteral(
WEBCRYPTO_NAMED_CURVE_P256)) {
JWK_ALG_ECDSA_P_256)) {
isValidCombination = true;
break;
}
@ -654,22 +665,35 @@ WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
CryptoBuffer regData;
if (NS_WARN_IF(!regData.Assign(aRegBuffer.Elements(), aRegBuffer.Length()))) {
mTransactionPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
Cancel(NS_ERROR_OUT_OF_MEMORY);
return;
}
mozilla::dom::CryptoBuffer aaguidBuf;
if (NS_WARN_IF(!aaguidBuf.SetCapacity(16, mozilla::fallible))) {
Cancel(NS_ERROR_OUT_OF_MEMORY);
return;
}
// TODO: Adjust the AAGUID from all zeroes in Bug 1381575 (if needed)
// See https://github.com/w3c/webauthn/issues/506
for (int i=0; i<16; i++) {
aaguidBuf.AppendElement(0x00, mozilla::fallible);
}
// Decompose the U2F registration packet
CryptoBuffer pubKeyBuf;
CryptoBuffer keyHandleBuf;
CryptoBuffer attestationCertBuf;
CryptoBuffer signatureBuf;
// Only handles attestation cert chains of length=1.
nsresult rv = U2FDecomposeRegistrationResponse(regData, pubKeyBuf, keyHandleBuf,
attestationCertBuf, signatureBuf);
if (NS_WARN_IF(NS_FAILED(rv))) {
Cancel(rv);
return;
}
MOZ_ASSERT(keyHandleBuf.Length() <= 0xFFFF);
CryptoBuffer clientDataBuf;
if (!clientDataBuf.Assign(mClientData.ref())) {
@ -691,13 +715,64 @@ WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
return;
}
// Construct the public key object
CryptoBuffer pubKeyObj;
rv = CBOREncodePublicKeyObj(pubKeyBuf, pubKeyObj);
if (NS_FAILED(rv)) {
Cancel(rv);
return;
}
// Format:
// 32 bytes: SHA256 of the RP ID
// 1 byte: flags (TUP & AT)
// 4 bytes: sign counter
// variable: attestation data struct
// - 16 bytes: AAGUID
// - 2 bytes: Length of Credential ID
// - L bytes: Credential ID
// - variable: CBOR-format public key
// variable: CBOR-format extension auth data (optional, not flagged)
mozilla::dom::CryptoBuffer authDataBuf;
if (NS_WARN_IF(!authDataBuf.SetCapacity(32 + 1 + 4 + aaguidBuf.Length() + 2 +
keyHandleBuf.Length() +
pubKeyObj.Length(),
mozilla::fallible))) {
Cancel(NS_ERROR_OUT_OF_MEMORY);
return;
}
authDataBuf.AppendElements(rpIdHashBuf, mozilla::fallible);
authDataBuf.AppendElement(FLAG_TUP | FLAG_AT, mozilla::fallible);
// During create credential, counter is always 0 for U2F
// See https://github.com/w3c/webauthn/issues/507
authDataBuf.AppendElement(0x00, mozilla::fallible);
authDataBuf.AppendElement(0x00, mozilla::fallible);
authDataBuf.AppendElement(0x00, mozilla::fallible);
authDataBuf.AppendElement(0x00, mozilla::fallible);
authDataBuf.AppendElements(aaguidBuf, mozilla::fallible);
authDataBuf.AppendElement((keyHandleBuf.Length() >> 8) & 0xFF, mozilla::fallible);
authDataBuf.AppendElement((keyHandleBuf.Length() >> 0) & 0xFF, mozilla::fallible);
authDataBuf.AppendElements(keyHandleBuf, mozilla::fallible);
authDataBuf.AppendElements(pubKeyObj, mozilla::fallible);
CryptoBuffer attObj;
rv = CBOREncodeAttestationObj(authDataBuf, attestationCertBuf, signatureBuf,
attObj);
if (NS_FAILED(rv)) {
Cancel(rv);
return;
}
// Create a new PublicKeyCredential object and populate its fields with the
// values returned from the authenticator as well as the clientDataJSON
// computed earlier.
RefPtr<AuthenticatorAttestationResponse> attestation =
new AuthenticatorAttestationResponse(mCurrentParent);
attestation->SetClientDataJSON(clientDataBuf);
attestation->SetAttestationObject(regData);
attestation->SetAttestationObject(attObj);
RefPtr<PublicKeyCredential> credential = new PublicKeyCredential(mCurrentParent);
credential->SetRawId(keyHandleBuf);

View File

@ -18,7 +18,9 @@ ReadToCryptoBuffer(pkix::Reader& aSrc, /* out */ CryptoBuffer& aDest,
return NS_ERROR_DOM_UNKNOWN_ERR;
}
aDest.ClearAndRetainStorage();
if (!aDest.SetCapacity(aLen, mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t offset = 0; offset < aLen; ++offset) {
uint8_t b;
@ -104,7 +106,7 @@ U2FDecomposeRegistrationResponse(const CryptoBuffer& aResponse,
// We have to parse the ASN.1 SEQUENCE on the outside to determine the cert's
// length.
pkix::Input cert;
if (pkix::der::ExpectTagAndGetValue(input, pkix::der::SEQUENCE, cert)
if (pkix::der::ExpectTagAndGetTLV(input, pkix::der::SEQUENCE, cert)
!= pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
@ -124,6 +126,38 @@ U2FDecomposeRegistrationResponse(const CryptoBuffer& aResponse,
return rv;
}
MOZ_ASSERT(input.AtEnd());
return NS_OK;
}
nsresult
U2FDecomposeECKey(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aXcoord,
/* out */ CryptoBuffer& aYcoord)
{
pkix::Input pubKey;
pubKey.Init(aPubKeyBuf.Elements(), aPubKeyBuf.Length());
pkix::Reader input(pubKey);
uint8_t b;
if (input.Read(b) != pkix::Success) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
if (b != 0x04) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
nsresult rv = ReadToCryptoBuffer(input, aXcoord, 32);
if (NS_FAILED(rv)) {
return rv;
}
rv = ReadToCryptoBuffer(input, aYcoord, 32);
if (NS_FAILED(rv)) {
return rv;
}
MOZ_ASSERT(input.AtEnd());
return NS_OK;
}

View File

@ -32,6 +32,11 @@ nsresult
ReadToCryptoBuffer(pkix::Reader& aSrc, /* out */ CryptoBuffer& aDest,
uint32_t aLen);
nsresult
U2FDecomposeECKey(const CryptoBuffer& aPubKeyBuf,
/* out */ CryptoBuffer& aXcoord,
/* out */ CryptoBuffer& aYcoord);
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,35 @@
cbor-cpp
========
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/naphaso/cbor-cpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
CBOR C++ serialization library
Just a simple SAX-like Concise Binary Object Representation (CBOR).
[http://tools.ietf.org/html/rfc7049](http://tools.ietf.org/html/rfc7049)
#### Examples
```C++
cbor::output_dynamic output;
{ //encoding
cbor::encoder encoder(output);
encoder.write_array(5);
{
encoder.write_int(123);
encoder.write_string("bar");
encoder.write_int(321);
encoder.write_int(321);
encoder.write_string("foo");
}
}
{ // decoding
cbor::input input(output.data(), output.size());
cbor::listener_debug listener;
cbor::decoder decoder(input, listener);
decoder.run();
}
```

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,5 @@
This library [1] has been stripped down to only the CBOR encoding parts, as there are outstanding issues [2]
related to memory safety for the decoder.
[1] https://github.com/naphaso/cbor-cpp/
[2] https://github.com/naphaso/cbor-cpp/issues/8

View File

@ -0,0 +1,23 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef CBOR_CPP_CBOR_H
#define CBOR_CPP_CBOR_H
#include "encoder.h"
#include "output_dynamic.h"
#endif //CBOR_CPP_CBOR_H

View File

@ -0,0 +1,150 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "encoder.h"
using namespace cbor;
encoder::encoder(output &out) {
_out = &out;
}
encoder::~encoder() {
}
void encoder::write_type_value(int major_type, unsigned int value) {
major_type <<= 5;
if(value < 24) {
_out->put_byte((unsigned char) (major_type | value));
} else if(value < 256) {
_out->put_byte((unsigned char) (major_type | 24));
_out->put_byte((unsigned char) value);
} else if(value < 65536) {
_out->put_byte((unsigned char) (major_type | 25));
_out->put_byte((unsigned char) (value >> 8));
_out->put_byte((unsigned char) value);
} else {
_out->put_byte((unsigned char) (major_type | 26));
_out->put_byte((unsigned char) (value >> 24));
_out->put_byte((unsigned char) (value >> 16));
_out->put_byte((unsigned char) (value >> 8));
_out->put_byte((unsigned char) value);
}
}
void encoder::write_type_value(int major_type, unsigned long long value) {
major_type <<= 5;
if(value < 24ULL) {
_out->put_byte((unsigned char) (major_type | value));
} else if(value < 256ULL) {
_out->put_byte((unsigned char) (major_type | 24));
_out->put_byte((unsigned char) value);
} else if(value < 65536ULL) {
_out->put_byte((unsigned char) (major_type | 25));
_out->put_byte((unsigned char) (value >> 8));
_out->put_byte((unsigned char) value);
} else if(value < 4294967296ULL) {
_out->put_byte((unsigned char) (major_type | 26));
_out->put_byte((unsigned char) (value >> 24));
_out->put_byte((unsigned char) (value >> 16));
_out->put_byte((unsigned char) (value >> 8));
_out->put_byte((unsigned char) value);
} else {
_out->put_byte((unsigned char) (major_type | 27));
_out->put_byte((unsigned char) (value >> 56));
_out->put_byte((unsigned char) (value >> 48));
_out->put_byte((unsigned char) (value >> 40));
_out->put_byte((unsigned char) (value >> 32));
_out->put_byte((unsigned char) (value >> 24));
_out->put_byte((unsigned char) (value >> 16));
_out->put_byte((unsigned char) (value >> 8));
_out->put_byte((unsigned char) value);
}
}
void encoder::write_int(unsigned int value) {
write_type_value(0, value);
}
void encoder::write_int(unsigned long long value) {
write_type_value(0, value);
}
void encoder::write_int(long long value) {
if(value < 0) {
write_type_value(1, (unsigned long long) -(value+1));
} else {
write_type_value(0, (unsigned long long) value);
}
}
void encoder::write_int(int value) {
if(value < 0) {
write_type_value(1, (unsigned int) -(value+1));
} else {
write_type_value(0, (unsigned int) value);
}
}
void encoder::write_bytes(const unsigned char *data, unsigned int size) {
write_type_value(2, size);
_out->put_bytes(data, size);
}
void encoder::write_string(const char *data, unsigned int size) {
write_type_value(3, size);
_out->put_bytes((const unsigned char *) data, size);
}
void encoder::write_string(const std::string str) {
write_type_value(3, (unsigned int) str.size());
_out->put_bytes((const unsigned char *) str.c_str(), (int) str.size());
}
void encoder::write_array(int size) {
write_type_value(4, (unsigned int) size);
}
void encoder::write_map(int size) {
write_type_value(5, (unsigned int) size);
}
void encoder::write_tag(const unsigned int tag) {
write_type_value(6, tag);
}
void encoder::write_special(int special) {
write_type_value(7, (unsigned int) special);
}
void encoder::write_bool(bool value) {
if (value == true) {
_out->put_byte((unsigned char) 0xf5);
} else {
_out->put_byte((unsigned char) 0xf4);
}
}
void encoder::write_null() {
_out->put_byte((unsigned char) 0xf6);
}
void encoder::write_undefined() {
_out->put_byte((unsigned char) 0xf7);
}

View File

@ -0,0 +1,68 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __CborEncoder_H_
#define __CborEncoder_H_
#include "output.h"
#include <string>
namespace cbor {
class encoder {
private:
output *_out;
public:
explicit encoder(output &out);
~encoder();
void write_bool(bool value);
void write_int(int value);
void write_int(long long value);
void write_int(unsigned int value);
void write_int(unsigned long long value);
void write_bytes(const unsigned char *data, unsigned int size);
void write_string(const char *data, unsigned int size);
void write_string(const std::string str);
void write_array(int size);
void write_map(int size);
void write_tag(const unsigned int tag);
void write_special(int special);
void write_null();
void write_undefined();
private:
void write_type_value(int major_type, unsigned int value);
void write_type_value(int major_type, unsigned long long value);
};
}
#endif //__CborEncoder_H_

View File

@ -0,0 +1,34 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __CborOutput_H_
#define __CborOutput_H_
namespace cbor {
class output {
public:
virtual unsigned char *data() = 0;
virtual unsigned int size() = 0;
virtual void put_byte(unsigned char value) = 0;
virtual void put_bytes(const unsigned char *data, int size) = 0;
};
}
#endif //__CborOutput_H_

View File

@ -0,0 +1,69 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "output_dynamic.h"
#include <string.h>
#include <stdlib.h>
using namespace cbor;
void output_dynamic::init(unsigned int initalCapacity) {
this->_capacity = initalCapacity;
this->_buffer = new unsigned char[initalCapacity];
this->_offset = 0;
}
output_dynamic::output_dynamic() {
init(256);
}
output_dynamic::output_dynamic(unsigned int inital_capacity) {
init(inital_capacity);
}
output_dynamic::~output_dynamic() {
delete _buffer;
}
unsigned char *output_dynamic::data() {
return _buffer;
}
unsigned int output_dynamic::size() {
return _offset;
}
void output_dynamic::put_byte(unsigned char value) {
if(_offset < _capacity) {
_buffer[_offset++] = value;
} else {
_capacity *= 2;
_buffer = (unsigned char *) realloc(_buffer, _capacity);
_buffer[_offset++] = value;
}
}
void output_dynamic::put_bytes(const unsigned char *data, int size) {
while(_offset + size > _capacity) {
_capacity *= 2;
_buffer = (unsigned char *) realloc(_buffer, _capacity);
}
memcpy(_buffer + _offset, data, size);
_offset += size;
}

View File

@ -0,0 +1,51 @@
/*
Copyright 2014-2015 Stanislav Ovsyannikov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef __CborDynamicOutput_H_
#define __CborDynamicOutput_H_
#include "output.h"
namespace cbor {
class output_dynamic : public output {
private:
unsigned char *_buffer;
unsigned int _capacity;
unsigned int _offset;
public:
output_dynamic();
explicit output_dynamic(unsigned int inital_capacity);
~output_dynamic();
virtual unsigned char *data();
virtual unsigned int size();
virtual void put_byte(unsigned char value);
virtual void put_bytes(const unsigned char *data, int size);
private:
void init(unsigned int initalCapacity);
};
}
#endif //__CborDynamicOutput_H_

View File

@ -21,26 +21,30 @@ EXPORTS.mozilla.dom += [
'U2FSoftTokenManager.h',
'U2FTokenManager.h',
'U2FTokenTransport.h',
'WebAuthnCBORUtil.h',
'WebAuthnManager.h',
'WebAuthnRequest.h',
'WebAuthnTransactionChild.h',
'WebAuthnTransactionParent.h',
'WebAuthnUtil.h'
'WebAuthnUtil.h',
]
UNIFIED_SOURCES += [
'AuthenticatorAssertionResponse.cpp',
'AuthenticatorAttestationResponse.cpp',
'AuthenticatorResponse.cpp',
'cbor-cpp/src/encoder.cpp',
'cbor-cpp/src/output_dynamic.cpp',
'NSSU2FTokenRemote.cpp',
'PublicKeyCredential.cpp',
'U2FHIDTokenManager.cpp',
'U2FSoftTokenManager.cpp',
'U2FTokenManager.cpp',
'WebAuthnCBORUtil.cpp',
'WebAuthnManager.cpp',
'WebAuthnTransactionChild.cpp',
'WebAuthnTransactionParent.cpp',
'WebAuthnUtil.cpp'
'WebAuthnUtil.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -0,0 +1,406 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
(function(global, undefined) { "use strict";
var POW_2_24 = 5.960464477539063e-8,
POW_2_32 = 4294967296,
POW_2_53 = 9007199254740992;
function encode(value) {
var data = new ArrayBuffer(256);
var dataView = new DataView(data);
var lastLength;
var offset = 0;
function prepareWrite(length) {
var newByteLength = data.byteLength;
var requiredLength = offset + length;
while (newByteLength < requiredLength)
newByteLength <<= 1;
if (newByteLength !== data.byteLength) {
var oldDataView = dataView;
data = new ArrayBuffer(newByteLength);
dataView = new DataView(data);
var uint32count = (offset + 3) >> 2;
for (var i = 0; i < uint32count; ++i)
dataView.setUint32(i << 2, oldDataView.getUint32(i << 2));
}
lastLength = length;
return dataView;
}
function commitWrite() {
offset += lastLength;
}
function writeFloat64(value) {
commitWrite(prepareWrite(8).setFloat64(offset, value));
}
function writeUint8(value) {
commitWrite(prepareWrite(1).setUint8(offset, value));
}
function writeUint8Array(value) {
var dataView = prepareWrite(value.length);
for (var i = 0; i < value.length; ++i)
dataView.setUint8(offset + i, value[i]);
commitWrite();
}
function writeUint16(value) {
commitWrite(prepareWrite(2).setUint16(offset, value));
}
function writeUint32(value) {
commitWrite(prepareWrite(4).setUint32(offset, value));
}
function writeUint64(value) {
var low = value % POW_2_32;
var high = (value - low) / POW_2_32;
var dataView = prepareWrite(8);
dataView.setUint32(offset, high);
dataView.setUint32(offset + 4, low);
commitWrite();
}
function writeTypeAndLength(type, length) {
if (length < 24) {
writeUint8(type << 5 | length);
} else if (length < 0x100) {
writeUint8(type << 5 | 24);
writeUint8(length);
} else if (length < 0x10000) {
writeUint8(type << 5 | 25);
writeUint16(length);
} else if (length < 0x100000000) {
writeUint8(type << 5 | 26);
writeUint32(length);
} else {
writeUint8(type << 5 | 27);
writeUint64(length);
}
}
function encodeItem(value) {
var i;
if (value === false)
return writeUint8(0xf4);
if (value === true)
return writeUint8(0xf5);
if (value === null)
return writeUint8(0xf6);
if (value === undefined)
return writeUint8(0xf7);
switch (typeof value) {
case "number":
if (Math.floor(value) === value) {
if (0 <= value && value <= POW_2_53)
return writeTypeAndLength(0, value);
if (-POW_2_53 <= value && value < 0)
return writeTypeAndLength(1, -(value + 1));
}
writeUint8(0xfb);
return writeFloat64(value);
case "string":
var utf8data = [];
for (i = 0; i < value.length; ++i) {
var charCode = value.charCodeAt(i);
if (charCode < 0x80) {
utf8data.push(charCode);
} else if (charCode < 0x800) {
utf8data.push(0xc0 | charCode >> 6);
utf8data.push(0x80 | charCode & 0x3f);
} else if (charCode < 0xd800) {
utf8data.push(0xe0 | charCode >> 12);
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
utf8data.push(0x80 | charCode & 0x3f);
} else {
charCode = (charCode & 0x3ff) << 10;
charCode |= value.charCodeAt(++i) & 0x3ff;
charCode += 0x10000;
utf8data.push(0xf0 | charCode >> 18);
utf8data.push(0x80 | (charCode >> 12) & 0x3f);
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
utf8data.push(0x80 | charCode & 0x3f);
}
}
writeTypeAndLength(3, utf8data.length);
return writeUint8Array(utf8data);
default:
var length;
if (Array.isArray(value)) {
length = value.length;
writeTypeAndLength(4, length);
for (i = 0; i < length; ++i)
encodeItem(value[i]);
} else if (value instanceof Uint8Array) {
writeTypeAndLength(2, value.length);
writeUint8Array(value);
} else {
var keys = Object.keys(value);
length = keys.length;
writeTypeAndLength(5, length);
for (i = 0; i < length; ++i) {
var key = keys[i];
encodeItem(key);
encodeItem(value[key]);
}
}
}
}
encodeItem(value);
if ("slice" in data)
return data.slice(0, offset);
var ret = new ArrayBuffer(offset);
var retView = new DataView(ret);
for (var i = 0; i < offset; ++i)
retView.setUint8(i, dataView.getUint8(i));
return ret;
}
function decode(data, tagger, simpleValue) {
var dataView = new DataView(data);
var offset = 0;
if (typeof tagger !== "function")
tagger = function(value) { return value; };
if (typeof simpleValue !== "function")
simpleValue = function() { return undefined; };
function commitRead(length, value) {
offset += length;
return value;
}
function readArrayBuffer(length) {
return commitRead(length, new Uint8Array(data, offset, length));
}
function readFloat16() {
var tempArrayBuffer = new ArrayBuffer(4);
var tempDataView = new DataView(tempArrayBuffer);
var value = readUint16();
var sign = value & 0x8000;
var exponent = value & 0x7c00;
var fraction = value & 0x03ff;
if (exponent === 0x7c00)
exponent = 0xff << 10;
else if (exponent !== 0)
exponent += (127 - 15) << 10;
else if (fraction !== 0)
return (sign ? -1 : 1) * fraction * POW_2_24;
tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
return tempDataView.getFloat32(0);
}
function readFloat32() {
return commitRead(4, dataView.getFloat32(offset));
}
function readFloat64() {
return commitRead(8, dataView.getFloat64(offset));
}
function readUint8() {
return commitRead(1, dataView.getUint8(offset));
}
function readUint16() {
return commitRead(2, dataView.getUint16(offset));
}
function readUint32() {
return commitRead(4, dataView.getUint32(offset));
}
function readUint64() {
return readUint32() * POW_2_32 + readUint32();
}
function readBreak() {
if (dataView.getUint8(offset) !== 0xff)
return false;
offset += 1;
return true;
}
function readLength(additionalInformation) {
if (additionalInformation < 24)
return additionalInformation;
if (additionalInformation === 24)
return readUint8();
if (additionalInformation === 25)
return readUint16();
if (additionalInformation === 26)
return readUint32();
if (additionalInformation === 27)
return readUint64();
if (additionalInformation === 31)
return -1;
throw "Invalid length encoding";
}
function readIndefiniteStringLength(majorType) {
var initialByte = readUint8();
if (initialByte === 0xff)
return -1;
var length = readLength(initialByte & 0x1f);
if (length < 0 || (initialByte >> 5) !== majorType)
throw "Invalid indefinite length element";
return length;
}
function appendUtf16Data(utf16data, length) {
for (var i = 0; i < length; ++i) {
var value = readUint8();
if (value & 0x80) {
if (value < 0xe0) {
value = (value & 0x1f) << 6
| (readUint8() & 0x3f);
length -= 1;
} else if (value < 0xf0) {
value = (value & 0x0f) << 12
| (readUint8() & 0x3f) << 6
| (readUint8() & 0x3f);
length -= 2;
} else {
value = (value & 0x0f) << 18
| (readUint8() & 0x3f) << 12
| (readUint8() & 0x3f) << 6
| (readUint8() & 0x3f);
length -= 3;
}
}
if (value < 0x10000) {
utf16data.push(value);
} else {
value -= 0x10000;
utf16data.push(0xd800 | (value >> 10));
utf16data.push(0xdc00 | (value & 0x3ff));
}
}
}
function decodeItem() {
var initialByte = readUint8();
var majorType = initialByte >> 5;
var additionalInformation = initialByte & 0x1f;
var i;
var length;
if (majorType === 7) {
switch (additionalInformation) {
case 25:
return readFloat16();
case 26:
return readFloat32();
case 27:
return readFloat64();
}
}
length = readLength(additionalInformation);
if (length < 0 && (majorType < 2 || 6 < majorType))
throw "Invalid length";
switch (majorType) {
case 0:
return length;
case 1:
return -1 - length;
case 2:
if (length < 0) {
var elements = [];
var fullArrayLength = 0;
while ((length = readIndefiniteStringLength(majorType)) >= 0) {
fullArrayLength += length;
elements.push(readArrayBuffer(length));
}
var fullArray = new Uint8Array(fullArrayLength);
var fullArrayOffset = 0;
for (i = 0; i < elements.length; ++i) {
fullArray.set(elements[i], fullArrayOffset);
fullArrayOffset += elements[i].length;
}
return fullArray;
}
return readArrayBuffer(length);
case 3:
var utf16data = [];
if (length < 0) {
while ((length = readIndefiniteStringLength(majorType)) >= 0)
appendUtf16Data(utf16data, length);
} else
appendUtf16Data(utf16data, length);
return String.fromCharCode.apply(null, utf16data);
case 4:
var retArray;
if (length < 0) {
retArray = [];
while (!readBreak())
retArray.push(decodeItem());
} else {
retArray = new Array(length);
for (i = 0; i < length; ++i)
retArray[i] = decodeItem();
}
return retArray;
case 5:
var retObject = {};
for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
var key = decodeItem();
retObject[key] = decodeItem();
}
return retObject;
case 6:
return tagger(decodeItem(), length);
case 7:
switch (length) {
case 20:
return false;
case 21:
return true;
case 22:
return null;
case 23:
return undefined;
default:
return simpleValue(length);
}
}
}
var ret = decodeItem();
if (offset !== data.byteLength)
throw "Remaining bytes";
return ret;
}
var obj = { encode: encode, decode: decode };
if (typeof define === "function" && define.amd)
define("cbor/cbor", obj);
else if (typeof module !== "undefined" && module.exports)
module.exports = obj;
else if (!global.CBOR)
global.CBOR = obj;
})(this);

View File

@ -1,5 +1,6 @@
[DEFAULT]
support-files =
cbor/cbor.js
pkijs/asn1.js
pkijs/common.js
pkijs/x509_schema.js

View File

@ -8,6 +8,7 @@
<script type="text/javascript" src="pkijs/asn1.js"></script>
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
<script type="text/javascript" src="cbor/cbor.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -39,26 +40,27 @@ function() {
testMakeCredential();
function checkCredentialValid(aCredInfo) {
function decodeCreatedCredential(aCredInfo) {
/* PublicKeyCredential : Credential
- rawId: Key Handle buffer pulled from U2F Register() Response
- response : AuthenticatorAttestationResponse : AuthenticatorResponse
- attestationObject: RP ID Hash || U2F Sign() Response
- attestationObject: CBOR object
- clientDataJSON: serialized JSON
- clientExtensionResults: (not yet supported)
*/
ok(aCredInfo.rawId.length > 0, "Key ID exists");
is(aCredInfo.response.attestationObject[0], 0x05, "Reserved byte is correct");
let clientData = JSON.parse(buffer2string(aCredInfo.response.clientDataJSON));
is(clientData.challenge, bytesToBase64UrlSafe(gCredentialChallenge), "Challenge is correct");
is(clientData.origin, window.location.origin, "Origin is correct");
is(clientData.hashAlg, "S256", "Hash algorithm is correct");
return decodeU2FRegistration(aCredInfo.response.attestationObject)
.then(function(u2fObj) {
aCredInfo.u2fReg = u2fObj;
return webAuthnDecodeAttestation(aCredInfo.response.attestationObject.buffer)
.then(function(decodedResult) {
aCredInfo.clientDataObj = clientData;
aCredInfo.publicKeyHandle = decodedResult.publicKeyHandle;
aCredInfo.attestationObject = decodedResult.attestationObject;
return aCredInfo;
});
}
@ -106,7 +108,7 @@ function() {
function testMakeCredential() {
let rp = {id: document.domain, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "P-256"};
let param = {type: "public-key", algorithm: "ES256"};
let makeCredentialOptions = {
rp: rp,
user: user,
@ -114,7 +116,7 @@ function() {
parameters: [param]
};
credm.create({publicKey: makeCredentialOptions})
.then(checkCredentialValid)
.then(decodeCreatedCredential)
.then(testMakeDuplicate)
.catch(function(aReason) {
ok(false, aReason);
@ -125,7 +127,7 @@ function() {
function testMakeDuplicate(aCredInfo) {
let rp = {id: document.domain, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "P-256"};
let param = {type: "public-key", algorithm: "ES256"};
let makeCredentialOptions = {
rp: rp,
user: user,
@ -162,7 +164,7 @@ function() {
credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(function(aAssertion) {
/* Pass along the pubKey. */
return checkAssertionAndSigValid(aCredInfo.u2fReg.publicKey, aAssertion);
return checkAssertionAndSigValid(aCredInfo.publicKeyHandle, aAssertion);
})
.then(function(aSigVerifyResult) {
ok(aSigVerifyResult, "Signing signature verified");

View File

@ -62,7 +62,7 @@
let rp = {id: document.domain, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
let param = {type: "public-key", algorithm: "es256"};
let unsupportedParam = {type: "public-key", algorithm: "3DES"};
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};

View File

@ -45,7 +45,7 @@ function() {
function testMakeCredential() {
let rp = {id: document.domain, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
let param = {type: "public-key", algorithm: "es256"};
let makeCredentialOptions = {
rp: rp, user: user, challenge: credentialChallenge, parameters: [param]
};

View File

@ -61,7 +61,7 @@
window.crypto.getRandomValues(chall);
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
let param = {type: "public-key", algorithm: "Es256"};
var testFuncs = [
function() {

View File

@ -127,24 +127,53 @@ function hexDecode(str) {
return new Uint8Array(str.match(/../g).map(x => parseInt(x, 16)));
}
function decodeU2FRegistration(aRegData) {
if (aRegData[0] != 0x05) {
return Promise.reject("Sentinal byte != 0x05");
function webAuthnDecodeAttestation(aAttestationBuf) {
let attObj = CBOR.decode(aAttestationBuf);
console.log("Attestation CBOR Object:", attObj);
if (!("authData" in attObj && "fmt" in attObj && "attStmt" in attObj)) {
throw "Invalid CBOR Attestation Object";
}
if (!("sig" in attObj.attStmt && "x5c" in attObj.attStmt)) {
throw "Invalid CBOR Attestation Statement";
}
let keyHandleLength = aRegData[66];
let u2fRegObj = {
publicKeyBytes: aRegData.slice(1, 66),
keyHandleBytes: aRegData.slice(67, 67 + keyHandleLength),
attestationBytes: aRegData.slice(67 + keyHandleLength)
let rpIdHash = attObj.authData.slice(0, 32);
let flags = attObj.authData.slice(32, 33);
let counter = attObj.authData.slice(33, 37);
let attData = {};
attData.aaguid = attObj.authData.slice(37, 53);
attData.credIdLen = (attObj.authData[53] << 8) + attObj.authData[54];
attData.credId = attObj.authData.slice(55, 55 + attData.credIdLen);
console.log(":: CBOR Attestation Object Data ::");
console.log("RP ID Hash: " + hexEncode(rpIdHash));
console.log("Counter: " + hexEncode(counter) + " Flags: " + flags);
console.log("AAGUID: " + hexEncode(attData.aaguid));
cborPubKey = attObj.authData.slice(55 + attData.credIdLen);
var pubkeyObj = CBOR.decode(cborPubKey.buffer);
if (!("alg" in pubkeyObj && "x" in pubkeyObj && "y" in pubkeyObj)) {
throw "Invalid CBOR Public Key Object";
}
if (pubkeyObj.alg != "ES256") {
throw "Unexpected public key algorithm";
}
u2fRegObj.keyHandle = bytesToBase64UrlSafe(u2fRegObj.keyHandleBytes);
let pubKeyBytes = assemblePublicKeyBytesData(pubkeyObj.x, pubkeyObj.y);
console.log(":: CBOR Public Key Object Data ::");
console.log("Algorithm: " + pubkeyObj.alg);
console.log("X: " + pubkeyObj.x);
console.log("Y: " + pubkeyObj.y);
console.log("Uncompressed (hex): " + hexEncode(pubKeyBytes));
return importPublicKey(u2fRegObj.publicKeyBytes)
.then(function(keyObj) {
u2fRegObj.publicKey = keyObj;
return u2fRegObj;
return importPublicKey(pubKeyBytes)
.then(function(aKeyHandle) {
return {
attestationObject: attObj,
attestationAuthData: attData,
publicKeyBytes: pubKeyBytes,
publicKeyHandle: aKeyHandle,
};
});
}
@ -175,6 +204,19 @@ function deriveAppAndChallengeParam(appId, clientData) {
});
}
function assemblePublicKeyBytesData(xCoord, yCoord) {
// Produce an uncompressed EC key point. These start with 0x04, and then
// two 32-byte numbers denoting X and Y.
if (xCoord.length != 32 || yCoord.length != 32) {
throw ("Coordinates must be 32 bytes long");
}
let keyBytes = new Uint8Array(65);
keyBytes[0] = 0x04;
xCoord.map((x, i) => keyBytes[1 + i] = x);
yCoord.map((x, i) => keyBytes[33 + i] = x);
return keyBytes;
}
function assembleSignedData(appParam, presenceAndCounter, challengeParam) {
let signedData = new Uint8Array(32 + 1 + 4 + 32);
appParam.map((x, i) => signedData[0 + i] = x);

View File

@ -31,6 +31,6 @@ if ! which mozmake 2>/dev/null; then
export PATH="$PATH:$SOURCE/.."
if ! which mozmake 2>/dev/null; then
TT_SERVER=${TT_SERVER:-https://api.pub.build.mozilla.org/tooltool/}
( cd $SOURCE/..; $SOURCE/mach artifact toolchain -v --tooltool-manifest $SOURCE/browser/config/tooltool-manifests/${platform:-win32}/releng.manifest --tooltool-url $TT_SERVER --retry 4${TOOLTOOL_CACHE:+ --cache-dir ${TOOLTOOL_CACHE}})
( cd $SOURCE/..; $SOURCE/mach artifact toolchain -v --tooltool-manifest $SOURCE/browser/config/tooltool-manifests/${platform:-win32}/releng.manifest --tooltool-url $TT_SERVER --retry 4${TOOLTOOL_CACHE:+ --cache-dir ${TOOLTOOL_CACHE}}${MOZ_TOOLCHAINS:+ ${MOZ_TOOLCHAINS}})
fi
fi

View File

@ -451,7 +451,7 @@ Statistics::formatDetailedSliceDescription(unsigned i, const SliceData& slice) c
Reason: %s\n\
Reset: %s%s\n\
State: %s -> %s\n\
Page Faults: %ld\n\
Page Faults: %" PRIu64 "\n\
Pause: %.3fms of %s budget (@ %.3fms)\n\
";
char buffer[1024];

View File

@ -567,7 +567,7 @@ ServoRestyleManager::ProcessPostTraversal(
}
// TODO(emilio): We could avoid some refcount traffic here, specially in the
// ServoComputedValues case, which uses atomic refcounting.
// ServoStyleContext case, which uses atomic refcounting.
//
// Hold the old style context alive, because it could become a dangling
// pointer during the replacement. In practice it's not a huge deal, but
@ -605,7 +605,7 @@ ServoRestyleManager::ProcessPostTraversal(
MOZ_ASSERT(styleFrame || displayContentsNode);
RefPtr<ServoStyleContext> currentContext =
aRestyleState.StyleSet().ResolveServoStyle(aElement, aRestyleBehavior);
MOZ_ASSERT(oldStyleContext->ComputedValues() != currentContext->ComputedValues());
MOZ_ASSERT(oldStyleContext->ComputedData() != currentContext->ComputedData());
newContext = currentContext;
newContext->UpdateWithElementState(aElement);

View File

@ -23,7 +23,7 @@ load 148245-1.html
load 149014-1.html
load 150431-1.html
load 176915-1.html
asserts-if(stylo,13) load 191272-1.html # bug 1324636
load 191272-1.html
load 199696-1.html
load 217903-1.html
load 223064-1.html

View File

@ -1929,7 +1929,7 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat
ServoStyleContext* servoStyle = pseudoStyleContext->GetAsServo();
if (servoStyle) {
hasServoAnimations =
Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle->ComputedValues());
Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle);
if (!hasServoAnimations) {
Servo_SetExplicitStyle(container, servoStyle);
}

View File

@ -178,17 +178,18 @@ nsImageFrame::AccessibleType()
void
nsImageFrame::DisconnectMap()
{
if (mImageMap) {
if (!mImageMap) {
return;
}
mImageMap->Destroy();
mImageMap = nullptr;
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = GetAccService();
if (accService) {
if (nsAccessibilityService* accService = GetAccService()) {
accService->RecreateAccessible(PresContext()->PresShell(), mContent);
}
#endif
}
}
void
@ -1755,8 +1756,7 @@ nsImageFrame::PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
nsLayoutUtils::GetSamplingFilterForFrame(this), dest, aDirtyRect,
svgContext, flags, &anchorPoint);
nsImageMap* map = GetImageMap();
if (map) {
if (nsImageMap* map = GetImageMap()) {
gfxPoint devPixelOffset =
nsLayoutUtils::PointToGfxPoint(dest.TopLeft(),
PresContext()->AppUnitsPerDevPixel());
@ -1929,8 +1929,7 @@ nsImageMap*
nsImageFrame::GetImageMap()
{
if (!mImageMap) {
nsIContent* map = GetMapElement();
if (map) {
if (nsIContent* map = GetMapElement()) {
mImageMap = new nsImageMap();
mImageMap->Init(this, map);
}
@ -2018,9 +2017,7 @@ nsImageFrame::GetContentForEvent(WidgetEvent* aEvent,
return NS_OK;
}
nsImageMap* map = GetImageMap();
if (nullptr != map) {
if (nsImageMap* map = GetImageMap()) {
nsIntPoint p;
TranslateEventCoords(
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this), p);
@ -2049,7 +2046,7 @@ nsImageFrame::HandleEvent(nsPresContext* aPresContext,
aEvent->mMessage == eMouseMove) {
nsImageMap* map = GetImageMap();
bool isServerMap = IsServerImageMap();
if ((nullptr != map) || isServerMap) {
if (map || isServerMap) {
nsIntPoint p;
TranslateEventCoords(
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this), p);
@ -2106,8 +2103,7 @@ nsresult
nsImageFrame::GetCursor(const nsPoint& aPoint,
nsIFrame::Cursor& aCursor)
{
nsImageMap* map = GetImageMap();
if (nullptr != map) {
if (nsImageMap* map = GetImageMap()) {
nsIntPoint p;
TranslateEventCoords(aPoint, p);
nsCOMPtr<nsIContent> area = map->GetArea(p.x, p.y);

View File

@ -713,9 +713,7 @@ nsImageMap::GetBoundsForAreaContent(nsIContent *aContent,
void
nsImageMap::FreeAreas()
{
uint32_t i, n = mAreas.Length();
for (i = 0; i < n; i++) {
Area* area = mAreas.ElementAt(i);
for (auto* area : mAreas) {
if (area->mArea->IsInUncomposedDoc()) {
NS_ASSERTION(area->mArea->GetPrimaryFrame() == mImageFrame,
"Unexpected primary frame");
@ -729,31 +727,28 @@ nsImageMap::FreeAreas()
false);
delete area;
}
mAreas.Clear();
}
nsresult
void
nsImageMap::Init(nsImageFrame* aImageFrame, nsIContent* aMap)
{
NS_PRECONDITION(aMap, "null ptr");
if (!aMap) {
return NS_ERROR_NULL_POINTER;
}
mImageFrame = aImageFrame;
MOZ_ASSERT(aMap);
MOZ_ASSERT(aImageFrame);
mImageFrame = aImageFrame;
mMap = aMap;
mMap->AddMutationObserver(this);
// "Compile" the areas in the map into faster access versions
return UpdateAreas();
UpdateAreas();
}
nsresult
void
nsImageMap::SearchForAreas(nsIContent* aParent, bool& aFoundArea,
bool& aFoundAnchor)
{
nsresult rv = NS_OK;
uint32_t i, n = aParent->GetChildCount();
// Look for <area> or <a> elements. We'll use whichever type we find first.
@ -764,8 +759,7 @@ nsImageMap::SearchForAreas(nsIContent* aParent, bool& aFoundArea,
// <a> element yet, then look for <area>.
if (!aFoundAnchor && child->IsHTMLElement(nsGkAtoms::area)) {
aFoundArea = true;
rv = AddArea(child);
NS_ENSURE_SUCCESS(rv, rv);
AddArea(child);
// Continue to next child. This stops mContainsBlockContents from
// getting set. It also makes us ignore children of <area>s which
@ -778,21 +772,17 @@ nsImageMap::SearchForAreas(nsIContent* aParent, bool& aFoundArea,
// <area> element yet, then look for <a>.
if (!aFoundArea && child->IsHTMLElement(nsGkAtoms::a)) {
aFoundAnchor = true;
rv = AddArea(child);
NS_ENSURE_SUCCESS(rv, rv);
AddArea(child);
}
if (child->IsElement()) {
mContainsBlockContents = true;
rv = SearchForAreas(child, aFoundArea, aFoundAnchor);
NS_ENSURE_SUCCESS(rv, rv);
SearchForAreas(child, aFoundArea, aFoundAnchor);
}
}
return NS_OK;
}
nsresult
void
nsImageMap::UpdateAreas()
{
// Get rid of old area data
@ -802,19 +792,15 @@ nsImageMap::UpdateAreas()
bool foundAnchor = false;
mContainsBlockContents = false;
nsresult rv = SearchForAreas(mMap, foundArea, foundAnchor);
SearchForAreas(mMap, foundArea, foundAnchor);
#ifdef ACCESSIBILITY
if (NS_SUCCEEDED(rv)) {
nsAccessibilityService* accService = GetAccService();
if (accService) {
if (nsAccessibilityService* accService = GetAccService()) {
accService->UpdateImageMap(mImageFrame);
}
}
#endif
return rv;
}
nsresult
void
nsImageMap::AddArea(nsIContent* aArea)
{
static nsIContent::AttrValuesArray strings[] =
@ -846,17 +832,13 @@ nsImageMap::AddArea(nsIContent* aArea)
break;
default:
area = nullptr;
NS_NOTREACHED("FindAttrValueIn returned an unexpected value.");
MOZ_ASSERT_UNREACHABLE("FindAttrValueIn returned an unexpected value.");
break;
}
if (!area)
return NS_ERROR_OUT_OF_MEMORY;
//Add focus listener to track area focus changes
aArea->AddSystemEventListener(NS_LITERAL_STRING("focus"), this, false,
false);
aArea->AddSystemEventListener(NS_LITERAL_STRING("blur"), this, false,
false);
aArea->AddSystemEventListener(NS_LITERAL_STRING("focus"), this, false, false);
aArea->AddSystemEventListener(NS_LITERAL_STRING("blur"), this, false, false);
// This is a nasty hack. It needs to go away: see bug 135040. Once this is
// removed, the code added to RestyleManager::RestyleElement,
@ -869,16 +851,13 @@ nsImageMap::AddArea(nsIContent* aArea)
aArea->GetAttr(kNameSpaceID_None, nsGkAtoms::coords, coords);
area->ParseCoords(coords);
mAreas.AppendElement(area);
return NS_OK;
}
nsIContent*
nsImageMap::GetArea(nscoord aX, nscoord aY) const
{
NS_ASSERTION(mMap, "Not initialized");
uint32_t i, n = mAreas.Length();
for (i = 0; i < n; i++) {
Area* area = mAreas.ElementAt(i);
for (auto* area : mAreas) {
if (area->IsInside(aX, aY)) {
return area->mArea;
}
@ -1012,7 +991,7 @@ nsImageMap::HandleEvent(nsIDOMEvent* aEvent)
}
void
nsImageMap::Destroy(void)
nsImageMap::Destroy()
{
FreeAreas();
mImageFrame = nullptr;

View File

@ -31,7 +31,7 @@ class nsImageMap final : public nsStubMutationObserver,
public:
nsImageMap();
nsresult Init(nsImageFrame* aImageFrame, nsIContent* aMap);
void Init(nsImageFrame* aImageFrame, nsIContent* aMap);
/**
* Return the first area element (in content order) for the given aX,aY pixel
@ -80,11 +80,12 @@ protected:
void FreeAreas();
nsresult UpdateAreas();
nsresult SearchForAreas(nsIContent* aParent, bool& aFoundArea,
void UpdateAreas();
void SearchForAreas(nsIContent* aParent,
bool& aFoundArea,
bool& aFoundAnchor);
nsresult AddArea(nsIContent* aArea);
void AddArea(nsIContent* aArea);
void MaybeUpdateAreas(nsIContent *aContent);

View File

@ -272,8 +272,7 @@ inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement,
ServoStyleContext* servo = styleContext->AsServo();
nsTArray<const RawServoStyleRule*> rawRuleList;
Servo_ComputedValues_GetStyleRuleList(servo->ComputedValues(),
&rawRuleList);
Servo_ComputedValues_GetStyleRuleList(servo, &rawRuleList);
ServoStyleSet* styleSet = shell->StyleSet()->AsServo();
ServoStyleRuleMap* map = styleSet->StyleRuleMap();

View File

@ -1,7 +1,7 @@
include input/reftest.list
include textarea/reftest.list
fuzzy-if(skiaContent,1,4) fails-if(styloVsGecko||stylo) == css-restrictions.html css-restrictions-ref.html
fuzzy-if(skiaContent,1,4) == css-restrictions.html css-restrictions-ref.html
== css-simple-styling.html css-simple-styling-ref.html
!= css-background.html css-background-ref.html
fuzzy-if(skiaContent,1,180) == ignore-pseudo-class.html ignore-pseudo-class-ref.html

View File

@ -25,12 +25,12 @@ load stress-7.html # assertion/crash test
load stress-10.html # crash test
== stress-11.xhtml stress-11-ref.xhtml
fails-if(styloVsGecko||stylo) == border-not-apply.html border-not-apply-ref.html
== border-not-apply.html border-not-apply-ref.html
fails-if(styloVsGecko||stylo) == 287088-1.html 287088-1-ref.html
fails-if(styloVsGecko||stylo) == 287088-2.html 287088-2-ref.html
fails-if(styloVsGecko) == 403177-1.html 403177-1-ref.html
fails-if(styloVsGecko||stylo) == 469227-2.html 469227-2-ref.html
fails-if(styloVsGecko||stylo) == 469227-3.html 469227-3-ref.html
== 469227-2.html 469227-2-ref.html
== 469227-3.html 469227-3-ref.html
fails-if(styloVsGecko||stylo) == restyle-inside-first-line.html restyle-inside-first-line-ref.html
fails-if(styloVsGecko||stylo) == font-styles.html font-styles-ref.html

View File

@ -235,7 +235,7 @@ SERVO_BINDING_FUNC(Servo_ComputedValues_ExtractAnimationValue,
ServoStyleContextBorrowed computed_values,
nsCSSPropertyID property)
SERVO_BINDING_FUNC(Servo_ComputedValues_SpecifiesAnimationsOrTransitions, bool,
ServoComputedValuesBorrowed computed_values)
ServoStyleContextBorrowed computed_values)
SERVO_BINDING_FUNC(Servo_Property_IsAnimatable, bool,
nsCSSPropertyID property)
SERVO_BINDING_FUNC(Servo_Property_IsTransitionable, bool,
@ -472,15 +472,15 @@ SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoStyleContextStrong,
ServoStyleContextBorrowedOrNull parent_style,
mozilla::InheritTarget target)
SERVO_BINDING_FUNC(Servo_ComputedValues_GetStyleBits, uint64_t,
ServoComputedValuesBorrowed values)
ServoStyleContextBorrowed values)
SERVO_BINDING_FUNC(Servo_ComputedValues_EqualCustomProperties, bool,
ServoComputedValuesBorrowed first,
ServoComputedValuesBorrowed second)
ServoComputedDataBorrowed first,
ServoComputedDataBorrowed second)
// Gets the source style rules for the computed values. This returns
// the result via rules, which would include a list of unowned pointers
// to RawServoStyleRule.
SERVO_BINDING_FUNC(Servo_ComputedValues_GetStyleRuleList, void,
ServoComputedValuesBorrowed values,
ServoStyleContextBorrowed values,
RawGeckoServoStyleRuleListBorrowedMut rules)
// Initialize Servo components. Should be called exactly once at startup.
@ -563,14 +563,14 @@ SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
// Get custom property value.
SERVO_BINDING_FUNC(Servo_GetCustomPropertyValue, bool,
ServoComputedValuesBorrowed computed_values,
ServoStyleContextBorrowed computed_values,
const nsAString* name, nsAString* value)
SERVO_BINDING_FUNC(Servo_GetCustomPropertiesCount, uint32_t,
ServoComputedValuesBorrowed computed_values)
ServoStyleContextBorrowed computed_values)
SERVO_BINDING_FUNC(Servo_GetCustomPropertyNameAt, bool,
ServoComputedValuesBorrowed, uint32_t index,
ServoStyleContextBorrowed, uint32_t index,
nsAString* name)
SERVO_BINDING_FUNC(Servo_GetEmptyVariables, const nsStyleVariables*)

View File

@ -107,8 +107,7 @@ typedef mozilla::dom::StyleChildrenIterator RawGeckoStyleChildrenIterator;
typedef mozilla::ServoStyleContext const* ServoStyleContextBorrowed;
typedef mozilla::ServoStyleContext const* ServoStyleContextBorrowedOrNull;
typedef ServoComputedValues const* ServoComputedValuesBorrowed;
typedef ServoComputedValues const* ServoComputedValuesBorrowedOrNull;
typedef ServoComputedData const* ServoComputedDataBorrowed;
struct MOZ_MUST_USE_TYPE ServoStyleContextStrong
{

View File

@ -213,7 +213,7 @@ Gecko_ServoStyleContext_Init(
ServoStyleContext* aContext,
const ServoStyleContext* aParentContext,
RawGeckoPresContextBorrowed aPresContext,
const ServoComputedValues* aValues,
const ServoComputedData* aValues,
mozilla::CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag)
{
@ -224,16 +224,17 @@ Gecko_ServoStyleContext_Init(
auto presContext = const_cast<nsPresContext*>(aPresContext);
new (KnownNotNull, aContext) ServoStyleContext(
parent, presContext, aPseudoTag, aPseudoType,
ServoComputedValuesForgotten(aValues));
ServoComputedDataForgotten(aValues));
}
ServoComputedValues::ServoComputedValues(
const ServoComputedValuesForgotten aValue)
ServoComputedData::ServoComputedData(
const ServoComputedDataForgotten aValue)
{
PodAssign(this, aValue.mPtr);
}
const nsStyleVariables* ServoComputedValues::GetStyleVariables() const
const nsStyleVariables*
ServoComputedData::GetStyleVariables() const
{
return Servo_GetEmptyVariables();
}
@ -398,8 +399,8 @@ Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
}
nsChangeHint
Gecko_CalcStyleDifference(const ServoStyleContext* aOldStyle,
const ServoStyleContext* aNewStyle,
Gecko_CalcStyleDifference(ServoStyleContextBorrowed aOldStyle,
ServoStyleContextBorrowed aNewStyle,
uint64_t aOldStyleBits,
bool* aAnyStyleChanged)
{
@ -416,7 +417,6 @@ Gecko_CalcStyleDifference(const ServoStyleContext* aOldStyle,
&equalStructs,
&samePointerStructs,
relevantStructs);
*aAnyStyleChanged = equalStructs != NS_STYLE_INHERIT_MASK;
return result;
}
@ -648,8 +648,8 @@ Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed aA,
void
Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
ServoStyleContextBorrowedOrNull aOldComputedValues,
ServoStyleContextBorrowedOrNull aComputedValues,
ServoStyleContextBorrowedOrNull aOldComputedData,
ServoStyleContextBorrowedOrNull aComputedData,
UpdateAnimationsTasks aTasks)
{
MOZ_ASSERT(NS_IsMainThread());
@ -670,30 +670,30 @@ Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
presContext->AnimationManager()->
UpdateAnimations(const_cast<dom::Element*>(aElement), pseudoType,
aComputedValues);
aComputedData);
}
// aComputedValues might be nullptr if the target element is now in a
// aComputedData might be nullptr if the target element is now in a
// display:none subtree. We still call Gecko_UpdateAnimations in this case
// because we need to stop CSS animations in the display:none subtree.
// However, we don't need to update transitions since they are stopped by
// RestyleManager::AnimationsWithDestroyedFrame so we just return early
// here.
if (!aComputedValues) {
if (!aComputedData) {
return;
}
if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
MOZ_ASSERT(aOldComputedValues);
MOZ_ASSERT(aOldComputedData);
presContext->TransitionManager()->
UpdateTransitions(const_cast<dom::Element*>(aElement), pseudoType,
aOldComputedValues,
aComputedValues);
aOldComputedData,
aComputedData);
}
if (aTasks & UpdateAnimationsTasks::EffectProperties) {
presContext->EffectCompositor()->UpdateEffectProperties(
aComputedValues, const_cast<dom::Element*>(aElement), pseudoType);
aComputedData, const_cast<dom::Element*>(aElement), pseudoType);
}
if (aTasks & UpdateAnimationsTasks::CascadeResults) {

View File

@ -75,7 +75,7 @@ namespace mozilla {
}
#define STYLE_STRUCT(name_, checkdata_cb_) \
const nsStyle##name_* ServoComputedValues::GetStyle##name_() const { return &name_.mPtr->gecko; }
const nsStyle##name_* ServoComputedData::GetStyle##name_() const { return &name_.mPtr->gecko; }
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
@ -150,7 +150,7 @@ void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* anon_content);
void Gecko_ServoStyleContext_Init(mozilla::ServoStyleContext* context,
ServoStyleContextBorrowedOrNull parent_context,
RawGeckoPresContextBorrowed pres_context, ServoComputedValuesBorrowed values,
RawGeckoPresContextBorrowed pres_context, ServoComputedDataBorrowed values,
mozilla::CSSPseudoElementType pseudo_type, nsIAtom* pseudo_tag);
void Gecko_ServoStyleContext_Destroy(mozilla::ServoStyleContext* context);
@ -378,8 +378,8 @@ void Gecko_SetOwnerDocumentNeedsStyleFlush(RawGeckoElementBorrowed element);
nsStyleContext* Gecko_GetStyleContext(RawGeckoElementBorrowed element,
nsIAtom* aPseudoTagOrNull);
mozilla::CSSPseudoElementType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
nsChangeHint Gecko_CalcStyleDifference(const mozilla::ServoStyleContext* old_style,
const mozilla::ServoStyleContext* new_style,
nsChangeHint Gecko_CalcStyleDifference(ServoStyleContextBorrowed old_style,
ServoStyleContextBorrowed new_style,
uint64_t old_style_bits,
bool* any_style_changed);
nsChangeHint Gecko_HintsHandledForDescendants(nsChangeHint aHint);

View File

@ -247,9 +247,8 @@ whitelist-types = [
"Runnable",
"ServoAttrSnapshot",
"ServoBundledURI",
"ServoComputedValues",
"ServoComputedValuesBorrowed",
"ServoComputedValuesBorrowedOrNull",
"ServoComputedData",
"ServoComputedDataBorrowed",
"ServoElementSnapshot",
"ServoStyleContextStrong",
"ServoStyleContextBorrowed",
@ -320,12 +319,12 @@ mapped-generic-types = [
{ generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
{ generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
{ generic = false, gecko = "mozilla::ServoFontComputationData", servo = "::properties::FontComputationData" },
{ generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::stylearc::Arc<::custom_properties::CustomPropertiesMap>>" },
{ generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" },
{ generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
{ generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::stylearc::RawOffsetArc<::properties::ComputedValues>>" },
{ generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::servo_arc::RawOffsetArc<::properties::ComputedValues>>" },
{ generic = false, gecko = "mozilla::ServoComputedValueFlags", servo = "::properties::computed_value_flags::ComputedValueFlags" },
{ generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::stylearc::RawOffsetArc" },
{ generic = false, gecko = "ServoStyleContextStrong", servo = "::gecko_bindings::sugar::ownership::Strong<ServoStyleContext>" },
{ generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::servo_arc::RawOffsetArc" },
{ generic = false, gecko = "ServoStyleContextStrong", servo = "::gecko_bindings::sugar::ownership::Strong<::properties::ComputedValues>" },
]
fixups = [
{ pat = "root::nsString", rep = "::nsstring::nsStringRepr" },
@ -345,10 +344,9 @@ raw-lines = [
"use gecko_bindings::structs::nsTArray;",
"type nsACString_internal = nsACString;",
"type nsAString_internal = nsAString;",
"pub type ServoStyleContextBorrowed<'a> = &'a ServoStyleContext;",
"pub type ServoStyleContextBorrowed<'a> = &'a ::properties::ComputedValues;",
"pub type ServoStyleContextBorrowedOrNull<'a> = Option<&'a ::properties::ComputedValues>;",
"pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;",
"pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;",
"pub type ServoComputedDataBorrowed<'a> = &'a ServoComputedData;",
]
whitelist-functions = ["Servo_.*", "Gecko_.*"]
structs-types = [
@ -476,7 +474,7 @@ structs-types = [
"Loader",
"LoaderReusableStyleSheets",
"ServoStyleSheet",
"ServoComputedValues",
"ServoComputedData",
"ServoStyleContext",
"ServoStyleContextStrong",
"EffectCompositor_CascadeLevel",

View File

@ -20,17 +20,17 @@ ServoStyleContext::ServoStyleContext(
nsPresContext* aPresContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
ServoComputedValuesForgotten aComputedValues)
ServoComputedDataForgotten aComputedValues)
: nsStyleContext(aParent, aPseudoTag, aPseudoType)
, mSource(aComputedValues)
{
mPresContext = aPresContext;
AddStyleBit(Servo_ComputedValues_GetStyleBits(&mSource));
AddStyleBit(Servo_ComputedValues_GetStyleBits(this));
FinishConstruction();
// No need to call ApplyStyleFixups here, since fixups are handled by Servo when
// producing the ServoComputedValues.
// producing the ServoComputedData.
}
void

View File

@ -22,17 +22,17 @@ public:
nsPresContext* aPresContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
ServoComputedValuesForgotten aComputedValues);
ServoComputedDataForgotten aComputedValues);
nsPresContext* PresContext() const { return mPresContext; }
const ServoComputedValues* ComputedValues() const { return &mSource; }
const ServoComputedData* ComputedData() const { return &mSource; }
void AddRef() { Servo_StyleContext_AddRef(this); }
void Release() { Servo_StyleContext_Release(this); }
ServoStyleContext* GetStyleIfVisited() const
{
return ComputedValues()->visited_style.mPtr;
return ComputedData()->visited_style.mPtr;
}
// Update visited state for a given element, and set the prescontext's
@ -47,7 +47,7 @@ public:
private:
nsPresContext* mPresContext;
ServoComputedValues mSource;
ServoComputedData mSource;
};
} // namespace mozilla

View File

@ -24,7 +24,7 @@ ServoStyleContext::ResolveSameStructsAs(const ServoStyleContext* aOther)
#define STYLE_STRUCT(name_, checkdata_cb) \
if (nsStyle##name_::kHasFinishStyle && newBits & NS_STYLE_INHERIT_BIT(name_)) { \
const nsStyle##name_* data = ComputedValues()->GetStyle##name_(); \
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
const_cast<nsStyle##name_*>(data)->FinishStyle(mPresContext); \
}
#include "nsStyleStructList.h"

View File

@ -782,8 +782,8 @@ ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
aType == CSSPseudoElementType::after;
if (isBeforeOrAfter) {
const nsStyleDisplay* display = computedValues->ComputedValues()->GetStyleDisplay();
const nsStyleContent* content = computedValues->ComputedValues()->GetStyleContent();
const nsStyleDisplay* display = computedValues->ComputedData()->GetStyleDisplay();
const nsStyleContent* content = computedValues->ComputedData()->GetStyleContent();
// XXXldb What is contentCount for |content: ""|?
if (display->mDisplay == StyleDisplay::None ||
content->ContentCount() == 0) {

View File

@ -192,7 +192,7 @@ public:
StyleRuleInclusion aRules =
StyleRuleInclusion::All);
// Similar to ResolveTransientStyle() but returns ServoComputedValues.
// Similar to ResolveTransientStyle() but doesn't update the context state
// Unlike ResolveServoStyle() this function calls PreTraverseSync().
already_AddRefed<ServoStyleContext>
ResolveTransientServoStyle(dom::Element* aElement,

View File

@ -176,7 +176,7 @@ class ServoStyleContext;
struct ServoVisitedStyle {
// This is actually a strong reference
// but ServoComputedValues' destructor is
// but ServoComputedData's destructor is
// managed by the Rust code so we just use a
// regular pointer
ServoStyleContext* mPtr;
@ -201,14 +201,14 @@ struct ServoComputedValueFlags {
} // namespace mozilla
class ServoComputedValues;
class ServoComputedData;
struct ServoComputedValuesForgotten
struct ServoComputedDataForgotten
{
// Make sure you manually mem::forget the backing ServoComputedValues
// Make sure you manually mem::forget the backing ServoComputedData
// after calling this
explicit ServoComputedValuesForgotten(const ServoComputedValues* aValue) : mPtr(aValue) {}
const ServoComputedValues* mPtr;
explicit ServoComputedDataForgotten(const ServoComputedData* aValue) : mPtr(aValue) {}
const ServoComputedData* mPtr;
};
/**
@ -216,13 +216,13 @@ struct ServoComputedValuesForgotten
* so we define this type on the C++ side and use the bindgenned version
* on the Rust side.
*/
class ServoComputedValues
class ServoComputedData
{
friend class mozilla::ServoStyleContext;
public:
// Constructs via memcpy. Will not move out of aValue.
explicit ServoComputedValues(const ServoComputedValuesForgotten aValue);
explicit ServoComputedData(const ServoComputedDataForgotten aValue);
#define STYLE_STRUCT(name_, checkdata_cb_) \
mozilla::ServoRawOffsetArc<mozilla::Gecko##name_> name_; \
@ -261,10 +261,10 @@ private:
// We remove the move ctor/assignment operator as well, because
// moves in C++ don't prevent destructors from being called,
// which will lead to double frees.
ServoComputedValues& operator=(const ServoComputedValues&) = delete;
ServoComputedValues(const ServoComputedValues&) = delete;
ServoComputedValues&& operator=(const ServoComputedValues&&) = delete;
ServoComputedValues(const ServoComputedValues&&) = delete;
ServoComputedData& operator=(const ServoComputedData&) = delete;
ServoComputedData(const ServoComputedData&) = delete;
ServoComputedData&& operator=(const ServoComputedData&&) = delete;
ServoComputedData(const ServoComputedData&&) = delete;
};
#endif // mozilla_ServoTypes_h

View File

@ -1035,7 +1035,7 @@ nsAnimationManager::UpdateAnimations(
ServoCSSAnimationBuilder builder(aStyleContext);
const nsStyleDisplay *disp =
aStyleContext->ComputedValues()->GetStyleDisplay();
aStyleContext->ComputedData()->GetStyleDisplay();
DoUpdateAnimations(target, *disp, builder);
}

View File

@ -17,7 +17,7 @@
class nsIGlobalObject;
class nsStyleContext;
class ServoComputedValues;
class ServoComputedData;
struct nsStyleDisplay;
namespace mozilla {

View File

@ -354,7 +354,7 @@ nsComputedDOMStyle::GetLength(uint32_t* aLength)
UpdateCurrentStyleSources(false);
if (mStyleContext) {
length += mStyleContext->IsServo()
? Servo_GetCustomPropertiesCount(mStyleContext->ComputedValues())
? Servo_GetCustomPropertiesCount(mStyleContext->AsServo())
: StyleVariables()->mVariables.Count();
}
@ -1094,7 +1094,7 @@ nsComputedDOMStyle::IndexedGetter(uint32_t aIndex,
: StyleVariables();
const uint32_t count = isServo
? Servo_GetCustomPropertiesCount(mStyleContext->ComputedValues())
? Servo_GetCustomPropertiesCount(mStyleContext->AsServo())
: variables->mVariables.Count();
const uint32_t index = aIndex - length;
@ -1102,8 +1102,7 @@ nsComputedDOMStyle::IndexedGetter(uint32_t aIndex,
aFound = true;
nsString varName;
if (isServo) {
Servo_GetCustomPropertyNameAt(mStyleContext->ComputedValues(),
index, &varName);
Servo_GetCustomPropertyNameAt(mStyleContext->AsServo(), index, &varName);
} else {
variables->mVariables.GetVariableAt(index, varName);
}
@ -6949,8 +6948,7 @@ nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
const nsAString& name = Substring(aPropertyName,
CSS_CUSTOM_NAME_PREFIX_LENGTH);
bool present = mStyleContext->IsServo()
? Servo_GetCustomPropertyValue(mStyleContext->ComputedValues(),
&name, &variableValue)
? Servo_GetCustomPropertyValue(mStyleContext->AsServo(), &name, &variableValue)
: StyleVariables()->mVariables.Get(name, variableValue);
if (!present) {
return nullptr;

View File

@ -116,7 +116,7 @@ nsStyleContext::FinishConstruction()
#ifdef DEBUG
if (auto servo = GetAsServo()) {
MOZ_ASSERT(servo->ComputedValues());
MOZ_ASSERT(servo->ComputedData());
} else {
MOZ_ASSERT(RuleNode());
}
@ -234,8 +234,8 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
}
} else {
if (Servo_ComputedValues_EqualCustomProperties(
ComputedValues(),
aNewContext->ComputedValues())) {
AsServo()->ComputedData(),
aNewContext->ComputedData())) {
*aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
}
}
@ -257,7 +257,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
(IsGecko() \
? PeekStyle##struct_() \
: ((aRelevantStructs & NS_STYLE_INHERIT_BIT(struct_)) \
? AsServo()->ComputedValues()->GetStyle##struct_() \
? AsServo()->ComputedData()->GetStyle##struct_() \
: nullptr))
#define EXPAND(...) __VA_ARGS__
@ -270,7 +270,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
} else if (checkUnrequestedServoStructs) { \
this##struct_ = \
AsServo()->ComputedValues()->GetStyle##struct_(); \
AsServo()->ComputedData()->GetStyle##struct_(); \
unrequestedStruct = true; \
} else { \
unrequestedStruct = false; \
@ -487,7 +487,7 @@ void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
}
if (IsServo()) {
fprintf_stderr(out, "%s{ServoComputedValues}\n", str.get());
fprintf_stderr(out, "%s{ServoComputedData}\n", str.get());
} else if (nsRuleNode* ruleNode = AsGecko()->RuleNode()) {
fprintf_stderr(out, "%s{\n", str.get());
str.Truncate();

View File

@ -212,7 +212,7 @@ public:
}
inline nsRuleNode* RuleNode();
inline const ServoComputedValues* ComputedValues();
inline const ServoComputedData* ComputedData();
void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
@ -343,8 +343,6 @@ protected:
void SetStyleBits();
inline const void* StyleStructFromServoComputedValues(nsStyleStructID aSID);
// Helper functions for GetStyle* and PeekStyle*
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
template<bool aComputeData> \

View File

@ -31,11 +31,11 @@ nsStyleContext::RuleNode()
return AsGecko()->RuleNode();
}
const ServoComputedValues*
nsStyleContext::ComputedValues()
const ServoComputedData*
nsStyleContext::ComputedData()
{
MOZ_RELEASE_ASSERT(IsServo());
return AsServo()->ComputedValues();
return AsServo()->ComputedData();
}
void
@ -58,7 +58,7 @@ nsStyleContext::Style##name_() { \
const nsStyle##name_ * \
nsStyleContext::ThreadsafeStyle##name_() { \
if (mozilla::ServoStyleSet::IsInServoTraversal()) { \
return AsServo()->ComputedValues()->GetStyle##name_(); \
return AsServo()->ComputedData()->GetStyle##name_(); \
} \
return Style##name_(); \
} \
@ -131,7 +131,7 @@ const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
} \
\
const nsStyle##name_* data = \
servo->ComputedValues()->GetStyle##name_(); \
servo->ComputedData()->GetStyle##name_(); \
/* perform any remaining main thread work on the struct */ \
if (needToCompute) { \
MOZ_ASSERT(NS_IsMainThread()); \
@ -164,7 +164,7 @@ const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
return nullptr; \
} \
const nsStyle##name_* data = \
servo->ComputedValues()->GetStyle##name_(); \
servo->ComputedData()->GetStyle##name_(); \
/* perform any remaining main thread work on the struct */ \
if (needToCompute) { \
const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext()); \
@ -216,20 +216,4 @@ nsStyleContext::StartBackgroundImageLoads()
StyleBackground();
}
const void*
nsStyleContext::StyleStructFromServoComputedValues(nsStyleStructID aSID)
{
switch (aSID) {
#define STYLE_STRUCT(name_, checkdata_cb_) \
case eStyleStruct_##name_: \
return ComputedValues()->GetStyle##name_();
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
default:
MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value");
return nullptr;
}
}
#endif // nsStyleContextInlines_h

View File

@ -635,7 +635,7 @@ nsTransitionManager::UpdateTransitions(
CSSTransitionCollection* collection =
CSSTransitionCollection::GetAnimationCollection(aElement, aPseudoType);
const nsStyleDisplay *disp =
aNewStyle->ComputedValues()->GetStyleDisplay();
aNewStyle->ComputedData()->GetStyleDisplay();
return DoUpdateTransitions(disp,
aElement, aPseudoType,
collection,

View File

@ -334,3 +334,6 @@ skip-if = toolkit == 'android' # TIMED_OUT for android
skip-if = toolkit == 'android' # TIMED_OUT for android
[test_webkit_device_pixel_ratio.html]
[test_webkit_flex_display.html]
[test_first_letter_restrictions.html]
[test_first_line_restrictions.html]
[test_placeholder_restrictions.html]

File diff suppressed because it is too large Load Diff

View File

@ -43,10 +43,6 @@ to mochitest command.
* SVG-in-OpenType values not supported servo/servo#15211 bug 1338764
* test_value_storage.html `context-` [7]
* test_bug798843_pref.html [3]
* Incorrect parsing
* different parsing bug 1364260
* test_supports_rules.html [1]
* test_condition_text.html [1]
* Incorrect serialization
* place-{content,items,self} shorthands bug 1363971
* test_align_shorthand_serialization.html [6]

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