Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE

This commit is contained in:
Ciure Andrei 2019-04-11 19:13:48 +03:00
Родитель bc3c25dece e70373f76a
Коммит 6d8c05133f
130 изменённых файлов: 2723 добавлений и 1469 удалений

Двоичные данные
browser/base/content/aboutRobots-widget-left.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Просмотреть файл

@ -1,26 +1,3 @@
#errorPageContainer {
background-image: none;
}
#errorPageContainer:before {
content: url('chrome://browser/content/aboutRobots-icon.png');
position: absolute;
}
body[dir=rtl] #icon,
body[dir=rtl] #errorPageContainer:before {
transform: scaleX(-1);
}
#widget1 {
position: absolute;
bottom: -12px;
left: -10px;
}
#widget2 {
position: absolute;
bottom: -12px;
right: -10px;
transform: scaleX(-1);
.title {
background-image: url("chrome://browser/content/aboutRobots-icon.png");
}

Просмотреть файл

@ -1,23 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
%htmlDTD;
]>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src chrome:" />
<title data-l10n-id="page-title"></title>
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />
<link rel="stylesheet" href="chrome://global/skin/in-content/info-pages.css" media="all"/>
<link rel="icon" type="image/png" id="favicon" href="chrome://browser/content/robot.ico"/>
<link rel="stylesheet" href="chrome://browser/content/aboutRobots.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/content/aboutRobots.css"/>
<linkset>
<link rel="localization" href="browser/aboutRobots.ftl"/>
</linkset>
@ -26,23 +18,23 @@
<body>
<!-- PAGE CONTAINER (for styling purposes only) -->
<div id="errorPageContainer">
<div class="container">
<!-- Error Title -->
<div id="errorTitle">
<h1 id="errorTitleText" data-l10n-id="error-title-text"></h1>
<div class="title">
<h1 class="title-text" data-l10n-id="error-title-text"></h1>
</div>
<!-- LONG CONTENT (the section most likely to require scrolling) -->
<div id="errorLongContent">
<div class="description">
<!-- Short Description -->
<div id="errorShortDesc">
<div>
<p id="errorShortDescText" data-l10n-id="error-short-desc-text"></p>
</div>
<!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
<div id="errorLongDesc">
<!-- Long Description -->
<div>
<ul>
<li data-l10n-id="error-long-desc1"></li>
<li data-l10n-id="error-long-desc2"></li>
@ -52,19 +44,18 @@
</div>
<!-- Short Description -->
<div id="errorTrailerDesc">
<p id="errorTrailerDescText" data-l10n-id="error-trailer-desc-text"></p>
<div>
<small data-l10n-id="error-trailer-desc-text"></small>
</div>
</div>
<!-- Button -->
<button id="errorTryAgain"
data-l10n-id="error-try-again"
data-l10n-attrs="label2"></button>
<img id="widget1" src="chrome://browser/content/aboutRobots-widget-left.png"/>
<img id="widget2" src="chrome://browser/content/aboutRobots-widget-left.png"/>
<div class="button-container">
<button id="errorTryAgain"
data-l10n-id="error-try-again"
data-l10n-attrs="label2"></button>
</div>
</div>
</body>
<script type="application/javascript" src="chrome://browser/content/aboutRobots.js"/>

Просмотреть файл

@ -22,7 +22,6 @@ browser.jar:
content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml)
content/browser/aboutNetError.js (content/aboutNetError.js)
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)

Просмотреть файл

@ -23,7 +23,6 @@ browser.jar:
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
skin/classic/browser/notification-icons/geo-detailed.svg (notification-icons/geo-detailed.svg)
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
* skin/classic/browser/places/sidebar.css (places/sidebar.css)
skin/classic/browser/places/organizer.css (places/organizer.css)

Двоичные данные
browser/themes/linux/places/allBookmarks.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 602 B

Просмотреть файл

@ -21,10 +21,8 @@ browser.jar:
skin/classic/browser/monitor-border.png
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
* skin/classic/browser/places/sidebar.css (places/sidebar.css)
skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/toolbar.png (places/toolbar.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png)

Двоичные данные
browser/themes/osx/places/allBookmarks.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 600 B

Просмотреть файл

@ -70,7 +70,6 @@
}
#placesToolbar > toolbarbutton {
list-style-image: url("chrome://browser/skin/places/toolbar.png");
margin: 4px 4px 5px;
padding: 0;
height: 22px;
@ -78,6 +77,9 @@
}
#placesToolbar > toolbarbutton > .toolbarbutton-icon {
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
fill-opacity: 0.8;
margin: 1px 4px;
}
@ -88,7 +90,6 @@
#placesToolbar > toolbarbutton[type="menu"] > .toolbarbutton-menu-dropmarker {
list-style-image: url(chrome://global/skin/icons/arrow-dropdown-12.svg);
padding: 0;
margin-top: 1px;
margin-inline-end: 2px;
}
@ -109,41 +110,45 @@
}
/* back and forward button */
#back-button:-moz-locale-dir(ltr),
#forward-button:-moz-locale-dir(rtl) {
-moz-image-region: rect(0px, 16px, 16px, 0px);
margin-right: 0;
#back-button,
#forward-button {
list-style-image: url("chrome://browser/skin/arrow-left.svg");
}
#forward-button:-moz-locale-dir(ltr),
#back-button:-moz-locale-dir(rtl) {
-moz-image-region: rect(0px, 32px, 16px, 16px);
margin-left: 0;
#back-button {
margin-inline-end: 0 !important; /* override margin from #placesToolbar > toolbarbutton */
}
#forward-button {
margin-inline-start: 0 !important; /* override margin from #placesToolbar > toolbarbutton */
}
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
#forward-button:-moz-locale-dir(ltr) > .toolbarbutton-icon {
transform: scaleX(-1);
}
#back-button > .toolbarbutton-icon {
margin-inline-start: 3px !important;
margin-inline-end: 2px !important;
margin-inline: 3px 2px !important;
}
#forward-button > .toolbarbutton-icon {
margin-inline-start: 2px !important;
margin-inline-end: 3px !important;
margin-inline: 2px 3px !important;
}
/* organize button */
#organizeButton {
-moz-image-region: rect(0px, 48px, 16px, 32px);
list-style-image: url("chrome://browser/skin/settings.svg");
}
/* view button */
#viewMenu {
-moz-image-region: rect(0px, 64px, 16px, 48px);
list-style-image: url("chrome://browser/skin/sort.svg");
}
/* maintenance button */
#maintenanceButton {
-moz-image-region: rect(0px, 80px, 16px, 64px);
list-style-image: url("chrome://browser/skin/import-export.svg");
}
/* Root View */

Двоичные данные
browser/themes/osx/places/toolbar.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 980 B

Просмотреть файл

@ -6,16 +6,8 @@
preffed on. The bulk of the styling is here in the shared file, but
there are overrides for each platform in their compacttheme.css files. */
:root:-moz-lwtheme {
--toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
--toolbar-non-lwt-textcolor: var(--lwt-text-color);
--toolbar-non-lwt-bgimage: none;
}
:root:-moz-lwtheme-brighttext {
/* !important to override LightweightThemeManager.addBuiltInTheme in
BrowserGlue.jsm */
/* !important to override LightweightThemeConsumer.jsm */
--autocomplete-popup-background: #2A2A2E !important;
--autocomplete-popup-highlight-background: #0060DF;
}

Просмотреть файл

@ -13,15 +13,16 @@
}
#customization-container {
background-color: var(--toolbar-non-lwt-bgcolor);
background-image: var(--toolbar-non-lwt-bgimage);
color: var(--toolbar-non-lwt-textcolor);
text-shadow: none;
background-color: var(--toolbar-bgcolor);
background-image: var(--toolbar-bgimage);
color: var(--toolbar-color);
}
:root[lwtheme-image] #customization-container {
background-color: transparent;
background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-non-lwt-bgcolor) 45px);
color: var(--toolbar-non-lwt-textcolor);
text-shadow: none;
}
#customization-palette {

Просмотреть файл

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
<path d="M8.71 3.29l-3-3a1 1 0 0 0-.33-.21 1 1 0 0 0-.76 0 1 1 0 0 0-.33.21l-3 3a1 1 0 0 0 1.42 1.42L4 3.41V9a1 1 0 0 0 2 0V3.41l1.29 1.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42zm6 8a1 1 0 0 0-1.42 0L12 12.59V7a1 1 0 0 0-2 0v5.59l-1.29-1.3a1 1 0 1 0-1.42 1.42l3 3a1 1 0 0 0 .33.21.94.94 0 0 0 .76 0 1 1 0 0 0 .33-.21l3-3a1 1 0 0 0 0-1.42z"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 697 B

Просмотреть файл

@ -0,0 +1,6 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="context-fill" fill-opacity="context-fill-opacity">
<path d="M11 7H5a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2zm-3 4H5a1 1 0 0 0 0 2h3a1 1 0 0 0 0-2zm6-8H5a1 1 0 0 0 0 2h9a1 1 0 0 0 0-2zM2 3a1 1 0 1 0 1 1 1 1 0 0 0-1-1zm0 4a1 1 0 1 0 1 1 1 1 0 0 0-1-1zm0 4a1 1 0 1 0 1 1 1 1 0 0 0-1-1z"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 586 B

Просмотреть файл

@ -132,7 +132,7 @@
skin/classic/browser/fxa/fxa-spinner.svg (../shared/fxa/fxa-spinner.svg)
skin/classic/browser/fxa/sync-illustration.svg (../shared/fxa/sync-illustration.svg)
skin/classic/browser/fxa/sync-illustration-issue.svg (../shared/fxa/sync-illustration-issue.svg)
skin/classic/browser/fxa/avatar.svg (../shared/fxa/avatar.svg)
skin/classic/browser/fxa/avatar-confirm.svg (../shared/fxa/avatar-confirm.svg)
skin/classic/browser/fxa/avatar-empty.svg (../shared/fxa/avatar-empty.svg)
@ -150,6 +150,7 @@
skin/classic/browser/bookmark-animation.svg (../shared/icons/bookmark-animation.svg)
skin/classic/browser/bookmark-hollow.svg (../shared/icons/bookmark-hollow.svg)
skin/classic/browser/bookmark-star-on-tray.svg (../shared/icons/bookmark-star-on-tray.svg)
skin/classic/browser/bookmarks-toolbar.svg (../shared/icons/bookmarks-toolbar.svg)
skin/classic/browser/characterEncoding.svg (../shared/icons/characterEncoding.svg)
skin/classic/browser/chevron.svg (../shared/icons/chevron.svg)
skin/classic/browser/chevron-animation.svg (../shared/icons/chevron-animation.svg)
@ -169,6 +170,9 @@
skin/classic/browser/fullscreen-exit.svg (../shared/icons/fullscreen-exit.svg)
skin/classic/browser/history.svg (../shared/icons/history.svg)
skin/classic/browser/home.svg (../shared/icons/home.svg)
#ifndef XP_LINUX
skin/classic/browser/import-export.svg (../shared/icons/import-export.svg)
#endif
skin/classic/browser/library.svg (../shared/icons/library.svg)
skin/classic/browser/library-bookmark-animation.svg (../shared/icons/library-bookmark-animation.svg)
skin/classic/browser/library-pocket-animation.svg (../shared/icons/library-pocket-animation.svg)
@ -197,13 +201,15 @@
skin/classic/browser/settings.svg (../shared/icons/settings.svg)
skin/classic/browser/sidebars.svg (../shared/icons/sidebars.svg)
skin/classic/browser/sidebars-right.svg (../shared/icons/sidebars-right.svg)
#ifndef XP_LINUX
skin/classic/browser/sort.svg (../shared/icons/sort.svg)
#endif
skin/classic/browser/stop.svg (../shared/icons/stop.svg)
skin/classic/browser/stop-to-reload.svg (../shared/icons/stop-to-reload.svg)
skin/classic/browser/sync.svg (../shared/icons/sync.svg)
skin/classic/browser/tab.svg (../shared/icons/tab.svg)
skin/classic/browser/undo.svg (../shared/icons/undo.svg)
skin/classic/browser/unpin-tab.svg (../shared/icons/unpin-tab.svg)
skin/classic/browser/bookmarks-toolbar.svg (../shared/icons/bookmarks-toolbar.svg)
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
skin/classic/browser/window.svg (../shared/icons/window.svg)
skin/classic/browser/zoom-in.svg (../shared/icons/zoom-in.svg)

Просмотреть файл

@ -127,11 +127,11 @@
list-style-image: url("chrome://browser/skin/bookmarks-toolbar.svg");
}
#appMenu-library-bookmarks-button,
#panelMenuBookmarkThisPage {
list-style-image: url("chrome://browser/skin/bookmark-hollow.svg");
}
#appMenu-library-bookmarks-button,
#panelMenuBookmarkThisPage[starred] {
list-style-image: url("chrome://browser/skin/bookmark.svg");
}

Просмотреть файл

@ -45,7 +45,7 @@ treechildren::-moz-tree-image(query) {
}
treechildren::-moz-tree-image(query, OrganizerQuery_allbms_____v) {
list-style-image: url("chrome://browser/skin/places/allBookmarks.png");
list-style-image: url("chrome://browser/skin/bookmark.svg");
}
treechildren::-moz-tree-image(query, OrganizerQuery_downloads__v) {

Просмотреть файл

@ -27,8 +27,6 @@ browser.jar:
* skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/editBookmark.css (places/editBookmark.css)
skin/classic/browser/places/libraryToolbar.png (places/libraryToolbar.png)
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png)
skin/classic/browser/preferences/application.png (preferences/application.png)
skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png)

Двоичные данные
browser/themes/windows/places/allBookmarks.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 545 B

Двоичные данные
browser/themes/windows/places/libraryToolbar.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -8,15 +8,14 @@
padding-inline-end: 6px;
}
#placesToolbar > toolbarbutton[disabled] > .toolbarbutton-icon {
opacity: .4;
#placesToolbar > toolbarbutton > .toolbarbutton-icon {
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
fill-opacity: 0.8;
}
#back-button > .toolbarbutton-icon,
#forward-button > .toolbarbutton-icon {
-moz-context-properties: fill;
fill: currentcolor;
opacity: 0.65;
#placesToolbar > toolbarbutton[disabled] > .toolbarbutton-icon {
opacity: .4;
}
#back-button {
@ -75,38 +74,19 @@
background-position: left center;
}
/* organize, view and maintenance buttons icons */
#organizeButton,
#viewMenu,
#maintenanceButton {
list-style-image: url("chrome://browser/skin/places/libraryToolbar.png");
}
/* organize button */
#organizeButton {
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
#organizeButton:hover,
#organizeButton[open="true"] {
-moz-image-region: rect(16px, 16px, 32px, 0px);
list-style-image: url("chrome://browser/skin/settings.svg");
}
/* view button */
#viewMenu {
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
#viewMenu:hover,
#viewMenu[open="true"] {
-moz-image-region: rect(16px, 32px, 32px, 16px);
list-style-image: url("chrome://browser/skin/sort.svg");
}
/* maintenance button */
#maintenanceButton {
-moz-image-region: rect(0px, 48px, 16px, 32px);
}
#maintenanceButton:hover,
#maintenanceButton[open="true"] {
-moz-image-region: rect(16px, 48px, 32px, 32px);
list-style-image: url("chrome://browser/skin/import-export.svg");
}
/* Info box */

Просмотреть файл

@ -133,8 +133,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"scroll-snap-destination",
"scroll-snap-points-x",
"scroll-snap-points-y",
"scroll-snap-type-x",
"scroll-snap-type-y",
"scroll-snap-type",
"shape-rendering",
"-moz-stack-sizing",
"scrollbar-width",

Просмотреть файл

@ -3081,8 +3081,7 @@ exports.CSS_PROPERTIES = {
"offset-path",
"scroll-behavior",
"scroll-snap-align",
"scroll-snap-type-x",
"scroll-snap-type-y",
"scroll-snap-type",
"overscroll-behavior-x",
"overscroll-behavior-y",
"isolation",
@ -8995,120 +8994,348 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"scroll-snap-coordinate": {
"scroll-margin": {
"isInherited": false,
"subproperties": [
"scroll-snap-coordinate"
"scroll-margin-top",
"scroll-margin-right",
"scroll-margin-bottom",
"scroll-margin-left"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-block": {
"isInherited": false,
"subproperties": [
"scroll-margin-block-start",
"scroll-margin-block-end"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-block-end": {
"isInherited": false,
"subproperties": [
"scroll-margin-block-end"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-block-start": {
"isInherited": false,
"subproperties": [
"scroll-margin-block-start"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-bottom": {
"isInherited": false,
"subproperties": [
"scroll-margin-bottom"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-inline": {
"isInherited": false,
"subproperties": [
"scroll-margin-inline-start",
"scroll-margin-inline-end"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-inline-end": {
"isInherited": false,
"subproperties": [
"scroll-margin-inline-end"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-inline-start": {
"isInherited": false,
"subproperties": [
"scroll-margin-inline-start"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-left": {
"isInherited": false,
"subproperties": [
"scroll-margin-left"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-right": {
"isInherited": false,
"subproperties": [
"scroll-margin-right"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-margin-top": {
"isInherited": false,
"subproperties": [
"scroll-margin-top"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding": {
"isInherited": false,
"subproperties": [
"scroll-padding-top",
"scroll-padding-right",
"scroll-padding-bottom",
"scroll-padding-left"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-block": {
"isInherited": false,
"subproperties": [
"scroll-padding-block-start",
"scroll-padding-block-end"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-block-end": {
"isInherited": false,
"subproperties": [
"scroll-padding-block-end"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-block-start": {
"isInherited": false,
"subproperties": [
"scroll-padding-block-start"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-bottom": {
"isInherited": false,
"subproperties": [
"scroll-padding-bottom"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-inline": {
"isInherited": false,
"subproperties": [
"scroll-padding-inline-start",
"scroll-padding-inline-end"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-inline-end": {
"isInherited": false,
"subproperties": [
"scroll-padding-inline-end"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-inline-start": {
"isInherited": false,
"subproperties": [
"scroll-padding-inline-start"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-left": {
"isInherited": false,
"subproperties": [
"scroll-padding-left"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-right": {
"isInherited": false,
"subproperties": [
"scroll-padding-right"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-padding-top": {
"isInherited": false,
"subproperties": [
"scroll-padding-top"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scroll-snap-align": {
"isInherited": false,
"subproperties": [
"scroll-snap-align"
],
"supports": [],
"values": [
"bottom",
"center",
"inherit",
"initial",
"left",
"none",
"revert",
"right",
"top",
"unset"
]
},
"scroll-snap-destination": {
"isInherited": false,
"subproperties": [
"scroll-snap-destination"
],
"supports": [],
"values": [
"bottom",
"center",
"inherit",
"initial",
"left",
"revert",
"right",
"top",
"unset"
]
},
"scroll-snap-points-x": {
"isInherited": false,
"subproperties": [
"scroll-snap-points-x"
],
"supports": [],
"values": [
"end",
"inherit",
"initial",
"none",
"repeat",
"revert",
"unset"
]
},
"scroll-snap-points-y": {
"isInherited": false,
"subproperties": [
"scroll-snap-points-y"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"repeat",
"revert",
"start",
"unset"
]
},
"scroll-snap-type": {
"isInherited": false,
"subproperties": [
"scroll-snap-type-x",
"scroll-snap-type-y"
"scroll-snap-type"
],
"supports": [],
"values": [
"block",
"both",
"inherit",
"initial",
"inline",
"mandatory",
"none",
"proximity",
"revert",
"unset"
]
},
"scroll-snap-type-x": {
"isInherited": false,
"subproperties": [
"scroll-snap-type-x"
],
"supports": [],
"values": [
"inherit",
"initial",
"mandatory",
"none",
"proximity",
"revert",
"unset"
]
},
"scroll-snap-type-y": {
"isInherited": false,
"subproperties": [
"scroll-snap-type-y"
],
"supports": [],
"values": [
"inherit",
"initial",
"mandatory",
"none",
"proximity",
"revert",
"unset"
"unset",
"x",
"y"
]
},
"scrollbar-color": {
@ -10306,14 +10533,6 @@ exports.PREFERENCES = [
"overscroll-behavior-y",
"layout.css.overscroll-behavior.enabled"
],
[
"scroll-snap-type-x",
"layout.css.scroll-snap.enabled"
],
[
"scroll-snap-type-y",
"layout.css.scroll-snap.enabled"
],
[
"font-variation-settings",
"layout.css.font-variations.enabled"
@ -10438,10 +10657,6 @@ exports.PREFERENCES = [
"overflow-clip-box",
"layout.css.overflow-clip-box.enabled"
],
[
"scroll-snap-type",
"layout.css.scroll-snap.enabled"
],
[
"overscroll-behavior",
"layout.css.overscroll-behavior.enabled"

Просмотреть файл

@ -346,7 +346,7 @@ void Element::Focus(mozilla::ErrorResult& aError) {
if (fm->CanSkipFocus(this)) {
fm->NeedsFlushBeforeEventHandling(this);
} else {
aError = fm->SetFocus(this, 0);
aError = fm->SetFocus(this, nsIFocusManager::FLAG_BYELEMENTFOCUS);
}
}
}
@ -778,6 +778,9 @@ void Element::ScrollIntoView(const ScrollIntoViewOptions& aOptions) {
} else if (aOptions.mBehavior == ScrollBehavior::Auto) {
flags |= nsIPresShell::SCROLL_SMOOTH_AUTO;
}
if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) {
flags |= nsIPresShell::SCROLL_SNAP;
}
presShell->ScrollContentIntoView(
this, nsIPresShell::ScrollAxis(vpercent, nsIPresShell::SCROLL_ALWAYS),

Просмотреть файл

@ -1879,7 +1879,8 @@ nsresult Selection::DoAutoScroll(nsIFrame* aFrame, nsPoint aPoint) {
while (true) {
didScroll = presShell->ScrollFrameRectIntoView(
aFrame, nsRect(aPoint, nsSize(0, 0)), nsIPresShell::ScrollAxis(),
nsIPresShell::ScrollAxis(), 0);
nsIPresShell::ScrollAxis(),
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING);
if (!weakFrame || !weakRootFrame) {
return NS_OK;
}
@ -3089,7 +3090,7 @@ nsresult Selection::ScrollIntoView(SelectionRegion aRegion,
// vertical scrollbar or the scroll range is at least one device pixel)
aVertical.mOnlyIfPerceivedScrollableDirection = true;
uint32_t flags = 0;
uint32_t flags = nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING;
if (aFlags & Selection::SCROLL_FIRST_ANCESTOR_ONLY) {
flags |= nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY;
}

Просмотреть файл

@ -2117,15 +2117,23 @@ void nsFocusManager::FireFocusOrBlurEvent(EventMessage aEventMessage,
void nsFocusManager::ScrollIntoView(nsIPresShell* aPresShell,
nsIContent* aContent, uint32_t aFlags) {
MOZ_ASSERT(!(aFlags & FLAG_BYELEMENTFOCUS) ||
!!(aFlags & FLAG_BYELEMENTFOCUS) == !(aFlags & FLAG_NOSCROLL),
"FLAG_BYELEMENTFOCUS shouldn't involve with FLAG_NOSCROLL");
// if the noscroll flag isn't set, scroll the newly focused element into view
if (!(aFlags & FLAG_NOSCROLL))
if (!(aFlags & FLAG_NOSCROLL)) {
uint32_t scrollFlags = nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
if (!(aFlags & FLAG_BYELEMENTFOCUS)) {
scrollFlags |= nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING;
}
aPresShell->ScrollContentIntoView(
aContent,
nsIPresShell::ScrollAxis(nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::ScrollAxis(nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
scrollFlags);
}
}
void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow) {

Просмотреть файл

@ -1019,7 +1019,8 @@ bool EventStateManager::LookForAccessKeyAndExecute(
} else {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY |
nsIFocusManager::FLAG_BYELEMENTFOCUS);
focusChanged = true;
}
}

Просмотреть файл

@ -56,7 +56,7 @@ void HTMLLabelElement::Focus(ErrorResult& aError) {
if (fm) {
RefPtr<Element> elem = GetLabeledElement();
if (elem) {
fm->SetFocus(elem, 0);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYELEMENTFOCUS);
}
}
}
@ -141,6 +141,7 @@ nsresult HTMLLabelElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
MouseEvent_Binding::MOZ_SOURCE_TOUCH);
fm->SetFocus(content,
nsIFocusManager::FLAG_BYMOVEFOCUS |
nsIFocusManager::FLAG_BYELEMENTFOCUS |
(byMouse ? nsIFocusManager::FLAG_BYMOUSE : 0) |
(byTouch ? nsIFocusManager::FLAG_BYTOUCH : 0));
}

Просмотреть файл

@ -89,7 +89,8 @@ void HTMLLegendElement::Focus(ErrorResult& aError) {
RefPtr<Element> result;
aError = fm->MoveFocus(nullptr, this, nsIFocusManager::MOVEFOCUS_FORWARD,
nsIFocusManager::FLAG_NOPARENTFRAME,
nsIFocusManager::FLAG_NOPARENTFRAME |
nsIFocusManager::FLAG_BYELEMENTFOCUS,
getter_AddRefs(result));
}

Просмотреть файл

@ -2332,7 +2332,8 @@ bool nsGenericHTMLElement::PerformAccesskey(bool aKeyCausesActivation,
bool focused = true;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetFocus(this, nsIFocusManager::FLAG_BYKEY);
fm->SetFocus(this, nsIFocusManager::FLAG_BYKEY |
nsIFocusManager::FLAG_BYELEMENTFOCUS);
// Return true if the element became the current focus within its window.
nsPIDOMWindowOuter* window = OwnerDoc()->GetWindow();

Просмотреть файл

@ -205,6 +205,16 @@ interface nsIFocusManager : nsISupports
*/
const unsigned long FLAG_BYTOUCH = 0x200000;
/**
* Focus is changing due to a Element.focus() call.
* This is used to distinguish the Element.focus() call from other focus
* functionalities since we need to factor scroll-margin and scroll-padding
* values into the position where we scroll to the element by the
* Element.focus() call.
* NOTE: This flag shouldn't be specified with FLAG_NOSCROLL.
*/
const unsigned long FLAG_BYELEMENTFOCUS = 0x400000;
// these constants are used with the aType argument to MoveFocus
/** move focus forward one element, used when pressing TAB */

Просмотреть файл

@ -147,6 +147,14 @@ size_t sAudioIPCStackSize;
StaticAutoPtr<char> sBrandName;
StaticAutoPtr<char> sCubebBackendName;
StaticAutoPtr<char> sCubebOutputDeviceName;
#ifdef MOZ_WIDGET_ANDROID
// Counts the number of time a request for switching to global "communication
// mode" has been received. If this is > 0, global communication mode is to be
// enabled. If it is 0, the global communication mode is to be disabled.
// This allows to correctly track the global behaviour to adopt accross
// asynchronous GraphDriver changes, on Android.
int sInCommunicationCount = 0;
#endif
const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
@ -309,6 +317,24 @@ void ForceSetCubebContext(cubeb* aCubebContext) {
sCubebState = CubebState::Initialized;
}
void SetInCommunication(bool aInCommunication) {
#ifdef MOZ_WIDGET_ANDROID
StaticMutexAutoLock lock(sMutex);
if (aInCommunication) {
sInCommunicationCount++;
} else {
MOZ_ASSERT(sInCommunicationCount > 0);
sInCommunicationCount--;
}
if (sInCommunicationCount == 1) {
java::GeckoAppShell::SetCommunicationAudioModeOn(true);
} else if (sInCommunicationCount == 0) {
java::GeckoAppShell::SetCommunicationAudioModeOn(false);
}
#endif
}
bool InitPreferredSampleRate() {
StaticMutexAutoLock lock(sMutex);
if (sPreferredSampleRate != 0) {

Просмотреть файл

@ -13,6 +13,8 @@
class AudioDeviceInfo;
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(cubeb_stream_prefs)
namespace mozilla {
namespace CubebUtils {
@ -45,6 +47,10 @@ bool CubebLatencyPrefSet();
void GetCurrentBackend(nsAString& aBackend);
cubeb_stream_prefs GetDefaultStreamPrefs();
char* GetForcedOutputDevice();
// No-op on all platforms but Android, where it tells the device's AudioManager
// to switch to "communication mode", which might change audio routing,
// bluetooth communication type, etc.
void SetInCommunication(bool aInCommunication);
# ifdef MOZ_WIDGET_ANDROID
uint32_t AndroidGetAudioOutputSampleRate();

Просмотреть файл

@ -469,7 +469,8 @@ StreamAndPromiseForOperation::StreamAndPromiseForOperation(
mFlags(aFlags) {}
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl,
uint32_t aInputChannelCount)
uint32_t aInputChannelCount,
AudioInputType aAudioInputType)
: GraphDriver(aGraphImpl),
mOutputChannels(0),
mSampleRate(0),
@ -494,6 +495,13 @@ AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl,
audio::AudioNotificationReceiver::Register(this);
}
#endif
if (aAudioInputType == AudioInputType::Voice) {
LOG(LogLevel::Debug, ("VOICE."));
mInputDevicePreference = CUBEB_DEVICE_PREF_VOICE;
CubebUtils::SetInCommunication(true);
} else {
mInputDevicePreference = CUBEB_DEVICE_PREF_ALL;
}
}
AudioCallbackDriver::~AudioCallbackDriver() {
@ -504,6 +512,9 @@ AudioCallbackDriver::~AudioCallbackDriver() {
audio::AudioNotificationReceiver::Unregister(this);
}
#endif
if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
CubebUtils::SetInCommunication(false);
}
}
bool IsMacbookOrMacbookAir() {
@ -589,6 +600,9 @@ bool AudioCallbackDriver::Init() {
output.channels = mOutputChannels;
output.layout = CUBEB_LAYOUT_UNDEFINED;
output.prefs = CubebUtils::GetDefaultStreamPrefs();
if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
output.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE);
}
uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output);

Просмотреть файл

@ -323,6 +323,7 @@ struct StreamAndPromiseForOperation {
};
enum AsyncCubebOperation { INIT, SHUTDOWN };
enum class AudioInputType { Unknown, Voice };
/**
* This is a graph driver that is based on callback functions called by the
@ -354,7 +355,8 @@ class AudioCallbackDriver : public GraphDriver,
public:
/** If aInputChannelCount is zero, then this driver is output-only. */
AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl,
uint32_t aInputChannelCount);
uint32_t aInputChannelCount,
AudioInputType aAudioInputType);
virtual ~AudioCallbackDriver();
void Start() override;
@ -402,6 +404,13 @@ class AudioCallbackDriver : public GraphDriver,
uint32_t InputChannelCount() { return mInputChannelCount; }
AudioInputType InputDevicePreference() {
if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
return AudioInputType::Voice;
}
return AudioInputType::Unknown;
}
/* Enqueue a promise that is going to be resolved when a specific operation
* occurs on the cubeb stream. */
void EnqueueStreamAndPromiseForOperation(
@ -503,12 +512,12 @@ class AudioCallbackDriver : public GraphDriver,
const RefPtr<SharedThreadPool> mInitShutdownThread;
/* This must be accessed with the graph monitor held. */
AutoTArray<StreamAndPromiseForOperation, 1> mPromisesForOperation;
cubeb_device_pref mInputDevicePreference;
/* This is used to signal adding the mixer callback on first run
* of audio callback. This is atomic because it is touched from different
* threads, the audio callback thread and the state change thread. However,
* the order of the threads does not allow concurent access. */
Atomic<bool> mAddedMixer;
/* Contains the id of the audio thread for as long as the callback
* is taking place, after that it is reseted to an invalid value. */
std::atomic<std::thread::id> mAudioThreadId;

Просмотреть файл

@ -368,8 +368,8 @@ void MediaStreamGraphImpl::UpdateStreamOrder() {
!CurrentDriver()->AsAudioCallbackDriver() && !switching) {
MonitorAutoLock mon(mMonitor);
if (LifecycleStateRef() == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver =
new AudioCallbackDriver(this, AudioInputChannelCount());
AudioCallbackDriver* driver = new AudioCallbackDriver(
this, AudioInputChannelCount(), AudioInputDevicePreference());
CurrentDriver()->SwitchAtNextIteration(driver);
}
}
@ -612,8 +612,8 @@ void MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream) {
if (!CurrentDriver()->AsAudioCallbackDriver() && !switching) {
MonitorAutoLock mon(mMonitor);
if (LifecycleStateRef() == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver =
new AudioCallbackDriver(this, AudioInputChannelCount());
AudioCallbackDriver* driver = new AudioCallbackDriver(
this, AudioInputChannelCount(), AudioInputDevicePreference());
CurrentDriver()->SwitchAtNextIteration(driver);
}
}
@ -746,8 +746,8 @@ void MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
// Switch Drivers since we're adding input (to input-only or full-duplex)
MonitorAutoLock mon(mMonitor);
if (LifecycleStateRef() == LIFECYCLE_RUNNING) {
AudioCallbackDriver* driver =
new AudioCallbackDriver(this, AudioInputChannelCount());
AudioCallbackDriver* driver = new AudioCallbackDriver(
this, AudioInputChannelCount(), AudioInputDevicePreference());
LOG(LogLevel::Debug,
("%p OpenAudioInput: starting new AudioCallbackDriver(input) %p",
this, driver));
@ -830,7 +830,8 @@ void MediaStreamGraphImpl::CloseAudioInputImpl(
LOG(LogLevel::Debug,
("%p: CloseInput: output present (AudioCallback)", this));
driver = new AudioCallbackDriver(this, AudioInputChannelCount());
driver = new AudioCallbackDriver(this, AudioInputChannelCount(),
AudioInputDevicePreference());
CurrentDriver()->SwitchAtNextIteration(driver);
} else if (CurrentDriver()->AsAudioCallbackDriver()) {
LOG(LogLevel::Debug,
@ -981,6 +982,10 @@ void MediaStreamGraphImpl::ReevaluateInputDevice() {
if (audioCallbackDriver->InputChannelCount() != AudioInputChannelCount()) {
needToSwitch = true;
}
if (audioCallbackDriver->InputDevicePreference() !=
AudioInputDevicePreference()) {
needToSwitch = true;
}
} else {
// We're already in the process of switching to a audio callback driver,
// which will happen at the next iteration.
@ -993,8 +998,8 @@ void MediaStreamGraphImpl::ReevaluateInputDevice() {
needToSwitch = true;
}
if (needToSwitch) {
AudioCallbackDriver* newDriver =
new AudioCallbackDriver(this, AudioInputChannelCount());
AudioCallbackDriver* newDriver = new AudioCallbackDriver(
this, AudioInputChannelCount(), AudioInputDevicePreference());
{
MonitorAutoLock lock(mMonitor);
CurrentDriver()->SwitchAtNextIteration(newDriver);
@ -3153,8 +3158,9 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
mMainThreadGraphTime(0, "MediaStreamGraphImpl::mMainThreadGraphTime") {
if (mRealtime) {
if (aDriverRequested == AUDIO_THREAD_DRIVER) {
// Always start with zero input channels.
mDriver = new AudioCallbackDriver(this, 0);
// Always start with zero input channels, and no particular preferences
// for the input channel.
mDriver = new AudioCallbackDriver(this, 0, AudioInputType::Unknown);
} else {
mDriver = new SystemClockDriver(this);
}
@ -3645,7 +3651,8 @@ void MediaStreamGraphImpl::ApplyAudioContextOperationImpl(
MOZ_ASSERT(nextDriver->AsAudioCallbackDriver());
driver = nextDriver->AsAudioCallbackDriver();
} else {
driver = new AudioCallbackDriver(this, AudioInputChannelCount());
driver = new AudioCallbackDriver(this, AudioInputChannelCount(),
AudioInputDevicePreference());
MonitorAutoLock lock(mMonitor);
CurrentDriver()->SwitchAtNextIteration(driver);
}

Просмотреть файл

@ -122,6 +122,10 @@ class AudioDataListenerInterface {
*/
virtual uint32_t RequestedInputChannelCount(MediaStreamGraphImpl* aGraph) = 0;
/**
* Whether the underlying audio device is used for voice input.
*/
virtual bool IsVoiceInput(MediaStreamGraphImpl* aGraph) const = 0;
/**
* Called when the underlying audio device has changed.
*/

Просмотреть файл

@ -398,6 +398,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
* reevaluated, for example, if the channel count of the input stream should
* be changed. */
void ReevaluateInputDevice();
/* Called on the graph thread when there is new output data for listeners.
* This is the mixed audio output of this MediaStreamGraph. */
void NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
@ -485,6 +486,29 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
return maxInputChannels;
}
AudioInputType AudioInputDevicePreference() {
MOZ_ASSERT(OnGraphThreadOrNotRunning());
if (!mInputDeviceUsers.GetValue(mInputDeviceID)) {
return AudioInputType::Unknown;
}
bool voiceInput = false;
// When/if we decide to support multiple input device per graph, this needs
// loop over them.
nsTArray<RefPtr<AudioDataListener>>* listeners =
mInputDeviceUsers.GetValue(mInputDeviceID);
MOZ_ASSERT(listeners);
// If at least one stream is considered to be voice,
for (const auto& listener : *listeners) {
voiceInput |= listener->IsVoiceInput(this);
}
if (voiceInput) {
return AudioInputType::Voice;
}
return AudioInputType::Unknown;
}
CubebUtils::AudioDeviceID InputDeviceID() { return mInputDeviceID; }
double MediaTimeToSeconds(GraphTime aTime) const {

Просмотреть файл

@ -180,9 +180,14 @@ void MediaEngineWebRTC::EnumerateMicrophoneDevices(
if (!foundPreferredDevice) {
foundPreferredDevice = true;
} else {
// This is possible on windows, there is a default communication
// device, and a default device:
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1542739
#ifndef XP_WIN
MOZ_ASSERT(!foundPreferredDevice,
"Found more than one preferred audio input device"
"while enumerating");
#endif
}
#endif
aDevices->InsertElementAt(0, device);

Просмотреть файл

@ -160,6 +160,12 @@ class AudioInputProcessing : public AudioDataListener {
void NotifyInputData(MediaStreamGraphImpl* aGraph,
const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override;
bool IsVoiceInput(MediaStreamGraphImpl* aGraph) const override {
// If we're passing data directly without AEC or any other process, this
// means that all voice-processing has been disabled intentionaly. In this
// case, consider that the device is not used for voice input.
return !PassThrough(aGraph);
}
void Start();
void Stop();

Просмотреть файл

@ -719,19 +719,24 @@ struct ScrollSnapInfo {
mScrollSnapIntervalX == aOther.mScrollSnapIntervalX &&
mScrollSnapIntervalY == aOther.mScrollSnapIntervalY &&
mScrollSnapDestination == aOther.mScrollSnapDestination &&
mScrollSnapCoordinates == aOther.mScrollSnapCoordinates;
mScrollSnapCoordinates == aOther.mScrollSnapCoordinates &&
mSnapPositionX == aOther.mSnapPositionX &&
mSnapPositionY == aOther.mSnapPositionY &&
mXRangeWiderThanSnapport == aOther.mXRangeWiderThanSnapport &&
mYRangeWiderThanSnapport == aOther.mYRangeWiderThanSnapport &&
mSnapportSize == aOther.mSnapportSize;
}
bool HasScrollSnapping() const {
return mScrollSnapTypeY != mozilla::StyleScrollSnapType::None ||
mScrollSnapTypeX != mozilla::StyleScrollSnapType::None;
return mScrollSnapTypeY != mozilla::StyleScrollSnapStrictness::None ||
mScrollSnapTypeX != mozilla::StyleScrollSnapStrictness::None;
}
// The scroll frame's scroll-snap-type.
mozilla::StyleScrollSnapType mScrollSnapTypeX =
mozilla::StyleScrollSnapType::None;
mozilla::StyleScrollSnapType mScrollSnapTypeY =
mozilla::StyleScrollSnapType::None;
mozilla::StyleScrollSnapStrictness mScrollSnapTypeX =
mozilla::StyleScrollSnapStrictness::None;
mozilla::StyleScrollSnapStrictness mScrollSnapTypeY =
mozilla::StyleScrollSnapStrictness::None;
// The intervals derived from the scroll frame's scroll-snap-points.
Maybe<nscoord> mScrollSnapIntervalX;
@ -744,6 +749,42 @@ struct ScrollSnapInfo {
// The scroll-snap-coordinates of any descendant frames of the scroll frame,
// relative to the origin of the scrolled frame.
nsTArray<nsPoint> mScrollSnapCoordinates;
// The scroll positions corresponding to scroll-snap-align values.
nsTArray<nscoord> mSnapPositionX;
nsTArray<nscoord> mSnapPositionY;
struct ScrollSnapRange {
ScrollSnapRange() = default;
ScrollSnapRange(nscoord aStart, nscoord aEnd)
: mStart(aStart), mEnd(aEnd) {}
nscoord mStart;
nscoord mEnd;
bool operator==(const ScrollSnapRange& aOther) const {
return mStart == aOther.mStart && mEnd == aOther.mEnd;
}
// Returns true if |aPoint| is a valid snap position in this range.
bool IsValid(nscoord aPoint, nscoord aSnapportSize) const {
MOZ_ASSERT(mEnd - mStart > aSnapportSize);
return mStart <= aPoint && aPoint <= mEnd - aSnapportSize;
}
};
// An array of the range that the target element is larger than the snapport
// on the axis.
// Snap positions in this range will be valid snap positions in the case where
// the distance between the closest snap position and the second closest snap
// position is still larger than the snapport size.
// See https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow
//
// Note: This range doesn't contain scroll-margin values.
nsTArray<ScrollSnapRange> mXRangeWiderThanSnapport;
nsTArray<ScrollSnapRange> mYRangeWiderThanSnapport;
// Note: This snapport size has been already deflated by scroll-padding.
nsSize mSnapportSize;
};
// clang-format off

Просмотреть файл

@ -8,6 +8,7 @@
#include "APZTestCommon.h"
#include "gfxPrefs.h"
#include "InputUtils.h"
#include "mozilla/StaticPrefs.h"
class APZCSnappingTester : public APZCTreeManagerTester {};
@ -26,8 +27,13 @@ TEST_F(APZCSnappingTester, Bug1265510) {
SetScrollHandoff(layers[1], root);
ScrollSnapInfo snap;
snap.mScrollSnapTypeY = StyleScrollSnapType::Mandatory;
snap.mScrollSnapIntervalY = Some(100 * AppUnitsPerCSSPixel());
snap.mScrollSnapTypeY = StyleScrollSnapStrictness::Mandatory;
if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) {
snap.mSnapPositionY.AppendElement(0 * AppUnitsPerCSSPixel());
snap.mSnapPositionY.AppendElement(100 * AppUnitsPerCSSPixel());
} else {
snap.mScrollSnapIntervalY = Some(100 * AppUnitsPerCSSPixel());
}
ScrollMetadata metadata = root->GetScrollMetadata(0);
metadata.SetSnapInfo(ScrollSnapInfo(snap));
@ -96,8 +102,14 @@ TEST_F(APZCSnappingTester, Snap_After_Pinch) {
// Set up some basic scroll snapping
ScrollSnapInfo snap;
snap.mScrollSnapTypeY = StyleScrollSnapType::Mandatory;
snap.mScrollSnapIntervalY = Some(100 * AppUnitsPerCSSPixel());
snap.mScrollSnapTypeY = StyleScrollSnapStrictness::Mandatory;
if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) {
snap.mSnapPositionY.AppendElement(0 * AppUnitsPerCSSPixel());
snap.mSnapPositionY.AppendElement(100 * AppUnitsPerCSSPixel());
} else {
snap.mScrollSnapIntervalY = Some(100 * AppUnitsPerCSSPixel());
}
// Save the scroll snap info on the root APZC.
// Also mark the root APZC as "root content", since APZC only allows

Просмотреть файл

@ -29,6 +29,8 @@
#include "mozilla/layers/WebRenderMessageUtils.h"
#include "VsyncSource.h"
#include "mozilla/Move.h"
#include "nsSize.h"
#include "VsyncSource.h"
#include <stdint.h>
@ -87,10 +89,11 @@ struct ParamTraits<mozilla::layers::ScaleMode>
mozilla::layers::kHighestScaleMode> {};
template <>
struct ParamTraits<mozilla::StyleScrollSnapType>
struct ParamTraits<mozilla::StyleScrollSnapStrictness>
: public ContiguousEnumSerializerInclusive<
mozilla::StyleScrollSnapType, mozilla::StyleScrollSnapType::None,
mozilla::StyleScrollSnapType::Proximity> {};
mozilla::StyleScrollSnapStrictness,
mozilla::StyleScrollSnapStrictness::None,
mozilla::StyleScrollSnapStrictness::Proximity> {};
template <>
struct ParamTraits<mozilla::layers::TextureFlags>
@ -292,6 +295,38 @@ struct ParamTraits<mozilla::layers::RepaintRequest>
}
};
template <>
struct ParamTraits<nsSize> {
typedef nsSize paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.width);
WriteParam(aMsg, aParam.height);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->width) &&
ReadParam(aMsg, aIter, &aResult->height);
}
};
template <>
struct ParamTraits<mozilla::layers::ScrollSnapInfo::ScrollSnapRange> {
typedef mozilla::layers::ScrollSnapInfo::ScrollSnapRange paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.mStart);
WriteParam(aMsg, aParam.mEnd);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->mStart) &&
ReadParam(aMsg, aIter, &aResult->mEnd);
}
};
template <>
struct ParamTraits<mozilla::layers::ScrollSnapInfo> {
typedef mozilla::layers::ScrollSnapInfo paramType;
@ -303,6 +338,11 @@ struct ParamTraits<mozilla::layers::ScrollSnapInfo> {
WriteParam(aMsg, aParam.mScrollSnapIntervalY);
WriteParam(aMsg, aParam.mScrollSnapDestination);
WriteParam(aMsg, aParam.mScrollSnapCoordinates);
WriteParam(aMsg, aParam.mSnapPositionX);
WriteParam(aMsg, aParam.mSnapPositionY);
WriteParam(aMsg, aParam.mXRangeWiderThanSnapport);
WriteParam(aMsg, aParam.mYRangeWiderThanSnapport);
WriteParam(aMsg, aParam.mSnapportSize);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
@ -312,7 +352,12 @@ struct ParamTraits<mozilla::layers::ScrollSnapInfo> {
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates));
ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates) &&
ReadParam(aMsg, aIter, &aResult->mSnapPositionX) &&
ReadParam(aMsg, aIter, &aResult->mSnapPositionY) &&
ReadParam(aMsg, aIter, &aResult->mXRangeWiderThanSnapport) &&
ReadParam(aMsg, aIter, &aResult->mYRangeWiderThanSnapport) &&
ReadParam(aMsg, aIter, &aResult->mSnapportSize));
}
};

Просмотреть файл

@ -23,7 +23,6 @@
#include <locale.h>
#include "nsGkAtoms.h"
#include "nsTArray.h"
#include "nsUnicodeRange.h"
#include "nsCRT.h"
#include "nsXULAppAPI.h"

Просмотреть файл

@ -19,7 +19,6 @@
#include "mozilla/TimeStamp.h"
#include "nsGkAtoms.h"
#include "nsUnicodeProperties.h"
#include "nsUnicodeRange.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"

Просмотреть файл

@ -24,7 +24,6 @@
#include "nsUnicodeProperties.h"
#include "nsMathUtils.h"
#include "nsBidiUtils.h"
#include "nsUnicodeRange.h"
#include "nsStyleConsts.h"
#include "mozilla/AppUnits.h"
#include "mozilla/FloatingPoint.h"
@ -1493,12 +1492,11 @@ void gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData) {
LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
Script script = GetScriptCode(aMatchData->mCh);
MOZ_LOG(log, LogLevel::Debug,
("(textrun-systemfallback-fonts) char: u+%6.6x "
"unicode-range: %d script: %d match: [%s]\n",
aMatchData->mCh, unicodeRange, int(script), e->Name().get()));
"script: %d match: [%s]\n",
aMatchData->mCh, int(script), e->Name().get()));
}
fe = e;

Просмотреть файл

@ -83,7 +83,6 @@
#include "gfxFontMissingGlyphs.h"
#include "nsExceptionHandler.h"
#include "nsUnicodeRange.h"
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsIObserverService.h"

Просмотреть файл

@ -16,7 +16,6 @@
#include "nsGkAtoms.h"
#include "nsServiceManagerUtils.h"
#include "nsUnicharUtils.h"
#include "nsUnicodeRange.h"
#include "nsUnicodeProperties.h"
#include "nsXULAppAPI.h"
@ -601,14 +600,12 @@ gfxFontEntry* gfxPlatformFontList::SystemFindFontForChar(
LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
uint32_t unicodeRange = FindCharUnicodeRange(aCh);
Script script = mozilla::unicode::GetScriptCode(aCh);
MOZ_LOG(log, LogLevel::Warning,
("(textrun-systemfallback-%s) char: u+%6.6x "
"unicode-range: %d script: %d match: [%s]"
"script: %d match: [%s]"
" time: %dus cmaps: %d\n",
(common ? "common" : "global"), aCh, unicodeRange,
static_cast<int>(script),
(common ? "common" : "global"), aCh, static_cast<int>(script),
(fontEntry ? fontEntry->Name().get() : "<none>"),
int32_t(elapsed.ToMicroseconds()), cmapCount));
}
@ -1046,61 +1043,116 @@ const char* gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang) {
return nullptr;
}
eFontPrefLang gfxPlatformFontList::GetFontPrefLangFor(uint8_t aUnicodeRange) {
switch (aUnicodeRange) {
case kRangeSetLatin:
eFontPrefLang gfxPlatformFontList::GetFontPrefLangFor(uint32_t aCh) {
switch (ublock_getCode(aCh)) {
case UBLOCK_BASIC_LATIN:
case UBLOCK_LATIN_1_SUPPLEMENT:
case UBLOCK_LATIN_EXTENDED_A:
case UBLOCK_LATIN_EXTENDED_B:
case UBLOCK_IPA_EXTENSIONS:
case UBLOCK_SPACING_MODIFIER_LETTERS:
case UBLOCK_LATIN_EXTENDED_ADDITIONAL:
case UBLOCK_LATIN_EXTENDED_C:
case UBLOCK_LATIN_EXTENDED_D:
case UBLOCK_LATIN_EXTENDED_E:
case UBLOCK_PHONETIC_EXTENSIONS:
return eFontPrefLang_Western;
case kRangeCyrillic:
return eFontPrefLang_Cyrillic;
case kRangeGreek:
case UBLOCK_GREEK:
case UBLOCK_GREEK_EXTENDED:
return eFontPrefLang_Greek;
case kRangeHebrew:
return eFontPrefLang_Hebrew;
case kRangeArabic:
return eFontPrefLang_Arabic;
case kRangeThai:
return eFontPrefLang_Thai;
case kRangeKorean:
return eFontPrefLang_Korean;
case kRangeJapanese:
return eFontPrefLang_Japanese;
case kRangeSChinese:
return eFontPrefLang_ChineseCN;
case kRangeTChinese:
return eFontPrefLang_ChineseTW;
case kRangeDevanagari:
return eFontPrefLang_Devanagari;
case kRangeTamil:
return eFontPrefLang_Tamil;
case kRangeArmenian:
case UBLOCK_CYRILLIC:
case UBLOCK_CYRILLIC_SUPPLEMENT:
case UBLOCK_CYRILLIC_EXTENDED_A:
case UBLOCK_CYRILLIC_EXTENDED_B:
case UBLOCK_CYRILLIC_EXTENDED_C:
return eFontPrefLang_Cyrillic;
case UBLOCK_ARMENIAN:
return eFontPrefLang_Armenian;
case kRangeBengali:
case UBLOCK_HEBREW:
return eFontPrefLang_Hebrew;
case UBLOCK_ARABIC:
case UBLOCK_ARABIC_PRESENTATION_FORMS_A:
case UBLOCK_ARABIC_PRESENTATION_FORMS_B:
case UBLOCK_ARABIC_SUPPLEMENT:
case UBLOCK_ARABIC_EXTENDED_A:
case UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS:
return eFontPrefLang_Arabic;
case UBLOCK_DEVANAGARI:
case UBLOCK_DEVANAGARI_EXTENDED:
return eFontPrefLang_Devanagari;
case UBLOCK_BENGALI:
return eFontPrefLang_Bengali;
case kRangeCanadian:
return eFontPrefLang_Canadian;
case kRangeEthiopic:
return eFontPrefLang_Ethiopic;
case kRangeGeorgian:
return eFontPrefLang_Georgian;
case kRangeGujarati:
return eFontPrefLang_Gujarati;
case kRangeGurmukhi:
case UBLOCK_GURMUKHI:
return eFontPrefLang_Gurmukhi;
case kRangeKhmer:
return eFontPrefLang_Khmer;
case kRangeMalayalam:
return eFontPrefLang_Malayalam;
case kRangeOriya:
case UBLOCK_GUJARATI:
return eFontPrefLang_Gujarati;
case UBLOCK_ORIYA:
return eFontPrefLang_Oriya;
case kRangeTelugu:
case UBLOCK_TAMIL:
return eFontPrefLang_Tamil;
case UBLOCK_TELUGU:
return eFontPrefLang_Telugu;
case kRangeKannada:
case UBLOCK_KANNADA:
return eFontPrefLang_Kannada;
case kRangeSinhala:
case UBLOCK_MALAYALAM:
return eFontPrefLang_Malayalam;
case UBLOCK_SINHALA:
case UBLOCK_SINHALA_ARCHAIC_NUMBERS:
return eFontPrefLang_Sinhala;
case kRangeTibetan:
case UBLOCK_THAI:
return eFontPrefLang_Thai;
case UBLOCK_TIBETAN:
return eFontPrefLang_Tibetan;
case kRangeSetCJK:
case UBLOCK_GEORGIAN:
case UBLOCK_GEORGIAN_SUPPLEMENT:
case UBLOCK_GEORGIAN_EXTENDED:
return eFontPrefLang_Georgian;
case UBLOCK_HANGUL_JAMO:
case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
case UBLOCK_HANGUL_SYLLABLES:
case UBLOCK_HANGUL_JAMO_EXTENDED_A:
case UBLOCK_HANGUL_JAMO_EXTENDED_B:
return eFontPrefLang_Korean;
case UBLOCK_ETHIOPIC:
case UBLOCK_ETHIOPIC_EXTENDED:
case UBLOCK_ETHIOPIC_SUPPLEMENT:
case UBLOCK_ETHIOPIC_EXTENDED_A:
return eFontPrefLang_Ethiopic;
case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS:
case UBLOCK_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED:
return eFontPrefLang_Canadian;
case UBLOCK_KHMER:
case UBLOCK_KHMER_SYMBOLS:
return eFontPrefLang_Khmer;
case UBLOCK_CJK_RADICALS_SUPPLEMENT:
case UBLOCK_KANGXI_RADICALS:
case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
case UBLOCK_HIRAGANA:
case UBLOCK_KATAKANA:
case UBLOCK_BOPOMOFO:
case UBLOCK_KANBUN:
case UBLOCK_BOPOMOFO_EXTENDED:
case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
case UBLOCK_CJK_COMPATIBILITY:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
case UBLOCK_CJK_COMPATIBILITY_FORMS:
case UBLOCK_SMALL_FORM_VARIANTS:
case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS:
case UBLOCK_CJK_STROKES:
case UBLOCK_VERTICAL_FORMS:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
case UBLOCK_KANA_SUPPLEMENT:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E:
case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION:
case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F:
case UBLOCK_KANA_EXTENDED_A:
return eFontPrefLang_CJKSet;
default:
return eFontPrefLang_Others;

Просмотреть файл

@ -284,8 +284,8 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
// ==> "zh-TW")
static const char* GetPrefLangName(eFontPrefLang aLang);
// map a Unicode range (based on char code) to a font language for Preferences
static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange);
// map a char code to a font language for Preferences
static eFontPrefLang GetFontPrefLangFor(uint32_t aCh);
// returns true if a pref lang is CJK
static bool IsLangCJK(eFontPrefLang aLang);

Просмотреть файл

@ -18,7 +18,6 @@
#include "gfxFontMissingGlyphs.h"
#include "gfxScriptItemizer.h"
#include "nsUnicodeProperties.h"
#include "nsUnicodeRange.h"
#include "nsStyleConsts.h"
#include "nsStyleUtil.h"
#include "mozilla/Likely.h"
@ -3155,8 +3154,7 @@ gfxFont* gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh,
charLang = eFontPrefLang_Emoji;
} else {
// get the pref font list if it hasn't been set up already
uint32_t unicodeRange = FindCharUnicodeRange(aCh);
charLang = pfl->GetFontPrefLangFor(unicodeRange);
charLang = pfl->GetFontPrefLangFor(aCh);
}
// if the last pref font was the first family in the pref list, no need to

Просмотреть файл

@ -211,7 +211,6 @@ UNIFIED_SOURCES += [
'gfxTextRun.cpp',
'gfxUserFontSet.cpp',
'gfxUtils.cpp',
'nsUnicodeRange.cpp',
'SoftwareVsyncSource.cpp',
'VsyncSource.cpp',
]

Просмотреть файл

@ -1,427 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "nsUnicodeRange.h"
/**********************************************************************
* Unicode subranges as defined in unicode 3.0
* x-western -> latin
* 0000 - 036f
* 1e00 - 1eff
* 2000 - 206f (general punctuation)
* 20a0 - 20cf (currency symbols)
* 2100 - 214f (letterlike symbols)
* 2150 - 218f (Number Forms)
* el -> greek
* 0370 - 03ff
* 1f00 - 1fff
* x-cyrillic -> cyrillic
* 0400 - 04ff
* he -> hebrew
* 0590 - 05ff
* ar -> arabic
* 0600 - 06ff
* fb50 - fdff (arabic presentation forms)
* fe70 - feff (arabic presentation forms b)
* th - thai
* 0e00 - 0e7f
* ko -> korean
* ac00 - d7af (hangul Syllables)
* 1100 - 11ff (jamo)
* 3130 - 318f (hangul compatibility jamo)
* ja
* 3040 - 309f (hiragana)
* 30a0 - 30ff (katakana)
* zh-CN
* zh-TW
*
* CJK
* 3100 - 312f (bopomofo)
* 31a0 - 31bf (bopomofo extended)
* 3000 - 303f (CJK Symbols and Punctuation)
* 2e80 - 2eff (CJK radicals supplement)
* 2f00 - 2fdf (Kangxi Radicals)
* 2ff0 - 2fff (Ideographic Description Characters)
* 3190 - 319f (kanbun)
* 3200 - 32ff (Enclosed CJK letters and Months)
* 3300 - 33ff (CJK compatibility)
* 3400 - 4dbf (CJK Unified Ideographs Extension A)
* 4e00 - 9faf (CJK Unified Ideographs)
* f900 - fa5f (CJK Compatibility Ideographs)
* fe30 - fe4f (CJK compatibility Forms)
* ff00 - ffef (halfwidth and fullwidth forms)
*
* Armenian
* 0530 - 058f
* Sriac
* 0700 - 074f
* Thaana
* 0780 - 07bf
* Devanagari
* 0900 - 097f
* Bengali
* 0980 - 09ff
* Gurmukhi
* 0a00 - 0a7f
* Gujarati
* 0a80 - 0aff
* Oriya
* 0b00 - 0b7f
* Tamil
* 0b80 - 0bff
* Telugu
* 0c00 - 0c7f
* Kannada
* 0c80 - 0cff
* Malayalam
* 0d00 - 0d7f
* Sinhala
* 0d80 - 0def
* Lao
* 0e80 - 0eff
* Tibetan
* 0f00 - 0fbf
* Myanmar
* 1000 - 109f
* Georgian
* 10a0 - 10ff
* Ethiopic
* 1200 - 137f
* Cherokee
* 13a0 - 13ff
* Canadian Aboriginal Syllabics
* 1400 - 167f
* Ogham
* 1680 - 169f
* Runic
* 16a0 - 16ff
* Khmer
* 1780 - 17ff
* Mongolian
* 1800 - 18af
* Misc - superscripts and subscripts
* 2070 - 209f
* Misc - Combining Diacritical Marks for Symbols
* 20d0 - 20ff
* Misc - Arrows
* 2190 - 21ff
* Misc - Mathematical Operators
* 2200 - 22ff
* Misc - Miscellaneous Technical
* 2300 - 23ff
* Misc - Control picture
* 2400 - 243f
* Misc - Optical character recognition
* 2440 - 2450
* Misc - Enclose Alphanumerics
* 2460 - 24ff
* Misc - Box Drawing
* 2500 - 257f
* Misc - Block Elements
* 2580 - 259f
* Misc - Geometric Shapes
* 25a0 - 25ff
* Misc - Miscellaneous Symbols
* 2600 - 267f
* Misc - Dingbats
* 2700 - 27bf
* Misc - Braille Patterns
* 2800 - 28ff
* Yi Syllables
* a000 - a48f
* Yi radicals
* a490 - a4cf
* Alphabetic Presentation Forms
* fb00 - fb4f
* Misc - Combining half Marks
* fe20 - fe2f
* Misc - small form variants
* fe50 - fe6f
* Misc - Specials
* fff0 - ffff
*********************************************************************/
#define NUM_OF_SUBTABLES 10
#define SUBTABLE_SIZE 16
static const uint8_t gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] = {
{
// table for X---
kRangeTableBase + 1, // u0xxx
kRangeTableBase + 2, // u1xxx
kRangeTableBase + 3, // u2xxx
kRangeSetCJK, // u3xxx
kRangeSetCJK, // u4xxx
kRangeSetCJK, // u5xxx
kRangeSetCJK, // u6xxx
kRangeSetCJK, // u7xxx
kRangeSetCJK, // u8xxx
kRangeSetCJK, // u9xxx
kRangeTableBase + 4, // uaxxx
kRangeKorean, // ubxxx
kRangeKorean, // ucxxx
kRangeTableBase + 5, // udxxx
kRangePrivate, // uexxx
kRangeTableBase + 6 // ufxxx
},
{
// table for 0X--
kRangeSetLatin, // u00xx
kRangeSetLatin, // u01xx
kRangeSetLatin, // u02xx
kRangeGreek, // u03xx XXX 0300-036f is in fact
// kRangeCombiningDiacriticalMarks
kRangeCyrillic, // u04xx
kRangeTableBase +
7, // u05xx, includes Cyrillic supplement, Hebrew, and Armenian
kRangeArabic, // u06xx
kRangeTertiaryTable, // u07xx
kRangeUnassigned, // u08xx
kRangeTertiaryTable, // u09xx
kRangeTertiaryTable, // u0axx
kRangeTertiaryTable, // u0bxx
kRangeTertiaryTable, // u0cxx
kRangeTertiaryTable, // u0dxx
kRangeTertiaryTable, // u0exx
kRangeTibetan // u0fxx
},
{
// table for 1x--
kRangeTertiaryTable, // u10xx
kRangeKorean, // u11xx
kRangeEthiopic, // u12xx
kRangeTertiaryTable, // u13xx
kRangeCanadian, // u14xx
kRangeCanadian, // u15xx
kRangeTertiaryTable, // u16xx
kRangeKhmer, // u17xx
kRangeMongolian, // u18xx
kRangeUnassigned, // u19xx
kRangeUnassigned, // u1axx
kRangeUnassigned, // u1bxx
kRangeUnassigned, // u1cxx
kRangeUnassigned, // u1dxx
kRangeSetLatin, // u1exx
kRangeGreek // u1fxx
},
{
// table for 2x--
kRangeSetLatin, // u20xx
kRangeSetLatin, // u21xx
kRangeMathOperators, // u22xx
kRangeMiscTechnical, // u23xx
kRangeControlOpticalEnclose, // u24xx
kRangeBoxBlockGeometrics, // u25xx
kRangeMiscSymbols, // u26xx
kRangeDingbats, // u27xx
kRangeBraillePattern, // u28xx
kRangeUnassigned, // u29xx
kRangeUnassigned, // u2axx
kRangeUnassigned, // u2bxx
kRangeUnassigned, // u2cxx
kRangeUnassigned, // u2dxx
kRangeSetCJK, // u2exx
kRangeSetCJK // u2fxx
},
{
// table for ax--
kRangeYi, // ua0xx
kRangeYi, // ua1xx
kRangeYi, // ua2xx
kRangeYi, // ua3xx
kRangeYi, // ua4xx
kRangeUnassigned, // ua5xx
kRangeUnassigned, // ua6xx
kRangeUnassigned, // ua7xx
kRangeUnassigned, // ua8xx
kRangeUnassigned, // ua9xx
kRangeUnassigned, // uaaxx
kRangeUnassigned, // uabxx
kRangeKorean, // uacxx
kRangeKorean, // uadxx
kRangeKorean, // uaexx
kRangeKorean // uafxx
},
{
// table for dx--
kRangeKorean, // ud0xx
kRangeKorean, // ud1xx
kRangeKorean, // ud2xx
kRangeKorean, // ud3xx
kRangeKorean, // ud4xx
kRangeKorean, // ud5xx
kRangeKorean, // ud6xx
kRangeKorean, // ud7xx
kRangeSurrogate, // ud8xx
kRangeSurrogate, // ud9xx
kRangeSurrogate, // udaxx
kRangeSurrogate, // udbxx
kRangeSurrogate, // udcxx
kRangeSurrogate, // uddxx
kRangeSurrogate, // udexx
kRangeSurrogate // udfxx
},
{
// table for fx--
kRangePrivate, // uf0xx
kRangePrivate, // uf1xx
kRangePrivate, // uf2xx
kRangePrivate, // uf3xx
kRangePrivate, // uf4xx
kRangePrivate, // uf5xx
kRangePrivate, // uf6xx
kRangePrivate, // uf7xx
kRangePrivate, // uf8xx
kRangeSetCJK, // uf9xx
kRangeSetCJK, // ufaxx
kRangeArabic, // ufbxx, includes alphabic presentation form
kRangeArabic, // ufcxx
kRangeArabic, // ufdxx
kRangeTableBase + 8, // ufexx
kRangeTableBase +
9 // uffxx, halfwidth and fullwidth forms, includes Specials
},
{
// table for 0x0500 - 0x05ff
kRangeCyrillic, // u050x
kRangeCyrillic, // u051x
kRangeCyrillic, // u052x
kRangeArmenian, // u053x
kRangeArmenian, // u054x
kRangeArmenian, // u055x
kRangeArmenian, // u056x
kRangeArmenian, // u057x
kRangeArmenian, // u058x
kRangeHebrew, // u059x
kRangeHebrew, // u05ax
kRangeHebrew, // u05bx
kRangeHebrew, // u05cx
kRangeHebrew, // u05dx
kRangeHebrew, // u05ex
kRangeHebrew // u05fx
},
{
// table for 0xfe00 - 0xfeff
kRangeSetCJK, // ufe0x
kRangeSetCJK, // ufe1x
kRangeSetCJK, // ufe2x
kRangeSetCJK, // ufe3x
kRangeSetCJK, // ufe4x
kRangeSetCJK, // ufe5x
kRangeSetCJK, // ufe6x
kRangeArabic, // ufe7x
kRangeArabic, // ufe8x
kRangeArabic, // ufe9x
kRangeArabic, // ufeax
kRangeArabic, // ufebx
kRangeArabic, // ufecx
kRangeArabic, // ufedx
kRangeArabic, // ufeex
kRangeArabic // ufefx
},
{
// table for 0xff00 - 0xffff
kRangeSetCJK, // uff0x, fullwidth latin
kRangeSetCJK, // uff1x, fullwidth latin
kRangeSetCJK, // uff2x, fullwidth latin
kRangeSetCJK, // uff3x, fullwidth latin
kRangeSetCJK, // uff4x, fullwidth latin
kRangeSetCJK, // uff5x, fullwidth latin
kRangeSetCJK, // uff6x, halfwidth katakana
kRangeSetCJK, // uff7x, halfwidth katakana
kRangeSetCJK, // uff8x, halfwidth katakana
kRangeSetCJK, // uff9x, halfwidth katakana
kRangeSetCJK, // uffax, halfwidth hangul jamo
kRangeSetCJK, // uffbx, halfwidth hangul jamo
kRangeSetCJK, // uffcx, halfwidth hangul jamo
kRangeSetCJK, // uffdx, halfwidth hangul jamo
kRangeSetCJK, // uffex, fullwidth symbols
kRangeSpecials, // ufffx, Specials
},
};
// Most scripts between U+0700 and U+16FF are assigned a chunk of 128 (0x80)
// code points so that the number of entries in the tertiary range
// table for that range is obtained by dividing (0x1700 - 0x0700) by 128.
// Exceptions: Ethiopic, Tibetan, Hangul Jamo and Canadian aboriginal
// syllabaries take multiple chunks and Ogham and Runic share a single chunk.
#define TERTIARY_TABLE_SIZE ((0x1700 - 0x0700) / 0x80)
static const uint8_t gUnicodeTertiaryRangeTable[TERTIARY_TABLE_SIZE] = {
// table for 0x0700 - 0x1600
kRangeSyriac, // u070x
kRangeThaana, // u078x
kRangeUnassigned, // u080x place holder(resolved in the 2ndary tab.)
kRangeUnassigned, // u088x place holder(resolved in the 2ndary tab.)
kRangeDevanagari, // u090x
kRangeBengali, // u098x
kRangeGurmukhi, // u0a0x
kRangeGujarati, // u0a8x
kRangeOriya, // u0b0x
kRangeTamil, // u0b8x
kRangeTelugu, // u0c0x
kRangeKannada, // u0c8x
kRangeMalayalam, // u0d0x
kRangeSinhala, // u0d8x
kRangeThai, // u0e0x
kRangeLao, // u0e8x
kRangeTibetan, // u0f0x place holder(resolved in the 2ndary tab.)
kRangeTibetan, // u0f8x place holder(resolved in the 2ndary tab.)
kRangeMyanmar, // u100x
kRangeGeorgian, // u108x
kRangeKorean, // u110x place holder(resolved in the 2ndary tab.)
kRangeKorean, // u118x place holder(resolved in the 2ndary tab.)
kRangeEthiopic, // u120x place holder(resolved in the 2ndary tab.)
kRangeEthiopic, // u128x place holder(resolved in the 2ndary tab.)
kRangeEthiopic, // u130x
kRangeCherokee, // u138x
kRangeCanadian, // u140x place holder(resolved in the 2ndary tab.)
kRangeCanadian, // u148x place holder(resolved in the 2ndary tab.)
kRangeCanadian, // u150x place holder(resolved in the 2ndary tab.)
kRangeCanadian, // u158x place holder(resolved in the 2ndary tab.)
kRangeCanadian, // u160x
kRangeOghamRunic // u168x this contains two scripts, Ogham & Runic
};
// A two level index is almost enough for locating a range, with the
// exception of u03xx and u05xx. Since we don't really care about range for
// combining diacritical marks in our font application, they are
// not discriminated further. But future adoption of this module for other use
// should be aware of this limitation. The implementation can be extended if
// there is such a need.
// For Indic, Southeast Asian scripts and some other scripts between
// U+0700 and U+16FF, it's extended to the third level.
uint32_t FindCharUnicodeRange(uint32_t ch) {
uint32_t range;
// aggregate ranges for non-BMP codepoints
if (ch > 0xFFFF) {
uint32_t p = (ch >> 16);
if (p == 1) {
return kRangeSMP;
} else if (p == 2) {
return kRangeSetCJK;
}
return kRangeHigherPlanes;
}
// lookup explicit range for BMP codepoints
// first general range
range = gUnicodeSubrangeTable[0][ch >> 12];
// if general range is good enough, return that
if (range < kRangeTableBase)
// we try to get a specific range
return range;
// otherwise, use subrange tables
range = gUnicodeSubrangeTable[range - kRangeTableBase][(ch & 0x0f00) >> 8];
if (range < kRangeTableBase) return range;
if (range < kRangeTertiaryTable)
return gUnicodeSubrangeTable[range - kRangeTableBase][(ch & 0x00f0) >> 4];
// Yet another table to look at : U+0700 - U+16FF : 128 code point blocks
return gUnicodeTertiaryRangeTable[(ch - 0x0700) >> 7];
}

Просмотреть файл

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 NS_UNICODERANGE_H
#define NS_UNICODERANGE_H
#include <stdint.h>
// The following constants define unicode subranges
// values below kRangeNum must be continuous so that we can map to
// lang group directly.
// all ranges we care about should be defined under 32, that allows
// us to store range using bits of a uint32_t
// frequently used range definitions
const uint8_t kRangeCyrillic = 0;
const uint8_t kRangeGreek = 1;
const uint8_t kRangeHebrew = 2;
const uint8_t kRangeArabic = 3;
const uint8_t kRangeThai = 4;
const uint8_t kRangeKorean = 5;
const uint8_t kRangeJapanese = 6;
const uint8_t kRangeSChinese = 7;
const uint8_t kRangeTChinese = 8;
const uint8_t kRangeDevanagari = 9;
const uint8_t kRangeTamil = 10;
const uint8_t kRangeArmenian = 11;
const uint8_t kRangeBengali = 12;
const uint8_t kRangeCanadian = 13;
const uint8_t kRangeEthiopic = 14;
const uint8_t kRangeGeorgian = 15;
const uint8_t kRangeGujarati = 16;
const uint8_t kRangeGurmukhi = 17;
const uint8_t kRangeKhmer = 18;
const uint8_t kRangeMalayalam = 19;
const uint8_t kRangeOriya = 20;
const uint8_t kRangeTelugu = 21;
const uint8_t kRangeKannada = 22;
const uint8_t kRangeSinhala = 23;
const uint8_t kRangeTibetan = 24;
const uint8_t kRangeSpecificItemNum = 25;
// range/rangeSet grow to this place 25-29
const uint8_t kRangeSetStart = 30; // range set definition starts from here
const uint8_t kRangeSetLatin = 30;
const uint8_t kRangeSetCJK = 31;
const uint8_t kRangeSetEnd = 31; // range set definition ends here, this
// and smaller ranges are used as bit
// mask, don't increase this value.
// less frequently used range definition
const uint8_t kRangeSurrogate = 32;
const uint8_t kRangePrivate = 33;
const uint8_t kRangeMisc = 34;
const uint8_t kRangeUnassigned = 35;
const uint8_t kRangeSyriac = 36;
const uint8_t kRangeThaana = 37;
const uint8_t kRangeLao = 38;
const uint8_t kRangeMyanmar = 39;
const uint8_t kRangeCherokee = 40;
const uint8_t kRangeOghamRunic = 41;
const uint8_t kRangeMongolian = 42;
const uint8_t kRangeMathOperators = 43;
const uint8_t kRangeMiscTechnical = 44;
const uint8_t kRangeControlOpticalEnclose = 45;
const uint8_t kRangeBoxBlockGeometrics = 46;
const uint8_t kRangeMiscSymbols = 47;
const uint8_t kRangeDingbats = 48;
const uint8_t kRangeBraillePattern = 49;
const uint8_t kRangeYi = 50;
const uint8_t kRangeCombiningDiacriticalMarks = 51;
const uint8_t kRangeSpecials = 52;
// aggregate ranges for non-BMP codepoints (u+2xxxx are all CJK)
const uint8_t kRangeSMP = 53; // u+1xxxx
const uint8_t kRangeHigherPlanes = 54; // u+3xxxx and above
const uint8_t kRangeTableBase =
128; // values over 127 are reserved for internal use only
const uint8_t kRangeTertiaryTable = 145; // leave room for 16 subtable
// indices (kRangeTableBase + 1 ..
// kRangeTableBase + 16)
uint32_t FindCharUnicodeRange(uint32_t ch);
#endif

Просмотреть файл

@ -12,6 +12,7 @@ UNIFIED_SOURCES += [
'testExample.cpp',
'tests.cpp',
'testStructuredCloneReader.cpp',
'testWasm.cpp',
]
if CONFIG['JS_BUILD_BINAST']:

Просмотреть файл

@ -0,0 +1,432 @@
/* 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 "mozilla/ScopeExit.h"
#include "jsapi.h"
#include "fuzz-tests/tests.h"
#include "vm/Interpreter.h"
#include "vm/TypedArrayObject.h"
#include "wasm/WasmCompile.h"
#include "wasm/WasmCraneliftCompile.h"
#include "wasm/WasmIonCompile.h"
#include "wasm/WasmJS.h"
#include "wasm/WasmTable.h"
#include "vm/ArrayBufferObject-inl.h"
#include "vm/JSContext-inl.h"
using namespace js;
using namespace js::wasm;
// These are defined and pre-initialized by the harness (in tests.cpp).
extern JS::PersistentRootedObject gGlobal;
extern JSContext* gCx;
static int testWasmInit(int* argc, char*** argv) {
if (!wasm::HasSupport(gCx)) {
MOZ_CRASH("Failed to initialize wasm support");
}
return 0;
}
static bool emptyNativeFunction(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setUndefined();
return true;
}
static bool callExportedFunc(HandleFunction func,
MutableHandleValue lastReturnVal) {
// TODO: We can specify a thisVal here.
RootedValue thisVal(gCx, UndefinedValue());
JS::RootedValueVector args(gCx);
if (!lastReturnVal.isNull() && !lastReturnVal.isUndefined() &&
!args.append(lastReturnVal)) {
return false;
}
RootedValue returnVal(gCx);
if (!Call(gCx, thisVal, func, args, &returnVal)) {
gCx->clearPendingException();
} else {
lastReturnVal.set(returnVal);
}
return true;
}
template <typename T>
static bool assignImportKind(const Import& import, HandleObject obj,
HandleObject lastExportsObj,
JS::Handle<JS::IdVector> lastExportIds,
size_t* currentExportId, size_t exportsLength,
HandleValue defaultValue) {
bool assigned = false;
while (*currentExportId < exportsLength) {
RootedValue propVal(gCx);
if (!JS_GetPropertyById(gCx, lastExportsObj,
lastExportIds[*currentExportId], &propVal)) {
return false;
}
(*currentExportId)++;
if (propVal.isObject() && propVal.toObject().is<T>()) {
if (!JS_SetProperty(gCx, obj, import.field.get(), propVal)) {
return false;
}
assigned = true;
break;
}
}
if (!assigned) {
if (!JS_SetProperty(gCx, obj, import.field.get(), defaultValue)) {
return false;
}
}
return true;
}
static int testWasmFuzz(const uint8_t* buf, size_t size) {
auto gcGuard = mozilla::MakeScopeExit([&] {
JS::PrepareForFullGC(gCx);
JS::NonIncrementalGC(gCx, GC_NORMAL, JS::GCReason::API);
});
const size_t MINIMUM_MODULE_SIZE = 8;
// The smallest valid wasm module is 8 bytes and we need 1 byte for size
if (size < MINIMUM_MODULE_SIZE + 1) return 0;
size_t currentIndex = 0;
// Store the last non-empty exports object and its enumerated Ids here
RootedObject lastExportsObj(gCx);
JS::Rooted<JS::IdVector> lastExportIds(gCx, JS::IdVector(gCx));
// Store the last return value so we can pass it in as an argument during
// the next call (which can be on another module as well).
RootedValue lastReturnVal(gCx);
while (size - currentIndex >= MINIMUM_MODULE_SIZE + 1) {
// Ensure we have no lingering exceptions from previous modules
gCx->clearPendingException();
unsigned char moduleLen = buf[currentIndex];
currentIndex++;
if (size - currentIndex < moduleLen) {
moduleLen = size - currentIndex;
}
if (moduleLen < MINIMUM_MODULE_SIZE) {
continue;
}
if (currentIndex == 1) {
// If this is the first module we are reading, we use the first
// few bytes to tweak some settings. These are fixed anyway and
// overwritten later on.
uint8_t optByte = (uint8_t)buf[currentIndex];
bool enableWasmBaseline = ((optByte & 0xF0) == (1 << 7));
bool enableWasmIon = IonCanCompile() && ((optByte & 0xF0) == (1 << 6));
bool enableWasmCranelift = false;
#ifdef ENABLE_WASM_CRANELIFT
enableWasmCranelift =
CraneliftCanCompile() && ((optByte & 0xF0) == (1 << 5));
#endif
bool enableWasmAwaitTier2 = (IonCanCompile()
#ifdef ENABLE_WASM_CRANELIFT
|| CraneliftCanCompile()
#endif
) &&
((optByte & 0xF) == (1 << 3));
if (!enableWasmBaseline && !enableWasmIon && !enableWasmCranelift) {
// If nothing is selected explicitly, select Ion to test
// more platform specific JIT code. However, on some platforms,
// e.g. ARM64, we do not have Ion available, so we need to switch
// to baseline instead.
if (IonCanCompile()) {
enableWasmIon = true;
} else {
enableWasmBaseline = true;
}
}
// TODO: Cranelift is not stable for fuzzing, defer to baseline
if (enableWasmCranelift) {
enableWasmCranelift = false;
enableWasmBaseline = true;
}
if (enableWasmAwaitTier2) {
// Tier 2 needs Baseline + {Ion,Cranelift}
enableWasmBaseline = true;
if (!enableWasmIon && !enableWasmCranelift) {
enableWasmIon = true;
}
}
JS::ContextOptionsRef(gCx)
.setWasmBaseline(enableWasmBaseline)
.setWasmIon(enableWasmIon)
.setTestWasmAwaitTier2(enableWasmAwaitTier2)
#ifdef ENABLE_WASM_CRANELIFT
.setWasmCranelift(enableWasmCranelift)
#endif
;
}
// Expected header for a valid WebAssembly module
uint32_t magic_header = 0x6d736100;
uint32_t magic_version = 0x1;
// We just skip over the first 8 bytes now because we fill them
// with `magic_header` and `magic_version` anyway.
currentIndex += 8;
moduleLen -= 8;
RootedWasmInstanceObject instanceObj(gCx);
MutableBytes bytecode = gCx->new_<ShareableBytes>();
if (!bytecode || !bytecode->append((uint8_t*)&magic_header, 4) ||
!bytecode->append((uint8_t*)&magic_version, 4) ||
!bytecode->append(&buf[currentIndex], moduleLen)) {
return 0;
}
currentIndex += moduleLen;
ScriptedCaller scriptedCaller;
SharedCompileArgs compileArgs =
CompileArgs::build(gCx, std::move(scriptedCaller));
if (!compileArgs) {
return 0;
}
UniqueChars error;
UniqueCharsVector warnings;
SharedModule module =
CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
if (!module) {
continue;
}
// At this point we have a valid module and we should try to ensure
// that its import requirements are met for instantiation.
const ImportVector& importVec = module->imports();
// Empty native function used to fill in function import slots if we
// run out of functions exported by other modules.
JS::RootedFunction emptyFunction(gCx);
emptyFunction =
JS_NewFunction(gCx, emptyNativeFunction, 0, 0, "emptyFunction");
if (!emptyFunction) {
return 0;
}
RootedValue emptyFunctionValue(gCx, ObjectValue(*emptyFunction));
RootedValue nullValue(gCx, NullValue());
RootedObject importObj(gCx, JS_NewPlainObject(gCx));
if (!importObj) {
return 0;
}
size_t exportsLength = lastExportIds.length();
size_t currentFunctionExportId = 0;
size_t currentTableExportId = 0;
size_t currentMemoryExportId = 0;
size_t currentGlobalExportId = 0;
for (const Import& import : importVec) {
// First try to get the namespace object, create one if this is the
// first time.
RootedValue v(gCx);
if (!JS_GetProperty(gCx, importObj, import.module.get(), &v) ||
!v.isObject()) {
// Insert empty object at importObj[import.module.get()]
RootedObject plainObj(gCx, JS_NewPlainObject(gCx));
if (!plainObj) {
return 0;
}
RootedValue plainVal(gCx, ObjectValue(*plainObj));
if (!JS_SetProperty(gCx, importObj, import.module.get(), plainVal)) {
return 0;
}
// Get the object we just inserted, store in v, ensure it is an
// object (no proxies or other magic at work).
if (!JS_GetProperty(gCx, importObj, import.module.get(), &v) ||
!v.isObject()) {
return 0;
}
}
RootedObject obj(gCx, &v.toObject());
bool found = false;
if (JS_HasProperty(gCx, obj, import.field.get(), &found) && !found) {
// Insert i-th export object that fits the type requirement
// at `v[import.field.get()]`.
switch (import.kind) {
case DefinitionKind::Function:
if (!assignImportKind<JSFunction>(
import, obj, lastExportsObj, lastExportIds,
&currentFunctionExportId, exportsLength,
emptyFunctionValue)) {
return 0;
}
break;
case DefinitionKind::Table:
// TODO: Pass a dummy defaultValue
if (!assignImportKind<WasmTableObject>(
import, obj, lastExportsObj, lastExportIds,
&currentTableExportId, exportsLength, nullValue)) {
return 0;
}
break;
case DefinitionKind::Memory:
// TODO: Pass a dummy defaultValue
if (!assignImportKind<WasmMemoryObject>(
import, obj, lastExportsObj, lastExportIds,
&currentMemoryExportId, exportsLength, nullValue)) {
return 0;
}
break;
case DefinitionKind::Global:
// TODO: Pass a dummy defaultValue
if (!assignImportKind<WasmGlobalObject>(
import, obj, lastExportsObj, lastExportIds,
&currentGlobalExportId, exportsLength, nullValue)) {
return 0;
}
break;
}
}
}
Rooted<ImportValues> imports(gCx);
if (!GetImports(gCx, *module, importObj, imports.address())) {
continue;
}
if (!module->instantiate(gCx, imports.get(), nullptr, &instanceObj)) {
continue;
}
// At this module we have a valid WebAssembly module instance.
RootedObject exportsObj(gCx, &instanceObj->exportsObj());
JS::Rooted<JS::IdVector> exportIds(gCx, JS::IdVector(gCx));
if (!JS_Enumerate(gCx, exportsObj, &exportIds)) {
continue;
}
if (!exportIds.length()) {
continue;
}
// Store the last exports for re-use later
lastExportsObj = exportsObj;
lastExportIds.get() = std::move(exportIds.get());
for (size_t i = 0; i < lastExportIds.length(); i++) {
RootedValue propVal(gCx);
if (!JS_GetPropertyById(gCx, exportsObj, lastExportIds[i], &propVal)) {
return 0;
}
if (propVal.isObject()) {
RootedObject propObj(gCx, &propVal.toObject());
if (propObj->is<JSFunction>()) {
RootedFunction func(gCx, &propObj->as<JSFunction>());
if (!callExportedFunc(func, &lastReturnVal)) {
return 0;
}
}
if (propObj->is<WasmTableObject>()) {
Rooted<WasmTableObject*> tableObj(gCx,
&propObj->as<WasmTableObject>());
size_t tableLen = tableObj->table().length();
RootedValue tableGetVal(gCx);
if (!JS_GetProperty(gCx, tableObj, "get", &tableGetVal)) {
return 0;
}
RootedFunction tableGet(gCx,
&tableGetVal.toObject().as<JSFunction>());
for (size_t i = 0; i < tableLen; i++) {
JS::RootedValueVector tableGetArgs(gCx);
if (!tableGetArgs.append(NumberValue(uint32_t(i)))) {
return 0;
}
RootedValue readFuncValue(gCx);
if (!Call(gCx, tableObj, tableGet, tableGetArgs, &readFuncValue)) {
return 0;
}
if (readFuncValue.isNull()) {
continue;
}
RootedFunction callee(gCx,
&readFuncValue.toObject().as<JSFunction>());
if (!callExportedFunc(callee, &lastReturnVal)) {
return 0;
}
}
}
if (propObj->is<WasmMemoryObject>()) {
Rooted<WasmMemoryObject*> memory(gCx,
&propObj->as<WasmMemoryObject>());
size_t byteLen = memory->volatileMemoryLength();
if (byteLen) {
// Read the bounds of the buffer to ensure it is valid.
// AddressSanitizer would detect any out-of-bounds here.
uint8_t* rawMemory = memory->buffer().dataPointerEither().unwrap();
volatile uint8_t rawMemByte = 0;
rawMemByte += rawMemory[0];
rawMemByte += rawMemory[byteLen - 1];
}
}
if (propObj->is<WasmGlobalObject>()) {
Rooted<WasmGlobalObject*> global(gCx,
&propObj->as<WasmGlobalObject>());
if (global->type() != ValType::I64) {
lastReturnVal = global->value(gCx);
}
}
}
}
}
return 0;
}
MOZ_FUZZING_INTERFACE_RAW(testWasmInit, testWasmFuzz, Wasm);

Просмотреть файл

@ -240,7 +240,7 @@ static bool GetProperty(JSContext* cx, HandleObject obj, const char* chars,
return GetProperty(cx, obj, obj, id, v);
}
static bool GetImports(JSContext* cx, const Module& module,
bool js::wasm::GetImports(JSContext* cx, const Module& module,
HandleObject importObj, ImportValues* imports) {
if (!module.imports().empty() && !importObj) {
return ThrowBadImportArg(cx);

Просмотреть файл

@ -75,6 +75,14 @@ MOZ_MUST_USE bool Eval(JSContext* cx, Handle<TypedArrayObject*> code,
HandleObject importObj,
MutableHandleWasmInstanceObject instanceObj);
// Extracts the various imports from the given import object into the given
// ImportValues structure while checking the imports against the given module.
// The resulting structure can be passed to WasmModule::instantiate.
struct ImportValues;
MOZ_MUST_USE bool GetImports(JSContext* cx, const Module& module,
HandleObject importObj, ImportValues* imports);
// For testing cross-process (de)serialization, this pair of functions are
// responsible for, in the child process, compiling the given wasm bytecode
// to a wasm::Module that is serialized into the given byte array, and, in

Просмотреть файл

@ -45,3 +45,8 @@ UNIFIED_SOURCES += [
'WasmTypes.cpp',
'WasmValidate.cpp'
]
# Make sure all WebAssembly code is built with libfuzzer
# coverage instrumentation in FUZZING mode.
if CONFIG['FUZZING_INTERFACES'] and CONFIG['LIBFUZZER']:
include('/tools/fuzzing/libfuzzer-config.mozbuild')

Просмотреть файл

@ -3374,7 +3374,10 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable,
if (gfxPrefs::ScrollBehaviorEnabled() && smoothScroll) {
scrollMode = ScrollMode::eSmoothMsd;
}
aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange);
aFrameAsScrollable->ScrollTo(scrollPt, scrollMode, &allowedRange,
aFlags & nsIPresShell::SCROLL_SNAP
? nsIScrollbarMediator::ENABLE_SNAP
: nsIScrollbarMediator::DISABLE_SNAP);
}
}
@ -3454,6 +3457,14 @@ void nsIPresShell::DoScrollContentIntoView() {
return;
}
// Get the scroll-margin here since |frame| is going to be changed to iterate
// over all continuation frames below.
nsMargin scrollMargin;
if (!(data->mContentToScrollToFlags &
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING)) {
scrollMargin = frame->StyleMargin()->GetScrollMargin();
}
// This is a two-step process.
// Step 1: Find the bounds of the rect we want to scroll into view. For
// example, for an inline frame we may want to scroll in the whole
@ -3480,6 +3491,8 @@ void nsIPresShell::DoScrollContentIntoView() {
frameBounds, haveRect, prevBlock, lines, curLine);
} while ((frame = frame->GetNextContinuation()));
frameBounds.Inflate(scrollMargin);
ScrollFrameRectIntoView(container, frameBounds, data->mContentScrollVAxis,
data->mContentScrollHAxis,
data->mContentToScrollToFlags);
@ -3522,8 +3535,16 @@ bool nsIPresShell::ScrollFrameRectIntoView(nsIFrame* aFrame,
}
targetRect.Inflate(padding);
}
ScrollToShowRect(sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
aVertical, aHorizontal, aFlags);
targetRect -= sf->GetScrolledFrame()->GetPosition();
if (!(aFlags & nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING)) {
nsMargin scrollPadding = sf->GetScrollPadding();
targetRect.Inflate(scrollPadding);
targetRect = targetRect.Intersect(sf->GetScrolledRect());
}
ScrollToShowRect(sf, targetRect, aVertical, aHorizontal, aFlags);
nsPoint newPosition = sf->LastScrollDestination();
// If the scroll position increased, that means our content moved up,
// so our rect's offset should decrease
@ -8455,7 +8476,8 @@ bool PresShell::EventHandler::PrepareToUseCaretPosition(
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::ScrollAxis(nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
nsIPresShell::SCROLL_OVERFLOW_HIDDEN |
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING);
NS_ENSURE_SUCCESS(rv, false);
frame = content->GetPrimaryFrame();
NS_WARNING_ASSERTION(frame, "No frame for focused content?");
@ -8513,8 +8535,10 @@ void PresShell::EventHandler::GetCurrentItemAndPositionForElement(
Element* aFocusedElement, nsIContent** aTargetToUse,
LayoutDeviceIntPoint& aTargetPt, nsIWidget* aRootWidget) {
nsCOMPtr<nsIContent> focusedContent = aFocusedElement;
mPresShell->ScrollContentIntoView(focusedContent, ScrollAxis(), ScrollAxis(),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
mPresShell->ScrollContentIntoView(
focusedContent, ScrollAxis(), ScrollAxis(),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN |
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING);
nsPresContext* presContext = GetPresContext();

Просмотреть файл

@ -9,31 +9,69 @@
namespace mozilla {
ScrollStyles::ScrollStyles(StyleOverflow aH, StyleOverflow aV,
const nsStyleDisplay* aDisplay)
void ScrollStyles::InitializeScrollSnapType(WritingMode aWritingMode,
const nsStyleDisplay* aDisplay) {
mScrollSnapTypeX = StyleScrollSnapStrictness::None;
mScrollSnapTypeY = StyleScrollSnapStrictness::None;
if (aDisplay->mScrollSnapType.strictness == StyleScrollSnapStrictness::None) {
return;
}
switch (aDisplay->mScrollSnapType.axis) {
case StyleScrollSnapAxis::X:
mScrollSnapTypeX = aDisplay->mScrollSnapType.strictness;
break;
case StyleScrollSnapAxis::Y:
mScrollSnapTypeY = aDisplay->mScrollSnapType.strictness;
break;
case StyleScrollSnapAxis::Block:
if (aWritingMode.IsVertical()) {
mScrollSnapTypeX = aDisplay->mScrollSnapType.strictness;
} else {
mScrollSnapTypeY = aDisplay->mScrollSnapType.strictness;
}
break;
case StyleScrollSnapAxis::Inline:
if (aWritingMode.IsVertical()) {
mScrollSnapTypeY = aDisplay->mScrollSnapType.strictness;
} else {
mScrollSnapTypeX = aDisplay->mScrollSnapType.strictness;
}
break;
case StyleScrollSnapAxis::Both:
mScrollSnapTypeX = aDisplay->mScrollSnapType.strictness;
mScrollSnapTypeY = aDisplay->mScrollSnapType.strictness;
break;
}
}
ScrollStyles::ScrollStyles(WritingMode aWritingMode, StyleOverflow aH,
StyleOverflow aV, const nsStyleDisplay* aDisplay)
: mHorizontal(aH),
mVertical(aV),
mScrollBehavior(aDisplay->mScrollBehavior),
mOverscrollBehaviorX(aDisplay->mOverscrollBehaviorX),
mOverscrollBehaviorY(aDisplay->mOverscrollBehaviorY),
mScrollSnapTypeX(aDisplay->mScrollSnapTypeX),
mScrollSnapTypeY(aDisplay->mScrollSnapTypeY),
mScrollSnapPointsX(aDisplay->mScrollSnapPointsX),
mScrollSnapPointsY(aDisplay->mScrollSnapPointsY),
mScrollSnapDestinationX(aDisplay->mScrollSnapDestination.horizontal),
mScrollSnapDestinationY(aDisplay->mScrollSnapDestination.vertical) {}
mScrollSnapDestinationY(aDisplay->mScrollSnapDestination.vertical) {
InitializeScrollSnapType(aWritingMode, aDisplay);
}
ScrollStyles::ScrollStyles(const nsStyleDisplay* aDisplay)
ScrollStyles::ScrollStyles(WritingMode aWritingMode,
const nsStyleDisplay* aDisplay)
: mHorizontal(aDisplay->mOverflowX),
mVertical(aDisplay->mOverflowY),
mScrollBehavior(aDisplay->mScrollBehavior),
mOverscrollBehaviorX(aDisplay->mOverscrollBehaviorX),
mOverscrollBehaviorY(aDisplay->mOverscrollBehaviorY),
mScrollSnapTypeX(aDisplay->mScrollSnapTypeX),
mScrollSnapTypeY(aDisplay->mScrollSnapTypeY),
mScrollSnapPointsX(aDisplay->mScrollSnapPointsX),
mScrollSnapPointsY(aDisplay->mScrollSnapPointsY),
mScrollSnapDestinationX(aDisplay->mScrollSnapDestination.horizontal),
mScrollSnapDestinationY(aDisplay->mScrollSnapDestination.vertical) {}
mScrollSnapDestinationY(aDisplay->mScrollSnapDestination.vertical) {
InitializeScrollSnapType(aWritingMode, aDisplay);
}
} // namespace mozilla

Просмотреть файл

@ -26,8 +26,8 @@ struct ScrollStyles {
uint8_t mScrollBehavior;
StyleOverscrollBehavior mOverscrollBehaviorX;
StyleOverscrollBehavior mOverscrollBehaviorY;
StyleScrollSnapType mScrollSnapTypeX;
StyleScrollSnapType mScrollSnapTypeY;
StyleScrollSnapStrictness mScrollSnapTypeX;
StyleScrollSnapStrictness mScrollSnapTypeY;
nsStyleCoord mScrollSnapPointsX;
nsStyleCoord mScrollSnapPointsY;
LengthPercentage mScrollSnapDestinationX;
@ -39,15 +39,18 @@ struct ScrollStyles {
mScrollBehavior(NS_STYLE_SCROLL_BEHAVIOR_AUTO),
mOverscrollBehaviorX(StyleOverscrollBehavior::Auto),
mOverscrollBehaviorY(StyleOverscrollBehavior::Auto),
mScrollSnapTypeX(StyleScrollSnapType::None),
mScrollSnapTypeY(StyleScrollSnapType::None),
mScrollSnapTypeX(StyleScrollSnapStrictness::None),
mScrollSnapTypeY(StyleScrollSnapStrictness::None),
mScrollSnapPointsX(nsStyleCoord(eStyleUnit_None)),
mScrollSnapPointsY(nsStyleCoord(eStyleUnit_None)),
mScrollSnapDestinationX(LengthPercentage::Zero()),
mScrollSnapDestinationY(LengthPercentage::Zero()) {}
explicit ScrollStyles(const nsStyleDisplay* aDisplay);
ScrollStyles(StyleOverflow aH, StyleOverflow aV, const nsStyleDisplay*);
ScrollStyles(WritingMode aWritingMode, const nsStyleDisplay* aDisplay);
ScrollStyles(WritingMode aWritingMode, StyleOverflow aH, StyleOverflow aV,
const nsStyleDisplay* aDisplay);
void InitializeScrollSnapType(WritingMode aWritingMode,
const nsStyleDisplay* aDisplay);
bool operator==(const ScrollStyles& aStyles) const {
return aStyles.mHorizontal == mHorizontal &&
aStyles.mVertical == mVertical &&

Просмотреть файл

@ -778,7 +778,9 @@ class nsIPresShell : public nsStubDocumentObserver {
SCROLL_OVERFLOW_HIDDEN = 0x02,
SCROLL_NO_PARENT_FRAMES = 0x04,
SCROLL_SMOOTH = 0x08,
SCROLL_SMOOTH_AUTO = 0x10
SCROLL_SMOOTH_AUTO = 0x10,
SCROLL_SNAP = 0x20,
SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING = 0x40
};
/**
* Scrolls the view of the document so that the given area of a frame
@ -797,6 +799,10 @@ class nsIPresShell : public nsStubDocumentObserver {
* If SCROLL_NO_PARENT_FRAMES is set then we only scroll
* nodes in this document, not in any parent documents which
* contain this document in a iframe or the like.
* If SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING is set we ignore scroll-margin
* value specified for |aFrame| and scroll-padding value for the scroll
* container. This option is typically used to locate poped-up frames into
* view.
* @return true if any scrolling happened, false if no scrolling happened
*/
bool ScrollFrameRectIntoView(nsIFrame* aFrame, const nsRect& aRect,

Просмотреть файл

@ -1015,26 +1015,27 @@ gfxSize nsPresContext::ScreenSizeInchesForFontInflation(bool* aChanged) {
return deviceSizeInches;
}
static bool CheckOverflow(const nsStyleDisplay* aDisplay,
static bool CheckOverflow(ComputedStyle* aComputedStyle,
ScrollStyles* aStyles) {
if (aDisplay->mOverflowX == StyleOverflow::Visible &&
aDisplay->mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_AUTO &&
aDisplay->mOverscrollBehaviorX == StyleOverscrollBehavior::Auto &&
aDisplay->mOverscrollBehaviorY == StyleOverscrollBehavior::Auto &&
aDisplay->mScrollSnapTypeX == StyleScrollSnapType::None &&
aDisplay->mScrollSnapTypeY == StyleScrollSnapType::None &&
aDisplay->mScrollSnapPointsX == nsStyleCoord(eStyleUnit_None) &&
aDisplay->mScrollSnapPointsY == nsStyleCoord(eStyleUnit_None) &&
aDisplay->mScrollSnapDestination.horizontal == LengthPercentage::Zero() &&
aDisplay->mScrollSnapDestination.vertical == LengthPercentage::Zero()) {
const nsStyleDisplay* display = aComputedStyle->StyleDisplay();
if (display->mOverflowX == StyleOverflow::Visible &&
display->mScrollBehavior == NS_STYLE_SCROLL_BEHAVIOR_AUTO &&
display->mOverscrollBehaviorX == StyleOverscrollBehavior::Auto &&
display->mOverscrollBehaviorY == StyleOverscrollBehavior::Auto &&
display->mScrollSnapType.strictness == StyleScrollSnapStrictness::None &&
display->mScrollSnapPointsX == nsStyleCoord(eStyleUnit_None) &&
display->mScrollSnapPointsY == nsStyleCoord(eStyleUnit_None) &&
display->mScrollSnapDestination.horizontal == LengthPercentage::Zero() &&
display->mScrollSnapDestination.vertical == LengthPercentage::Zero()) {
return false;
}
if (aDisplay->mOverflowX == StyleOverflow::MozHiddenUnscrollable) {
*aStyles =
ScrollStyles(StyleOverflow::Hidden, StyleOverflow::Hidden, aDisplay);
WritingMode writingMode = WritingMode(aComputedStyle);
if (display->mOverflowX == StyleOverflow::MozHiddenUnscrollable) {
*aStyles = ScrollStyles(writingMode, StyleOverflow::Hidden,
StyleOverflow::Hidden, display);
} else {
*aStyles = ScrollStyles(aDisplay);
*aStyles = ScrollStyles(writingMode, display);
}
return true;
}
@ -1053,7 +1054,7 @@ static Element* GetPropagatedScrollStylesForViewport(
// Check the style on the document root element
ServoStyleSet* styleSet = aPresContext->StyleSet();
RefPtr<ComputedStyle> rootStyle = styleSet->ResolveStyleLazily(*docElement);
if (CheckOverflow(rootStyle->StyleDisplay(), aStyles)) {
if (CheckOverflow(rootStyle, aStyles)) {
// tell caller we stole the overflow style from the root element
return docElement;
}
@ -1083,7 +1084,7 @@ static Element* GetPropagatedScrollStylesForViewport(
// https://github.com/w3c/csswg-drafts/issues/3779
RefPtr<ComputedStyle> bodyStyle = styleSet->ResolveStyleLazily(*bodyElement);
if (CheckOverflow(bodyStyle->StyleDisplay(), aStyles)) {
if (CheckOverflow(bodyStyle, aStyles)) {
// tell caller we stole the overflow style from the body element
return bodyElement;
}

Просмотреть файл

@ -19,7 +19,7 @@
var testCases = [
{
"description" : "Proximity + Within proximity => Snaps to point (Right)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -34,7 +34,7 @@ var testCases = [
{
"description" : "Proximity + Within proximity => Snaps to point (Left)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -49,7 +49,7 @@ var testCases = [
{
"description" : "Proximity + Within proximity => Snaps to point (Up)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -64,7 +64,7 @@ var testCases = [
{
"description" : "Proximity + Within proximity => Snaps to point (Down)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -79,7 +79,7 @@ var testCases = [
{
"description" : "Proximity + Beyond proximity => Does not snap to point (Right)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -94,7 +94,7 @@ var testCases = [
{
"description" : "Proximity + Beyond proximity => Does not snap to point (Left)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -109,7 +109,7 @@ var testCases = [
{
"description" : "Proximity + Beyond proximity => Does not snap to point (Up)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -124,7 +124,7 @@ var testCases = [
{
"description" : "Proximity + Beyond proximity => Does not snap to point (Down)",
"scrollSnapType" : "proximity",
"scrollSnapType" : "both proximity",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -139,7 +139,7 @@ var testCases = [
{
"description" : "Mandatory + Beyond proximity => Snaps to point (Right)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -154,7 +154,7 @@ var testCases = [
{
"description" : "Mandatory + Beyond proximity => Snaps to point (Left)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -169,7 +169,7 @@ var testCases = [
{
"description" : "Mandatory + Beyond proximity => Snaps to point (Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -184,7 +184,7 @@ var testCases = [
{
"description" : "Mandatory + Beyond proximity => Snaps to point (Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -199,7 +199,7 @@ var testCases = [
{
"description" : "Mandatory + No snap points => Does not snap or scroll (Left)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -214,7 +214,7 @@ var testCases = [
{
"description" : "Mandatory + No snap points => Does not snap or scroll (Right)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -229,7 +229,7 @@ var testCases = [
{
"description" : "Mandatory + No snap points => Does not snap or scroll (Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -244,7 +244,7 @@ var testCases = [
{
"description" : "Mandatory + No snap points => Does not snap or scroll (Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -259,7 +259,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + scroll-snap-destination + Start of page + No snap point at start of page => Does not snap to top of page (Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "25px 25px",
@ -274,7 +274,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + scroll-snap-destination + Start of page + No snap point at start of page => Does not snap to top of page (Page Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "25px 25px",
@ -289,7 +289,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + scroll-snap-destination + Start of page + No snap point at start of page => Snaps to highest snap point (Home)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "25px 25px",
@ -304,7 +304,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-x + scroll-snap-destination + Start of page + No snap point at start of page => Does not snap to left of page (Left)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(500px)",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "25px 25px",
@ -319,7 +319,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + negative scroll-snap-destination + End of page + No snap point at end of page => Does not snap to end of page (Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "-25px -25px",
@ -334,7 +334,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + negative scroll-snap-destination + End of page + No snap point at end of page => Does not snap to end of page (Page Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "-25px -25px",
@ -349,7 +349,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y + negative scroll-snap-destination + End of page + No snap point at end of page => Snaps to lowest snap point (End)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(500px)",
"scrollSnapDestination" : "-25px -25px",
@ -364,7 +364,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-coordinate + No snap point at start of page => Does not snap to top of page (Home)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -379,7 +379,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-coordinate + No snap point at end of page => Does not snap to end of page (End)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -394,7 +394,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y greater than scrolling rect + positive non-zero scroll-snap-destination => No snap points, does not scroll or snap (Left)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(1500px)",
"scrollSnapDestination" : "25px 25px",
@ -409,7 +409,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y greater than scrolling rect + positive non-zero scroll-snap-destination => No snap points, does not scroll or snap (Right)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(1500px)",
"scrollSnapDestination" : "25px 25px",
@ -424,7 +424,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y greater than scrolling rect + positive non-zero scroll-snap-destination => No snap points, does not scroll or snap (Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(1500px)",
"scrollSnapDestination" : "25px 25px",
@ -439,7 +439,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-y greater than scrolling rect + positive non-zero scroll-snap-destination => No snap points, does not scroll or snap (Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "repeat(1500px)",
"scrollSnapDestination" : "25px 25px",
@ -454,7 +454,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Right #1)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -469,7 +469,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Right #2)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -485,7 +485,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Right #3)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -500,7 +500,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Up #1)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -515,7 +515,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Up #2)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -530,7 +530,7 @@ var testCases = [
{
"description" : "Mandatory + scroll-snap-points-{x|y} + scroll-snap-coordinate with two points => Interval and element snapping points are combined. Test 1 snap point generated by scroll-snap-points-{x|y} and two generated by scroll-snap-coordinate, ensure that they are evaluated as snap points. (Up #3)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "repeat(200px)",
"scrollSnapPointsY" : "repeat(200px)",
"scrollSnapDestination" : "0px 0px",
@ -545,7 +545,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the next snap point in the direction of the scroll is selected rather than a closer point in the opposite direction (page Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -560,7 +560,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the next snap point in the direction of the scroll is selected rather than a closer point in the opposite direction (Page Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -575,7 +575,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the farthest snap point before the destination is selected and prioritized over a snap point that is past the destination, even if the snap point past the destination is closer to the destination. Setup - two snap points between current position and destination and one snap point past the destination which is closer than any of the other points. Scrollable rect size is 500px. (Page Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -590,7 +590,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the farthest snap point before the destination is selected and prioritized over a snap point that is past the destination, even if the snap point past the destination is closer to the destination. Setup - two snap points between current position and destination and one snap point past the destination which is closer than any of the other points. Scrollable rect size is 500px. (Page Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -605,7 +605,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the closest snap point past the destination is selected when no snap points exist between the starting position and the destination. Additionally, a snap point closer to the destination than the one past the snap point, but not in the scrolling direction, must not be selected. Setup - Two snap points beyond the destination and one snap point in the opposite direction of scrolling which is closest to the destination. Scrollable rect size is 500px. (Page Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -620,7 +620,7 @@ var testCases = [
{
"description" : "Ensure that when paging down/up that the closest snap point past the destination is selected when no snap points exist between the starting position and the destination. Additionally, a snap point closer to the destination than the one past the snap point, but not in the scrolling direction, must not be selected. Setup - Two snap points beyond the destination and one snap point in the opposite direction of scrolling which is closest to the destination. Scrollable rect size is 500px. (Page Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -635,7 +635,7 @@ var testCases = [
{
"description" : "Ensure that when scrolling by lines up,down,left,or right, that the closest snap point to the destination in the direction of travel is selected. Setup - Two snap points in the direction of travel and one in the opposite direction. Snap point in opposite direction is closest to the destination but must not be selected. (Down)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -650,7 +650,7 @@ var testCases = [
{
"description" : "Ensure that when scrolling by lines up,down,left,or right, that the closest snap point to the destination in the direction of travel is selected. Setup - Two snap points in the direction of travel and one in the opposite direction. Snap point in opposite direction is closest to the destination but must not be selected. (Up)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -665,7 +665,7 @@ var testCases = [
{
"description" : "Ensure that when scrolling by lines up,down,left,or right, that the closest snap point to the destination in the direction of travel is selected. Setup - Two snap points in the direction of travel and one in the opposite direction. Snap point in opposite direction is closest to the destination but must not be selected. (Left)",
"scrollSnapType" : "mandatory",
"scrollSnapType" : "both mandatory",
"scrollSnapPointsX" : "none",
"scrollSnapPointsY" : "none",
"scrollSnapDestination" : "0px 0px",
@ -793,6 +793,7 @@ function testScrolling() {
function doTest() {
SpecialPowers.pushPrefEnv({
"set": [["layout.css.scroll-snap.enabled", true],
["layout.css.scroll-snap-v1.enabled", false],
["layout.css.scroll-snap.proximity-threshold", 100]]},
testScrollSnapping);
}

Просмотреть файл

@ -243,7 +243,7 @@ function doTest() {
lastScrollLeft = sc.scrollLeft;
sc.scrollTo(testCase.startScroll.x, testCase.startScroll.y);
sc.style.scrollSnapType = "mandatory";
sc.style.scrollSnapType = "both mandatory";
sd.style.scrollSnapCoordinate = testCase.snapCoord;
synthesizeMouse(sc,
@ -343,6 +343,7 @@ addLoadEvent(function() {
sd = document.getElementById("sd");
SpecialPowers.pushPrefEnv({
"set": [["layout.css.scroll-snap.enabled", true],
["layout.css.scroll-snap-v1.enabled", false],
["layout.css.scroll-snap.proximity-threshold", 100]]},
doTest);
});

Просмотреть файл

@ -1816,7 +1816,8 @@ void nsListControlFrame::ScrollToFrame(dom::HTMLOptionElement& aOptElement) {
childFrame, nsRect(nsPoint(0, 0), childFrame->GetSize()),
nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis(),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN |
nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY);
nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING);
}
}

Просмотреть файл

@ -32,12 +32,18 @@ class CalcSnapPoints final {
nscoord aOffset);
void AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos,
nscoord aScrollingDirection, nscoord* aBestEdge,
bool* aEdgeFound);
nscoord* aSecondBestEdge, bool* aEdgeFound);
void AddEdgeInterval(nscoord aInterval, nscoord aMinPos, nscoord aMaxPos,
nscoord aOffset, nscoord aDestination, nscoord aStartPos,
nscoord aScrollingDirection, nscoord* aBestEdge,
bool* aEdgeFound);
nscoord* aSecondBestEdge, bool* aEdgeFound);
nsPoint GetBestEdge() const;
nscoord XDistanceBetweenBestAndSecondEdge() const {
return std::abs(mBestEdge.x - mSecondBestEdge.x);
}
nscoord YDistanceBetweenBestAndSecondEdge() const {
return std::abs(mBestEdge.y - mSecondBestEdge.y);
}
protected:
nsIScrollableFrame::ScrollUnit mUnit;
@ -46,6 +52,8 @@ class CalcSnapPoints final {
nsPoint mStartPos; // gives the position before scrolling
nsIntPoint mScrollingDirection; // always -1, 0, or 1
nsPoint mBestEdge; // keeps track of the position of the current best edge
nsPoint mSecondBestEdge; // keeps track of the position of the current
// second best edge
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid
// horizontal edge
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical
@ -74,6 +82,7 @@ CalcSnapPoints::CalcSnapPoints(nsIScrollableFrame::ScrollUnit aUnit,
mScrollingDirection.y = 1;
}
mBestEdge = aDestination;
mSecondBestEdge = nsPoint(nscoord_MAX, nscoord_MAX);
mHorizontalEdgeFound = false;
mVerticalEdgeFound = false;
}
@ -85,12 +94,12 @@ nsPoint CalcSnapPoints::GetBestEdge() const {
void CalcSnapPoints::AddHorizontalEdge(nscoord aEdge) {
AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y,
&mBestEdge.y, &mHorizontalEdgeFound);
&mBestEdge.y, &mSecondBestEdge.y, &mHorizontalEdgeFound);
}
void CalcSnapPoints::AddVerticalEdge(nscoord aEdge) {
AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x,
&mBestEdge.x, &mVerticalEdgeFound);
&mBestEdge.x, &mSecondBestEdge.x, &mVerticalEdgeFound);
}
void CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect& aScrollRange,
@ -98,7 +107,7 @@ void CalcSnapPoints::AddHorizontalEdgeInterval(const nsRect& aScrollRange,
nscoord aOffset) {
AddEdgeInterval(aInterval, aScrollRange.y, aScrollRange.YMost(), aOffset,
mDestination.y, mStartPos.y, mScrollingDirection.y,
&mBestEdge.y, &mHorizontalEdgeFound);
&mBestEdge.y, &mSecondBestEdge.y, &mHorizontalEdgeFound);
}
void CalcSnapPoints::AddVerticalEdgeInterval(const nsRect& aScrollRange,
@ -106,12 +115,13 @@ void CalcSnapPoints::AddVerticalEdgeInterval(const nsRect& aScrollRange,
nscoord aOffset) {
AddEdgeInterval(aInterval, aScrollRange.x, aScrollRange.XMost(), aOffset,
mDestination.x, mStartPos.x, mScrollingDirection.x,
&mBestEdge.x, &mVerticalEdgeFound);
&mBestEdge.x, &mSecondBestEdge.x, &mVerticalEdgeFound);
}
void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
nscoord aStartPos, nscoord aScrollingDirection,
nscoord* aBestEdge, bool* aEdgeFound) {
nscoord* aBestEdge, nscoord* aSecondBestEdge,
bool* aEdgeFound) {
// nsIScrollableFrame::DEVICE_PIXELS indicates that we are releasing a drag
// gesture or any other user input event that sets an absolute scroll
// position. In this case, scroll snapping is expected to travel in any
@ -144,11 +154,27 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
*aEdgeFound = true;
return;
}
// A utility function to update the best and the second best edges in the
// given conditions.
// |aIsCloserThanBest| True if the current candidate is closer than the best
// edge.
// |aIsCloserThanSecond| True if the current candidate is closer than
// the second best edge.
auto updateBestEdges = [&](bool aIsCloserThanBest, bool aIsCloserThanSecond) {
if (aIsCloserThanBest) {
*aSecondBestEdge = *aBestEdge;
*aBestEdge = aEdge;
} else if (aIsCloserThanSecond) {
*aSecondBestEdge = aEdge;
}
};
if (mUnit == nsIScrollableFrame::DEVICE_PIXELS ||
mUnit == nsIScrollableFrame::LINES) {
if (std::abs(aEdge - aDestination) < std::abs(*aBestEdge - aDestination)) {
*aBestEdge = aEdge;
}
nscoord distance = std::abs(aEdge - aDestination);
updateBestEdges(distance < std::abs(*aBestEdge - aDestination),
distance < std::abs(*aSecondBestEdge - aDestination));
} else if (mUnit == nsIScrollableFrame::PAGES) {
// distance to the edge from the scrolling destination in the direction of
// scrolling
@ -157,23 +183,27 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
// direction of scrolling
nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection;
nscoord secondOvershoot =
(*aSecondBestEdge - aDestination) * aScrollingDirection;
// edges between the current position and the scrolling destination are
// favoured to preserve context
if (overshoot < 0 && (overshoot > curOvershoot || curOvershoot >= 0)) {
*aBestEdge = aEdge;
if (overshoot < 0) {
updateBestEdges(overshoot > curOvershoot || curOvershoot >= 0,
overshoot > secondOvershoot || secondOvershoot >= 0);
}
// if there are no edges between the current position and the scrolling
// destination the closest edge beyond the destination is used
if (overshoot > 0 && overshoot < curOvershoot) {
*aBestEdge = aEdge;
if (overshoot > 0) {
updateBestEdges(overshoot < curOvershoot, overshoot < secondOvershoot);
}
} else if (mUnit == nsIScrollableFrame::WHOLE) {
// the edge closest to the top/bottom/left/right is used, depending on
// scrolling direction
if (aScrollingDirection > 0 && aEdge > *aBestEdge) {
*aBestEdge = aEdge;
} else if (aScrollingDirection < 0 && aEdge < *aBestEdge) {
*aBestEdge = aEdge;
if (aScrollingDirection > 0) {
updateBestEdges(aEdge > *aBestEdge, aEdge > *aSecondBestEdge);
} else if (aScrollingDirection < 0) {
updateBestEdges(aEdge < *aBestEdge, aEdge < *aSecondBestEdge);
}
} else {
NS_ERROR("Invalid scroll mode");
@ -181,11 +211,10 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
}
}
void CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
nscoord aMaxPos, nscoord aOffset,
nscoord aDestination, nscoord aStartPos,
nscoord aScrollingDirection,
nscoord* aBestEdge, bool* aEdgeFound) {
void CalcSnapPoints::AddEdgeInterval(
nscoord aInterval, nscoord aMinPos, nscoord aMaxPos, nscoord aOffset,
nscoord aDestination, nscoord aStartPos, nscoord aScrollingDirection,
nscoord* aBestEdge, nscoord* aSecondBestEdge, bool* aEdgeFound) {
if (aInterval == 0) {
// When interval is 0, there are no scroll snap points.
// Avoid division by zero and bail.
@ -210,12 +239,22 @@ void CalcSnapPoints::AddEdgeInterval(nscoord aInterval, nscoord aMinPos,
nscoord edge = clamped - r;
if (edge >= aMinPos && edge <= aMaxPos) {
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
aEdgeFound);
aSecondBestEdge, aEdgeFound);
}
edge += aInterval;
if (edge >= aMinPos && edge <= aMaxPos) {
AddEdge(edge, aDestination, aStartPos, aScrollingDirection, aBestEdge,
aEdgeFound);
aSecondBestEdge, aEdgeFound);
}
}
static void ProcessSnapPositions(CalcSnapPoints& aCalcSnapPoints,
const ScrollSnapInfo& aSnapInfo) {
for (auto position : aSnapInfo.mSnapPositionX) {
aCalcSnapPoints.AddVerticalEdge(position);
}
for (auto position : aSnapInfo.mSnapPositionY) {
aCalcSnapPoints.AddHorizontalEdge(position);
}
}
@ -236,37 +275,65 @@ Maybe<nsPoint> ScrollSnapUtils::GetSnapPointForDestination(
const ScrollSnapInfo& aSnapInfo, nsIScrollableFrame::ScrollUnit aUnit,
const nsRect& aScrollRange, const nsPoint& aStartPos,
const nsPoint& aDestination) {
if (aSnapInfo.mScrollSnapTypeY == StyleScrollSnapType::None &&
aSnapInfo.mScrollSnapTypeX == StyleScrollSnapType::None) {
if (aSnapInfo.mScrollSnapTypeY == StyleScrollSnapStrictness::None &&
aSnapInfo.mScrollSnapTypeX == StyleScrollSnapStrictness::None) {
return Nothing();
}
nsPoint destPos = aSnapInfo.mScrollSnapDestination;
CalcSnapPoints calcSnapPoints(aUnit, aDestination, aStartPos);
if (aSnapInfo.mScrollSnapIntervalX.isSome()) {
nscoord interval = aSnapInfo.mScrollSnapIntervalX.value();
calcSnapPoints.AddVerticalEdgeInterval(aScrollRange, interval, destPos.x);
}
if (aSnapInfo.mScrollSnapIntervalY.isSome()) {
nscoord interval = aSnapInfo.mScrollSnapIntervalY.value();
calcSnapPoints.AddHorizontalEdgeInterval(aScrollRange, interval, destPos.y);
if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) {
ProcessSnapPositions(calcSnapPoints, aSnapInfo);
// If the distance between the first and the second candidate snap points
// is larger than the snapport size and the snapport is covered by larger
// elements, any points inside the covering area should be valid snap
// points.
// https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow
for (auto range : aSnapInfo.mXRangeWiderThanSnapport) {
if (range.IsValid(aDestination.x, aSnapInfo.mSnapportSize.width) &&
calcSnapPoints.XDistanceBetweenBestAndSecondEdge() >
aSnapInfo.mSnapportSize.width) {
calcSnapPoints.AddVerticalEdge(aDestination.x);
break;
}
}
for (auto range : aSnapInfo.mYRangeWiderThanSnapport) {
if (range.IsValid(aDestination.y, aSnapInfo.mSnapportSize.height) &&
calcSnapPoints.YDistanceBetweenBestAndSecondEdge() >
aSnapInfo.mSnapportSize.height) {
calcSnapPoints.AddHorizontalEdge(aDestination.y);
break;
}
}
} else {
nsPoint destPos = aSnapInfo.mScrollSnapDestination;
if (aSnapInfo.mScrollSnapIntervalX.isSome()) {
nscoord interval = aSnapInfo.mScrollSnapIntervalX.value();
calcSnapPoints.AddVerticalEdgeInterval(aScrollRange, interval, destPos.x);
}
if (aSnapInfo.mScrollSnapIntervalY.isSome()) {
nscoord interval = aSnapInfo.mScrollSnapIntervalY.value();
calcSnapPoints.AddHorizontalEdgeInterval(aScrollRange, interval,
destPos.y);
}
ProcessScrollSnapCoordinates(calcSnapPoints,
aSnapInfo.mScrollSnapCoordinates, destPos);
}
ProcessScrollSnapCoordinates(calcSnapPoints, aSnapInfo.mScrollSnapCoordinates,
destPos);
bool snapped = false;
nsPoint finalPos = calcSnapPoints.GetBestEdge();
nscoord proximityThreshold = gfxPrefs::ScrollSnapProximityThreshold();
proximityThreshold = nsPresContext::CSSPixelsToAppUnits(proximityThreshold);
if (aSnapInfo.mScrollSnapTypeY == StyleScrollSnapType::Proximity &&
if (aSnapInfo.mScrollSnapTypeY == StyleScrollSnapStrictness::Proximity &&
std::abs(aDestination.y - finalPos.y) > proximityThreshold) {
finalPos.y = aDestination.y;
} else {
snapped = true;
}
if (aSnapInfo.mScrollSnapTypeX == StyleScrollSnapType::Proximity &&
if (aSnapInfo.mScrollSnapTypeX == StyleScrollSnapStrictness::Proximity &&
std::abs(aDestination.x - finalPos.x) > proximityThreshold) {
finalPos.x = aDestination.x;
} else {

Просмотреть файл

@ -14,7 +14,7 @@
try { computed.getPropertyValue('quotes') } catch (e) {}
try { header_0.style.setProperty('scroll-behavior', 'smooth', undefined) } catch (e) {}
try { window.scrollBy(256, 1) } catch (e) {}
try { header_0.style.setProperty('scroll-snap-type', 'mandatory', '') } catch (e) {}
try { header_0.style.setProperty('scroll-snap-type', 'both mandatory', '') } catch (e) {}
try { header_0.getClientRects() } catch (e) {}
try { style_1.sheet.insertRule('i { }', undefined) } catch (e) {}
}

Просмотреть файл

@ -2186,31 +2186,47 @@ void ScrollFrameHelper::ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
ScrollToWithOrigin(aScrollPosition, aMode, aOrigin, aRange, aSnap);
}
void ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
ScrollMode aMode, nsAtom* aOrigin) {
static nsIScrollbarMediator::ScrollSnapMode DefaultSnapMode() {
return StaticPrefs::layout_css_scroll_snap_v1_enabled()
? nsIScrollableFrame::ENABLE_SNAP
: nsIScrollableFrame::DISABLE_SNAP;
}
void ScrollFrameHelper::ScrollToCSSPixels(
const CSSIntPoint& aScrollPosition, ScrollMode aMode,
nsIScrollbarMediator::ScrollSnapMode aSnap, nsAtom* aOrigin) {
nsPoint current = GetScrollPosition();
CSSIntPoint currentCSSPixels = GetScrollPositionCSSPixels();
nsPoint pt = CSSPoint::ToAppUnits(aScrollPosition);
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
2 * halfPixel - 1);
// XXX I don't think the following blocks are needed anymore, now that
// ScrollToImpl simply tries to scroll an integer number of layer
// pixels from the current position
if (currentCSSPixels.x == aScrollPosition.x) {
pt.x = current.x;
range.x = pt.x;
range.width = 0;
if (aSnap == nsIScrollableFrame::DEFAULT) {
aSnap = DefaultSnapMode();
}
if (currentCSSPixels.y == aScrollPosition.y) {
pt.y = current.y;
range.y = pt.y;
range.height = 0;
nsRect range;
if (aSnap != nsIScrollableFrame::ENABLE_SNAP) {
range = nsRect(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
2 * halfPixel - 1);
// XXX I don't think the following blocks are needed anymore, now that
// ScrollToImpl simply tries to scroll an integer number of layer
// pixels from the current position
if (currentCSSPixels.x == aScrollPosition.x) {
pt.x = current.x;
range.x = pt.x;
range.width = 0;
}
if (currentCSSPixels.y == aScrollPosition.y) {
pt.y = current.y;
range.y = pt.y;
range.height = 0;
}
}
if (aOrigin == nullptr) {
aOrigin = nsGkAtoms::other;
}
ScrollTo(pt, aMode, aOrigin, &range);
ScrollTo(pt, aMode, aOrigin,
aSnap == nsIScrollableFrame::ENABLE_SNAP ? nullptr : &range, aSnap);
// 'this' might be destroyed here
}
@ -4034,7 +4050,7 @@ ScrollStyles ScrollFrameHelper::GetScrollStylesFromFrame() const {
if (!mIsRoot) {
const nsStyleDisplay* disp = mOuter->StyleDisplay();
return ScrollStyles(disp);
return ScrollStyles(mOuter->GetWritingMode(), disp);
}
ScrollStyles result = presContext->GetViewportScrollStylesOverride();
@ -4211,8 +4227,9 @@ void ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
ScrollStyles styles = GetScrollStylesFromFrame();
if (styles.mScrollSnapTypeY != StyleScrollSnapType::None ||
styles.mScrollSnapTypeX != StyleScrollSnapType::None) {
if (styles.mScrollSnapTypeY != StyleScrollSnapStrictness::None ||
styles.mScrollSnapTypeX != StyleScrollSnapStrictness::None) {
nscoord appUnitsPerDevPixel =
mOuter->PresContext()->AppUnitsPerDevPixel();
deltaMultiplier = nsSize(appUnitsPerDevPixel, appUnitsPerDevPixel);
@ -4259,31 +4276,41 @@ void ScrollFrameHelper::ScrollBy(nsIntPoint aDelta,
}
}
void ScrollFrameHelper::ScrollByCSSPixels(const CSSIntPoint& aDelta,
ScrollMode aMode, nsAtom* aOrigin) {
void ScrollFrameHelper::ScrollByCSSPixels(
const CSSIntPoint& aDelta, ScrollMode aMode, nsAtom* aOrigin,
nsIScrollbarMediator::ScrollSnapMode aSnap) {
nsPoint current = GetScrollPosition();
nsPoint pt = current + CSSPoint::ToAppUnits(aDelta);
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
2 * halfPixel - 1);
// XXX I don't think the following blocks are needed anymore, now that
// ScrollToImpl simply tries to scroll an integer number of layer
// pixels from the current position
if (aDelta.x == 0.0f) {
pt.x = current.x;
range.x = pt.x;
range.width = 0;
if (aSnap == nsIScrollableFrame::DEFAULT) {
aSnap = DefaultSnapMode();
}
if (aDelta.y == 0.0f) {
pt.y = current.y;
range.y = pt.y;
range.height = 0;
nsRect range;
if (aSnap != nsIScrollableFrame::ENABLE_SNAP) {
range = nsRect(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
2 * halfPixel - 1);
// XXX I don't think the following blocks are needed anymore, now that
// ScrollToImpl simply tries to scroll an integer number of layer
// pixels from the current position
if (aDelta.x == 0.0f) {
pt.x = current.x;
range.x = pt.x;
range.width = 0;
}
if (aDelta.y == 0.0f) {
pt.y = current.y;
range.y = pt.y;
range.height = 0;
}
}
if (aOrigin == nullptr) {
aOrigin = nsGkAtoms::other;
}
ScrollToWithOrigin(pt, aMode, aOrigin, &range,
nsIScrollbarMediator::DISABLE_SNAP);
ScrollToWithOrigin(
pt, aMode, aOrigin,
aSnap == nsIScrollableFrame::ENABLE_SNAP ? nullptr : &range, aSnap);
// 'this' might be destroyed here
}
@ -6492,6 +6519,183 @@ uint32_t nsIScrollableFrame::GetPerceivedScrollingDirections() const {
return directions;
}
static nsRect InflateByScrollMargin(const nsRect& aTargetRect,
const nsMargin& aScrollMargin,
const nsRect& aScrolledRect) {
// Inflate the rect by scroll-margin.
nsRect result = aTargetRect;
result.Inflate(aScrollMargin);
// But don't be beyond the limit boundary.
return result.Intersect(aScrolledRect);
}
/**
* Append scroll positions for valid snap positions into |aSnapInfo| if
* applicable.
*/
static void AppendScrollPositionsForSnap(const nsIFrame* aFrame,
const nsIFrame* aScrolledFrame,
const nsRect& aScrolledRect,
const nsMargin& aScrollPadding,
const Maybe<nsRect>& aSnapport,
ScrollSnapInfo& aSnapInfo) {
nsRect targetRect = nsLayoutUtils::TransformFrameRectToAncestor(
aFrame, aFrame->GetRectRelativeToSelf(), aScrolledFrame);
// Ignore elements outside of the snapport when we scroll to the given
// destination.
// https://drafts.csswg.org/css-scroll-snap-1/#snap-scope
if (aSnapport && !aSnapport->Intersects(targetRect)) {
return;
}
// These snap range shouldn't be involved with scroll-margin since we just
// need the visible range of the target element.
if (targetRect.width > aSnapInfo.mSnapportSize.width) {
aSnapInfo.mXRangeWiderThanSnapport.AppendElement(
ScrollSnapInfo::ScrollSnapRange(targetRect.X(), targetRect.XMost()));
}
if (targetRect.height > aSnapInfo.mSnapportSize.height) {
aSnapInfo.mYRangeWiderThanSnapport.AppendElement(
ScrollSnapInfo::ScrollSnapRange(targetRect.Y(), targetRect.YMost()));
}
nsMargin scrollMargin = aFrame->StyleMargin()->GetScrollMargin();
targetRect = InflateByScrollMargin(targetRect, scrollMargin, aScrolledRect);
// Shift target rect position by the scroll padding to get the padded
// position thus we don't need to take account scroll-padding values in
// ScrollSnapUtils::GetSnapPointForDestination() when it gets called from
// the compositor thread.
targetRect.y -= aScrollPadding.top;
targetRect.x -= aScrollPadding.left;
WritingMode writingMode = aScrolledFrame->GetWritingMode();
LogicalRect logicalTargetRect(writingMode, targetRect,
aSnapInfo.mSnapportSize);
LogicalSize logicalSnapportRect(writingMode, aSnapInfo.mSnapportSize);
Maybe<nscoord> blockDirectionPosition;
Maybe<nscoord> inlineDirectionPosition;
const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
nscoord containerBSize = logicalSnapportRect.BSize(writingMode);
switch (styleDisplay->mScrollSnapAlign.block) {
case StyleScrollSnapAlignKeyword::None:
break;
case StyleScrollSnapAlignKeyword::Start:
blockDirectionPosition.emplace(logicalTargetRect.BStart(writingMode));
break;
case StyleScrollSnapAlignKeyword::End:
if (writingMode.IsVerticalRL()) {
blockDirectionPosition.emplace(containerBSize -
logicalTargetRect.BEnd(writingMode));
} else {
// What we need here is the scroll position instead of the snap position
// itself, so we need, for example, the top edge of the scroll port
// on horizontal-tb when the frame is positioned at the bottom edge of
// the scroll port. For this reason we subtract containerBSize from
// BEnd of the target.
blockDirectionPosition.emplace(logicalTargetRect.BEnd(writingMode) -
containerBSize);
}
break;
case StyleScrollSnapAlignKeyword::Center: {
nscoord targetCenter = (logicalTargetRect.BStart(writingMode) +
logicalTargetRect.BEnd(writingMode)) /
2;
nscoord halfSnapportSize = containerBSize / 2;
// Get the center of the target to align with the center of the snapport
// depending on direction.
if (writingMode.IsVerticalRL()) {
blockDirectionPosition.emplace(halfSnapportSize - targetCenter);
} else {
blockDirectionPosition.emplace(targetCenter - halfSnapportSize);
}
break;
}
}
nscoord containerISize = logicalSnapportRect.ISize(writingMode);
switch (styleDisplay->mScrollSnapAlign.inline_) {
case StyleScrollSnapAlignKeyword::None:
break;
case StyleScrollSnapAlignKeyword::Start:
inlineDirectionPosition.emplace(logicalTargetRect.IStart(writingMode));
break;
case StyleScrollSnapAlignKeyword::End:
if (writingMode.IsInlineReversed()) {
inlineDirectionPosition.emplace(containerISize -
logicalTargetRect.IEnd(writingMode));
} else {
// Same as above BEnd case, we subtract containerISize.
inlineDirectionPosition.emplace(logicalTargetRect.IEnd(writingMode) -
containerISize);
}
break;
case StyleScrollSnapAlignKeyword::Center: {
nscoord targetCenter = (logicalTargetRect.IStart(writingMode) +
logicalTargetRect.IEnd(writingMode)) /
2;
nscoord halfSnapportSize = containerISize / 2;
// Get the center of the target to align with the center of the snapport
// depending on direction.
if (writingMode.IsInlineReversed()) {
inlineDirectionPosition.emplace(halfSnapportSize - targetCenter);
} else {
inlineDirectionPosition.emplace(targetCenter - halfSnapportSize);
}
break;
}
}
if (inlineDirectionPosition) {
(writingMode.IsVertical() ? aSnapInfo.mSnapPositionY
: aSnapInfo.mSnapPositionX)
.AppendElement(inlineDirectionPosition.value());
}
if (blockDirectionPosition) {
(writingMode.IsVertical() ? aSnapInfo.mSnapPositionX
: aSnapInfo.mSnapPositionY)
.AppendElement(blockDirectionPosition.value());
}
}
/**
* Collect the scroll positions corresponding to snap positions of frames in the
* subtree rooted at |aFrame|, relative to |aScrolledFrame|, into |aSnapInfo|.
* If |aSnapport| is given, elements outside of the range of |aSnapport| will be
* ignored.
*/
static void CollectScrollPositionsForSnap(nsIFrame* aFrame,
nsIFrame* aScrolledFrame,
const nsRect& aScrolledRect,
const nsMargin& aScrollPadding,
const Maybe<nsRect>& aSnapport,
ScrollSnapInfo& aSnapInfo) {
MOZ_ASSERT(StaticPrefs::layout_css_scroll_snap_v1_enabled());
nsIFrame::ChildListIterator childLists(aFrame);
for (; !childLists.IsDone(); childLists.Next()) {
nsFrameList::Enumerator childFrames(childLists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* f = childFrames.get();
const nsStyleDisplay* styleDisplay = f->StyleDisplay();
if (styleDisplay->mScrollSnapAlign.inline_ !=
StyleScrollSnapAlignKeyword::None ||
styleDisplay->mScrollSnapAlign.block !=
StyleScrollSnapAlignKeyword::None) {
AppendScrollPositionsForSnap(f, aScrolledFrame, aScrolledRect,
aScrollPadding, aSnapport, aSnapInfo);
}
CollectScrollPositionsForSnap(f, aScrolledFrame, aScrolledRect,
aScrollPadding, aSnapport, aSnapInfo);
}
}
}
/**
* Collect the scroll-snap-coordinates of frames in the subtree rooted at
* |aFrame|, relative to |aScrolledFrame|, into |aOutCoords|.
@ -6499,6 +6703,8 @@ uint32_t nsIScrollableFrame::GetPerceivedScrollingDirections() const {
static void CollectScrollSnapCoordinates(nsIFrame* aFrame,
nsIFrame* aScrolledFrame,
nsTArray<nsPoint>& aOutCoords) {
MOZ_ASSERT(!StaticPrefs::layout_css_scroll_snap_v1_enabled());
nsIFrame::ChildListIterator childLists(aFrame);
for (; !childLists.IsDone(); childLists.Next()) {
nsFrameList::Enumerator childFrames(childLists.CurrentList());
@ -6529,14 +6735,70 @@ static void CollectScrollSnapCoordinates(nsIFrame* aFrame,
}
}
static layers::ScrollSnapInfo ComputeScrollSnapInfo(
const ScrollFrameHelper& aScrollFrame) {
static nscoord ResolveScrollPaddingStyleValue(
const StyleRect<mozilla::NonNegativeLengthPercentageOrAuto>&
aScrollPaddingStyle,
Side aSide, const nsSize& aScrollPortSize) {
if (aScrollPaddingStyle.Get(aSide).IsAuto()) {
// https://drafts.csswg.org/css-scroll-snap-1/#valdef-scroll-padding-auto
return 0;
}
nscoord percentageBasis;
switch (aSide) {
case eSideTop:
case eSideBottom:
percentageBasis = aScrollPortSize.height;
break;
case eSideLeft:
case eSideRight:
percentageBasis = aScrollPortSize.width;
break;
}
return aScrollPaddingStyle.Get(aSide).AsLengthPercentage().Resolve(
percentageBasis);
}
static nsMargin ResolveScrollPaddingStyle(
const StyleRect<mozilla::NonNegativeLengthPercentageOrAuto>&
aScrollPaddingStyle,
const nsSize& aScrollPortSize) {
return nsMargin(ResolveScrollPaddingStyleValue(aScrollPaddingStyle, eSideTop,
aScrollPortSize),
ResolveScrollPaddingStyleValue(aScrollPaddingStyle,
eSideRight, aScrollPortSize),
ResolveScrollPaddingStyleValue(aScrollPaddingStyle,
eSideBottom, aScrollPortSize),
ResolveScrollPaddingStyleValue(aScrollPaddingStyle, eSideLeft,
aScrollPortSize));
}
nsMargin ScrollFrameHelper::GetScrollPadding() const {
nsIFrame* styleFrame;
if (mIsRoot) {
const Element* scrollElement =
mOuter->PresContext()->GetViewportScrollStylesOverrideElement();
styleFrame = scrollElement ? scrollElement->GetPrimaryFrame() : mOuter;
} else {
styleFrame = mOuter;
}
MOZ_ASSERT(styleFrame);
// The spec says percentage values are relative to the scroll port size.
// https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding
return ResolveScrollPaddingStyle(styleFrame->StylePadding()->mScrollPadding,
GetScrollPortRect().Size());
}
layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo(
const Maybe<nsPoint>& aDestination) const {
ScrollSnapInfo result;
ScrollStyles styles = aScrollFrame.GetScrollStylesFromFrame();
ScrollStyles styles = GetScrollStylesFromFrame();
if (styles.mScrollSnapTypeY == StyleScrollSnapType::None &&
styles.mScrollSnapTypeX == StyleScrollSnapType::None) {
if (styles.mScrollSnapTypeY == StyleScrollSnapStrictness::None &&
styles.mScrollSnapTypeX == StyleScrollSnapStrictness::None) {
// We won't be snapping, short-circuit the computation.
return result;
}
@ -6544,7 +6806,7 @@ static layers::ScrollSnapInfo ComputeScrollSnapInfo(
result.mScrollSnapTypeX = styles.mScrollSnapTypeX;
result.mScrollSnapTypeY = styles.mScrollSnapTypeY;
nsSize scrollPortSize = aScrollFrame.GetScrollPortRect().Size();
nsSize scrollPortSize = GetScrollPortRect().Size();
result.mScrollSnapDestination =
nsPoint(styles.mScrollSnapDestinationX.Resolve(scrollPortSize.width),
@ -6561,24 +6823,49 @@ static layers::ScrollSnapInfo ComputeScrollSnapInfo(
scrollPortSize.height));
}
CollectScrollSnapCoordinates(aScrollFrame.GetScrolledFrame(),
aScrollFrame.GetScrolledFrame(),
if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) {
nsRect snapport = GetScrollPortRect();
nsMargin scrollPadding = GetScrollPadding();
Maybe<nsRect> snapportOnDestination;
if (aDestination) {
if (IsPhysicalLTR()) {
snapport.MoveTo(aDestination.value());
} else {
snapport.MoveTo(
nsPoint(aDestination->x - snapport.Size().width, aDestination->y));
}
snapport.Deflate(scrollPadding);
snapportOnDestination.emplace(snapport);
} else {
snapport.Deflate(scrollPadding);
}
result.mSnapportSize = snapport.Size();
CollectScrollPositionsForSnap(mScrolledFrame, mScrolledFrame,
GetScrolledRect(), scrollPadding,
snapportOnDestination, result);
return result;
}
CollectScrollSnapCoordinates(mScrolledFrame, mScrolledFrame,
result.mScrollSnapCoordinates);
return result;
}
layers::ScrollSnapInfo ScrollFrameHelper::GetScrollSnapInfo() const {
layers::ScrollSnapInfo ScrollFrameHelper::GetScrollSnapInfo(
const Maybe<nsPoint>& aDestination) const {
// TODO(botond): Should we cache it?
return ComputeScrollSnapInfo(*this);
return ComputeScrollSnapInfo(aDestination);
}
bool ScrollFrameHelper::GetSnapPointForDestination(
nsIScrollableFrame::ScrollUnit aUnit, nsPoint aStartPos,
nsPoint& aDestination) {
Maybe<nsPoint> snapPoint = ScrollSnapUtils::GetSnapPointForDestination(
GetScrollSnapInfo(), aUnit, GetLayoutScrollRange(), aStartPos,
aDestination);
GetScrollSnapInfo(Some(aDestination)), aUnit, GetLayoutScrollRange(),
aStartPos, aDestination);
if (snapPoint) {
aDestination = snapPoint.ref();
return true;

Просмотреть файл

@ -287,6 +287,8 @@ class ScrollFrameHelper : public nsIReflowCallback {
*/
void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
ScrollMode aMode = ScrollMode::eInstant,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT,
nsAtom* aOrigin = nullptr);
/**
* @note This method might destroy the frame, pres shell and other objects.
@ -313,7 +315,9 @@ class ScrollFrameHelper : public nsIReflowCallback {
nsIScrollbarMediator::DISABLE_SNAP);
void ScrollByCSSPixels(const CSSIntPoint& aDelta,
ScrollMode aMode = ScrollMode::eInstant,
nsAtom* aOrigin = nullptr);
nsAtom* aOrigin = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT);
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
@ -334,6 +338,8 @@ class ScrollFrameHelper : public nsIReflowCallback {
bool GetSnapPointForDestination(nsIScrollableFrame::ScrollUnit aUnit,
nsPoint aStartPos, nsPoint& aDestination);
nsMargin GetScrollPadding() const;
nsSize GetLineScrollAmount() const;
nsSize GetPageScrollAmount() const;
@ -405,6 +411,9 @@ class ScrollFrameHelper : public nsIReflowCallback {
nsIFrame* GetFrameForDir() const; // helper for Is{Physical,Bidi}LTR to find
// the frame whose directionality we use
ScrollSnapInfo ComputeScrollSnapInfo(
const Maybe<nsPoint>& aDestination) const;
public:
bool IsScrollbarOnRight() const;
bool IsScrollingActive(nsDisplayListBuilder* aBuilder) const;
@ -467,7 +476,11 @@ class ScrollFrameHelper : public nsIReflowCallback {
bool UsesContainerScrolling() const;
ScrollSnapInfo GetScrollSnapInfo() const;
// In the case where |aDestination| is given, elements which are entirely out
// of view when the scroll position is moved to |aDestination| are not going
// to be used for snap positions.
ScrollSnapInfo GetScrollSnapInfo(
const mozilla::Maybe<nsPoint>& aDestination) const;
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aVisibleRect, nsRect* aDirtyRect,
@ -948,6 +961,9 @@ class nsHTMLScrollFrame : public nsContainerFrame,
virtual nsSize GetPageScrollAmount() const override {
return mHelper.GetPageScrollAmount();
}
virtual nsMargin GetScrollPadding() const override {
return mHelper.GetScrollPadding();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
@ -962,8 +978,10 @@ class nsHTMLScrollFrame : public nsContainerFrame,
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
ScrollMode aMode = ScrollMode::eInstant,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aOrigin);
mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aSnap, aOrigin);
}
virtual void ScrollToCSSPixelsApproximate(
const mozilla::CSSPoint& aScrollPosition,
@ -990,8 +1008,10 @@ class nsHTMLScrollFrame : public nsContainerFrame,
}
virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
ScrollMode aMode = ScrollMode::eInstant,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin);
nsAtom* aOrigin = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT) override {
mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin, aSnap);
}
virtual void ScrollSnap() override { mHelper.ScrollSnap(); }
/**
@ -1172,7 +1192,7 @@ class nsHTMLScrollFrame : public nsContainerFrame,
}
ScrollSnapInfo GetScrollSnapInfo() const override {
return mHelper.GetScrollSnapInfo();
return mHelper.GetScrollSnapInfo(Nothing());
}
virtual bool DragScroll(mozilla::WidgetEvent* aEvent) override {
@ -1427,6 +1447,9 @@ class nsXULScrollFrame final : public nsBoxFrame,
virtual nsSize GetPageScrollAmount() const override {
return mHelper.GetPageScrollAmount();
}
virtual nsMargin GetScrollPadding() const override {
return mHelper.GetScrollPadding();
}
/**
* @note This method might destroy the frame, pres shell and other objects.
*/
@ -1440,8 +1463,10 @@ class nsXULScrollFrame final : public nsBoxFrame,
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
ScrollMode aMode = ScrollMode::eInstant,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DISABLE_SNAP,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aOrigin);
mHelper.ScrollToCSSPixels(aScrollPosition, aMode, aSnap, aOrigin);
}
virtual void ScrollToCSSPixelsApproximate(
const mozilla::CSSPoint& aScrollPosition,
@ -1465,8 +1490,10 @@ class nsXULScrollFrame final : public nsBoxFrame,
}
virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
ScrollMode aMode = ScrollMode::eInstant,
nsAtom* aOrigin = nullptr) override {
mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin);
nsAtom* aOrigin = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT) override {
mHelper.ScrollByCSSPixels(aDelta, aMode, aOrigin, aSnap);
}
virtual void ScrollSnap() override { mHelper.ScrollSnap(); }
/**
@ -1654,7 +1681,7 @@ class nsXULScrollFrame final : public nsBoxFrame,
}
ScrollSnapInfo GetScrollSnapInfo() const override {
return mHelper.GetScrollSnapInfo();
return mHelper.GetScrollSnapInfo(Nothing());
}
virtual bool DragScroll(mozilla::WidgetEvent* aEvent) override {

Просмотреть файл

@ -192,6 +192,10 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
*/
virtual nsSize GetPageScrollAmount() const = 0;
/**
* Return scroll-padding value of this frame.
*/
virtual nsMargin GetScrollPadding() const = 0;
/**
* Some platforms (OSX) may generate additional scrolling events even
* after the user has stopped scrolling, simulating a momentum scrolling
@ -230,9 +234,14 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
* range and / or moving in any direction; GetScrollPositionCSSPixels will be
* exactly aScrollPosition at the end of the scroll animation unless the
* SMOOTH_MSD animation is interrupted.
*
* FIXME: Drop |aSnap| argument once after we finished the migration to the
* Scroll Snap Module v1. We should alway use ENABLE_SNAP.
*/
virtual void ScrollToCSSPixels(const CSSIntPoint& aScrollPosition,
ScrollMode aMode = ScrollMode::eInstant,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT,
nsAtom* aOrigin = nullptr) = 0;
/**
* @note This method might destroy the frame, pres shell and other objects.
@ -271,9 +280,15 @@ class nsIScrollableFrame : public nsIScrollbarMediator {
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DISABLE_SNAP) = 0;
/**
* FIXME: Drop |aSnap| argument once after we finished the migration to the
* Scroll Snap Module v1. We should alway use ENABLE_SNAP.
*/
virtual void ScrollByCSSPixels(const CSSIntPoint& aDelta,
ScrollMode aMode = ScrollMode::eInstant,
nsAtom* aOrigin = nullptr) = 0;
nsAtom* aOrigin = nullptr,
nsIScrollbarMediator::ScrollSnapMode aSnap =
nsIScrollbarMediator::DEFAULT) = 0;
/**
* Perform scroll snapping, possibly resulting in a smooth scroll to

Просмотреть файл

@ -0,0 +1,4 @@
default-preferences pref(layout.css.scroll-snap-v1.enabled,true)
== scroll-margin-on-anchor.html#target scroll-margin-on-anchor-ref.html
== scroll-padding-on-anchor.html#target scroll-padding-on-anchor-ref.html

Просмотреть файл

@ -0,0 +1,16 @@
<style>
html,body {
overflow: hidden;
margin: 0px;
padding: 0px;
}
body {
margin-top: 100px;
}
#target {
background-color: blue;
width: 100%;
height: 100px;
}
</style>
<div id="target"></div>

Просмотреть файл

@ -0,0 +1,29 @@
<!--
This reftest is a test case that scroll-margin value is propery handled when
navigating an anchor node, id="target" in this case, so the content scrolls
to the target element on loading.
-->
<style>
html,body {
overflow: hidden;
margin: 0px;
padding: 0px;
}
.spacer {
height: 2000px;
width: 100%;
padding: 0px;
margin: 0px;
}
#target {
background-color: blue;
width: 100%;
height: 100px;
padding: 0px;
margin: 0px;
scroll-margin: 100px;
}
</style>
<div class="spacer"></div>
<div id="target"></div>
<div class="spacer"></div>

Просмотреть файл

@ -0,0 +1,16 @@
<style>
html,body {
overflow: hidden;
margin: 0px;
padding: 0px;
}
body {
padding-top: 100px;
}
#target {
background-color: blue;
width: 100%;
height: 100px;
}
</style>
<div id="target"></div>

Просмотреть файл

@ -0,0 +1,29 @@
<!--
This reftest is a test case that scroll-padding value is propery handled when
navigating an anchor node, id="target" in this case, so the content scrolls
to the target element on loading.
-->
<style>
html,body {
overflow: hidden;
scroll-padding: 100px;
margin: 0px;
padding: 0px;
}
.spacer {
height: 2000px;
width: 100%;
padding: 0px;
margin: 0px;
}
#target {
background-color: blue;
width: 100%;
height: 100px;
padding: 0px;
margin: 0px;
}
</style>
<div class="spacer"></div>
<div id="target"></div>
<div class="spacer"></div>

Просмотреть файл

@ -106,6 +106,9 @@ include css-ruby/reftest.list
# css required
include css-required/reftest.list
# css scroll snap
include css-scroll-snap/reftest.list
# css shapes
include css-shapes/reftest.list

Просмотреть файл

@ -413,6 +413,7 @@ cbindgen-types = [
{ gecko = "StyleBorderStyle", servo = "values::computed::BorderStyle" },
{ gecko = "StyleOutlineStyle", servo = "values::computed::OutlineStyle" },
{ gecko = "StyleScrollSnapAlign", servo = "values::computed::ScrollSnapAlign" },
{ gecko = "StyleScrollSnapStrictness", servo = "values::computed::ScrollSnapStrictness" },
{ gecko = "StyleScrollSnapType", servo = "values::computed::ScrollSnapType" },
{ gecko = "StyleResize", servo = "values::computed::Resize" },
{ gecko = "StyleOverflowClipBox", servo = "values::computed::OverflowClipBox" },

Просмотреть файл

@ -202,13 +202,25 @@ nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
nsChangeHint nsStyleMargin::CalcDifference(
const nsStyleMargin& aNewData) const {
if (mMargin == aNewData.mMargin) {
if (mMargin == aNewData.mMargin && mScrollMargin == aNewData.mScrollMargin) {
return nsChangeHint(0);
}
// Margin differences can't affect descendant intrinsic sizes and
// don't need to force children to reflow.
return nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition |
nsChangeHint_ClearAncestorIntrinsics;
nsChangeHint hint = nsChangeHint(0);
if (mMargin != aNewData.mMargin) {
// Margin differences can't affect descendant intrinsic sizes and
// don't need to force children to reflow.
hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition |
nsChangeHint_ClearAncestorIntrinsics;
}
if (mScrollMargin != aNewData.mScrollMargin) {
// FIXME: Bug 1530253 Support re-snapping when scroll-margin changes.
hint |= nsChangeHint_NeutralChange;
}
return hint;
}
nsStylePadding::nsStylePadding(const Document& aDocument)
@ -224,18 +236,31 @@ nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
nsChangeHint nsStylePadding::CalcDifference(
const nsStylePadding& aNewData) const {
if (mPadding == aNewData.mPadding) {
if (mPadding == aNewData.mPadding &&
mScrollPadding == aNewData.mScrollPadding) {
return nsChangeHint(0);
}
// Padding differences can't affect descendant intrinsic sizes, but do need
// to force children to reflow so that we can reposition them, since their
// offsets are from our frame bounds but our content rect's position within
// those bounds is moving.
// FIXME: It would be good to return a weaker hint here that doesn't
// force reflow of all descendants, but the hint would need to force
// reflow of the frame's children (see how
// ReflowInput::InitResizeFlags initializes the inline-resize flag).
return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
nsChangeHint hint = nsChangeHint(0);
if (mPadding != aNewData.mPadding) {
// Padding differences can't affect descendant intrinsic sizes, but do need
// to force children to reflow so that we can reposition them, since their
// offsets are from our frame bounds but our content rect's position within
// those bounds is moving.
// FIXME: It would be good to return a weaker hint here that doesn't
// force reflow of all descendants, but the hint would need to force
// reflow of the frame's children (see how
// ReflowInput::InitResizeFlags initializes the inline-resize flag).
hint |= NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
}
if (mScrollPadding != aNewData.mScrollPadding) {
// FIXME: Bug 1530253 Support re-snapping when scroll-padding changes.
hint |= nsChangeHint_NeutralChange;
}
return hint;
}
static nscoord TwipsPerPixel(const Document& aDocument) {
@ -2939,8 +2964,8 @@ nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
mOverscrollBehaviorX(StyleOverscrollBehavior::Auto),
mOverscrollBehaviorY(StyleOverscrollBehavior::Auto),
mOverflowAnchor(StyleOverflowAnchor::Auto),
mScrollSnapTypeX(StyleScrollSnapType::None),
mScrollSnapTypeY(StyleScrollSnapType::None),
mScrollSnapType(
{StyleScrollSnapAxis::Both, StyleScrollSnapStrictness::None}),
mScrollSnapPointsX(eStyleUnit_None),
mScrollSnapPointsY(eStyleUnit_None),
mScrollSnapDestination(
@ -3004,8 +3029,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
mScrollBehavior(aSource.mScrollBehavior),
mOverscrollBehaviorX(aSource.mOverscrollBehaviorX),
mOverscrollBehaviorY(aSource.mOverscrollBehaviorY),
mScrollSnapTypeX(aSource.mScrollSnapTypeX),
mScrollSnapTypeY(aSource.mScrollSnapTypeY),
mScrollSnapType(aSource.mScrollSnapType),
mScrollSnapPointsX(aSource.mScrollSnapPointsX),
mScrollSnapPointsY(aSource.mScrollSnapPointsY),
mScrollSnapDestination(aSource.mScrollSnapDestination),
@ -3145,8 +3169,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(
mContain != aNewData.mContain ||
(mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) ||
mScrollBehavior != aNewData.mScrollBehavior ||
mScrollSnapTypeX != aNewData.mScrollSnapTypeX ||
mScrollSnapTypeY != aNewData.mScrollSnapTypeY ||
mScrollSnapType != aNewData.mScrollSnapType ||
mScrollSnapPointsX != aNewData.mScrollSnapPointsX ||
mScrollSnapPointsY != aNewData.mScrollSnapPointsY ||
mScrollSnapDestination != aNewData.mScrollSnapDestination ||
@ -3167,6 +3190,11 @@ nsChangeHint nsStyleDisplay::CalcDifference(
return nsChangeHint_ReconstructFrame;
}
if (mScrollSnapAlign != aNewData.mScrollSnapAlign) {
// FIXME: Bug 1530253 Support re-snapping when scroll-snap-align changes.
hint |= nsChangeHint_NeutralChange;
}
if (mOverflowX != aNewData.mOverflowX || mOverflowY != aNewData.mOverflowY) {
hint |= nsChangeHint_ScrollbarChange;
}

Просмотреть файл

@ -714,6 +714,13 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin {
return true;
}
nsMargin GetScrollMargin() const {
return nsMargin(mScrollMargin.Get(mozilla::eSideTop).ToAppUnits(),
mScrollMargin.Get(mozilla::eSideRight).ToAppUnits(),
mScrollMargin.Get(mozilla::eSideBottom).ToAppUnits(),
mScrollMargin.Get(mozilla::eSideLeft).ToAppUnits());
}
// Return true if either the start or end side in the axis is 'auto'.
// (defined in WritingModes.h since we need the full WritingMode type)
inline bool HasBlockAxisAuto(mozilla::WritingMode aWM) const;
@ -1895,8 +1902,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
mozilla::StyleOverscrollBehavior mOverscrollBehaviorY;
mozilla::StyleOverflowAnchor mOverflowAnchor;
mozilla::StyleScrollSnapAlign mScrollSnapAlign;
mozilla::StyleScrollSnapType mScrollSnapTypeX;
mozilla::StyleScrollSnapType mScrollSnapTypeY;
mozilla::StyleScrollSnapType mScrollSnapType;
nsStyleCoord mScrollSnapPointsX;
nsStyleCoord mScrollSnapPointsY;
mozilla::Position mScrollSnapDestination;

Просмотреть файл

@ -7635,7 +7635,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.overscroll-behavior.enabled")) {
};
}
if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap.enabled")) {
if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap.enabled") &&
!IsCSSPropertyPrefEnabled("layout.css.scroll-snap-v1.enabled")) {
gCSSProperties["scroll-snap-coordinate"] = {
domProp: "scrollSnapCoordinate",
inherited: false,
@ -7690,31 +7691,26 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap.enabled")) {
gCSSProperties["scroll-snap-type"] = {
domProp: "scrollSnapType",
inherited: false,
type: CSS_TYPE_TRUE_SHORTHAND,
subproperties: [ "scroll-snap-type-x", "scroll-snap-type-y" ],
initial_values: [ "none" ],
other_values: [ "mandatory", "proximity" ],
invalid_values: [ "auto", "1px" ]
};
gCSSProperties["scroll-snap-type-x"] = {
domProp: "scrollSnapTypeX",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: ["mandatory", "proximity"],
invalid_values: [ "auto", "1px" ]
};
gCSSProperties["scroll-snap-type-y"] = {
domProp: "scrollSnapTypeY",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: ["mandatory", "proximity"],
other_values: [ "both mandatory", "both" ],
invalid_values: [ "auto", "1px" ]
};
}
if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap-v1.enabled")) {
gCSSProperties["scroll-snap-type"] = {
domProp: "scrollSnapType",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "both mandatory", "y mandatory", "inline proximity",
"both", "x", "y", "block", "inline" ],
invalid_values: [ "auto", "1px", "x y", "block mandatory inline",
"mandatory", "proximity", "mandatory inline",
"proximity both", "mandatory x", "proximity y",
"mandatory block", "proximity mandatory" ],
};
gCSSProperties["scroll-snap-align"] = {
domProp: "scrollSnapAlign",
inherited: false,

Просмотреть файл

@ -27,8 +27,10 @@ class nsIScrollbarMediator : public nsQueryFrame {
* scroll operation to maintain the constraints set by CSS Scroll snapping.
* The additional scrolling may include asynchronous smooth scrolls that
* continue to animate after the initial scroll position has been set.
* In case of DEFAULT, it means ENABLE_SNAP for CSS scroll snap v1,
* DISABLE_SNAP for the old scroll snap.
*/
enum ScrollSnapMode { DISABLE_SNAP, ENABLE_SNAP };
enum ScrollSnapMode { DEFAULT, DISABLE_SNAP, ENABLE_SNAP };
/**
* One of the following three methods is called when the scrollbar's button is

Просмотреть файл

@ -1808,7 +1808,8 @@ void nsMenuPopupFrame::EnsureMenuItemIsVisible(nsMenuFrame* aMenuItem) {
aMenuItem, nsRect(nsPoint(0, 0), aMenuItem->GetRect().Size()),
nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis(),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN |
nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY);
nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
nsIPresShell::SCROLL_IGNORE_SCROLL_MARGIN_AND_PADDING);
}
}

Просмотреть файл

@ -1,34 +1,3 @@
diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -216,20 +216,23 @@ enum {
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
};
/** Miscellaneous stream preferences. */
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
- CUBEB_STREAM_PREF_LOOPBACK = 0x01 /**< Request a loopback stream. Should be
- specified on the input params and an
- output device to loopback from should
- be passed in place of an input device. */
+ CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
+ specified on the input params and an
+ output device to loopback from should
+ be passed in place of an input device. */
+ CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
+ default device on OS
+ changes. */
} cubeb_stream_prefs;
/** Stream format initialization parameters. */
typedef struct {
cubeb_sample_format format; /**< Requested sample format. One of
#cubeb_sample_format. */
uint32_t rate; /**< Requested sample rate. Valid range is [1000, 192000]. */
uint32_t channels; /**< Requested channel count. Valid range is [1, 8]. */
diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@ -85,3 +54,26 @@ diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasa
// The variables intialized in wasapi_stream_init,
// must be destroyed in wasapi_stream_destroy.
stm->linear_input_buffer.reset();
diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
--- a/media/libcubeb/include/cubeb.h
+++ a/media/libcubeb/include/cubeb.h
@@ -222,16 +222,19 @@
/** Miscellaneous stream preferences. */
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
+ CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
+ default device on OS
+ changes. */
CUBEB_STREAM_PREF_VOICE = 0x04 /**< This stream is going to transport voice data.
Depending on the backend and platform, this can
change the audio input or output devices
selected, as well as the quality of the stream,
for example to accomodate bluetooth SCO modes on
bluetooth devices. */
} cubeb_stream_prefs;

Просмотреть файл

@ -224,12 +224,18 @@ enum {
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
default device on OS
changes. */
CUBEB_STREAM_PREF_VOICE = 0x04 /**< This stream is going to transport voice data.
Depending on the backend and platform, this can
change the audio input or output devices
selected, as well as the quality of the stream,
for example to accomodate bluetooth SCO modes on
bluetooth devices. */
} cubeb_stream_prefs;
/** Stream format initialization parameters. */

Просмотреть файл

@ -19,5 +19,5 @@ origin:
license: "ISC"
# update.sh will update this value
release: "66d9c48d916f00c396482f9c5075feacc2bc0db8 (2019-04-03 12:41:20 +0300)"
release: "c0a71704ae935666ecbd0e8a61345de583139607 (2019-04-10 18:19:29 +0200)"

Просмотреть файл

@ -43,10 +43,9 @@
#define SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION ((SLuint32) 0x00000003)
/** uses the main microphone tuned for audio communications */
#define SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION ((SLuint32) 0x00000004)
/** uses the main microphone unprocessed */
#define SL_ANDROID_RECORDING_PRESET_UNPROCESSED ((SLuint32) 0x00000005)
/** Audio recording get session ID (read only) */
/** Audio recording get session ID key */
#define SL_ANDROID_KEY_RECORDING_SESSION_ID ((const SLchar*) "androidRecordingSessionId")
/*---------------------------------------------------------------------------*/
/* Android AudioPlayer configuration */
@ -69,9 +68,35 @@
#define SL_ANDROID_STREAM_ALARM ((SLint32) 0x00000004)
/* same as android.media.AudioManager.STREAM_NOTIFICATION */
#define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005)
/* same as android.media.AudioManager.STREAM_BLUETOOTH_SCO */
#define SL_ANDROID_STREAM_BLUETOOTH_SCO ((SLint32) 0x00000006)
/* same as android.media.AudioManager.STREAM_SYSTEM_ENFORCED */
#define SL_ANDROID_STREAM_SYSTEM_ENFORCED ((SLint32) 0x00000007)
/*---------------------------------------------------------------------------*/
/* Android AudioPlayer and AudioRecorder configuration */
/*---------------------------------------------------------------------------*/
/** Audio Performance mode.
* Performance mode tells the framework how to configure the audio path
* for a player or recorder according to application performance and
* functional requirements.
* It affects the output or input latency based on acceptable tradeoffs on
* battery drain and use of pre or post processing effects.
* Performance mode should be set before realizing the object and should be
* read after realizing the object to check if the requested mode could be
* granted or not.
*/
/** Audio Performance mode key */
#define SL_ANDROID_KEY_PERFORMANCE_MODE ((const SLchar*) "androidPerformanceMode")
/** Audio performance values */
/* No specific performance requirement. Allows HW and SW pre/post processing. */
#define SL_ANDROID_PERFORMANCE_NONE ((SLuint32) 0x00000000)
/* Priority given to latency. No HW or software pre/post processing.
* This is the default if no performance mode is specified. */
#define SL_ANDROID_PERFORMANCE_LATENCY ((SLuint32) 0x00000001)
/* Priority given to latency while still allowing HW pre and post processing. */
#define SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS ((SLuint32) 0x00000002)
/* Priority given to power saving if latency is not a concern.
* Allows HW and SW pre/post processing. */
#define SL_ANDROID_PERFORMANCE_POWER_SAVING ((SLuint32) 0x00000003)
#endif /* OPENSL_ES_ANDROIDCONFIGURATION_H_ */

Просмотреть файл

@ -868,7 +868,7 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags)
{
if (std::atomic_exchange(&stm->reinit_pending, true)) {
// A reinit task is already pending, nothing more to do.
ALOG("(%p) re-init stream task already pending, cancelling request ", stm);
ALOG("(%p) re-init stream task already pending, cancelling request", stm);
return;
}
@ -944,7 +944,7 @@ audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
}
break;
case kAudioDevicePropertyDataSource: {
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource for id=%d", (unsigned int) i, id);
LOG("Event[%u] - mSelector == kAudioDevicePropertyDataSource for id=%d", (unsigned int) i, id);
}
break;
default:
@ -1314,9 +1314,9 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
static cubeb_channel_layout
audiounit_convert_channel_layout(AudioChannelLayout * layout)
{
// When having on or two channel, force mono or stereo. Some devices (namely,
// Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
// some reason.
// When having one or two channel, force mono or stereo. Some devices (namely,
// Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
// some reason.
if (layout->mNumberChannelDescriptions == 1) {
return CUBEB_LAYOUT_MONO;
} else if (layout->mNumberChannelDescriptions == 2) {
@ -1611,7 +1611,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioDeviceID
0, NULL,
&size);
if (r != noErr) {
LOG("AudioHardwareGetPropertyInfo/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
LOG("AudioObjectGetPropertyDataSize/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
return CUBEB_ERROR;
}
@ -1629,7 +1629,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioDeviceID
&size,
&translation_value);
if (r != noErr) {
LOG("AudioHardwareGetProperty/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
LOG("AudioObjectGetPropertyData/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
return CUBEB_ERROR;
}
@ -2072,23 +2072,23 @@ audiounit_create_unit(AudioUnit * unit, device_info * device)
if (device->flags & DEV_INPUT) {
r = audiounit_enable_unit_scope(unit, io_side::INPUT, ENABLE);
if (r != CUBEB_OK) {
LOG("Failed to enable audiounit input scope ");
LOG("Failed to enable audiounit input scope");
return r;
}
r = audiounit_enable_unit_scope(unit, io_side::OUTPUT, DISABLE);
if (r != CUBEB_OK) {
LOG("Failed to disable audiounit output scope ");
LOG("Failed to disable audiounit output scope");
return r;
}
} else if (device->flags & DEV_OUTPUT) {
r = audiounit_enable_unit_scope(unit, io_side::OUTPUT, ENABLE);
if (r != CUBEB_OK) {
LOG("Failed to enable audiounit output scope ");
LOG("Failed to enable audiounit output scope");
return r;
}
r = audiounit_enable_unit_scope(unit, io_side::INPUT, DISABLE);
if (r != CUBEB_OK) {
LOG("Failed to disable audiounit input scope ");
LOG("Failed to disable audiounit input scope");
return r;
}
} else {
@ -2588,16 +2588,16 @@ audiounit_setup_stream(cubeb_stream * stm)
}
/* Latency cannot change if another stream is operating in parallel. In this case
* latecy is set to the other stream value. */
* latency is set to the other stream value. */
if (audiounit_active_streams(stm->context) > 1) {
LOG("(%p) More than one active stream, use global latency.", stm);
stm->latency_frames = stm->context->global_latency_frames;
} else {
/* Silently clamp the latency down to the platform default, because we
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
stm->latency_frames = audiounit_clamp_latency(stm, stm->latency_frames);
assert(stm->latency_frames); // Ungly error check
assert(stm->latency_frames); // Ugly error check
audiounit_set_global_latency(stm->context, stm->latency_frames);
}

Просмотреть файл

@ -63,6 +63,11 @@
#define DEFAULT_SAMPLE_RATE 48000
#define DEFAULT_NUM_OF_FRAMES 480
// If the latency requested is above this threshold, this stream is considered
// intended for playback (vs. real-time). Tell Android it should favor saving
// power over performance or latency.
// This is around 100ms at 44100 or 48000
#define POWERSAVE_LATENCY_FRAMES_THRESHOLD 4000
static struct cubeb_ops const opensl_ops;
@ -84,7 +89,7 @@ struct cubeb {
};
#define NELEMS(A) (sizeof(A) / sizeof A[0])
#define NBUFS 4
#define NBUFS 2
struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
@ -155,10 +160,13 @@ struct cubeb_stream {
cubeb_resampler * resampler;
unsigned int user_output_rate;
unsigned int output_configured_rate;
unsigned int latency_frames;
unsigned int buffer_size_frames;
// Audio output latency used in cubeb_stream_get_position().
unsigned int output_latency_ms;
int64_t lastPosition;
int64_t lastPositionTimeStamp;
int64_t lastCompensativePosition;
int voice;
};
/* Forward declaration. */
@ -846,16 +854,17 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
lDataSource.pLocator = &lDataLocatorIn;
lDataSource.pFormat = NULL;
const SLuint32 lSoundRecorderIIDCount = 2;
const SLInterfaceID lSoundRecorderIIDs[] = { stm->context->SL_IID_RECORD,
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean lSoundRecorderReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
stm->context->SL_IID_ANDROIDCONFIGURATION };
const SLboolean lSoundRecorderReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
// create the audio recorder abstract object
SLresult res = (*stm->context->eng)->CreateAudioRecorder(stm->context->eng,
&stm->recorderObj,
&lDataSource,
&lDataSink,
lSoundRecorderIIDCount,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs,
lSoundRecorderReqs);
// Sample rate not supported. Try again with default sample rate!
@ -874,7 +883,7 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
&stm->recorderObj,
&lDataSource,
&lDataSink,
lSoundRecorderIIDCount,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs,
lSoundRecorderReqs);
@ -884,6 +893,35 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
}
}
SLAndroidConfigurationItf recorderConfig;
res = (*stm->recorderObj)
->GetInterface(stm->recorderObj,
stm->context->SL_IID_ANDROIDCONFIGURATION,
&recorderConfig);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to get the android configuration interface for recorder. Error "
"code: %lu",
res);
return CUBEB_ERROR;
}
// Voice recognition is the lowest latency, according to the docs. Camcorder
// uses a microphone that is in the same direction as the camera.
SLint32 streamType = stm->voice ? SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION
: SL_ANDROID_RECORDING_PRESET_CAMCORDER;
res = (*recorderConfig)
->SetConfiguration(recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET,
&streamType, sizeof(SLint32));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set the android configuration to VOICE for the recorder. "
"Error code: %lu",
res);
return CUBEB_ERROR;
}
// realize the audio recorder
res = (*stm->recorderObj)->Realize(stm->recorderObj, SL_BOOLEAN_FALSE);
if (res != SL_RESULT_SUCCESS) {
@ -937,7 +975,7 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
// Calculate length of input buffer according to requested latency
stm->input_frame_size = params->channels * sizeof(int16_t);
stm->input_buffer_length = (stm->input_frame_size * stm->latency_frames);
stm->input_buffer_length = (stm->input_frame_size * stm->buffer_size_frames);
// Calculate the capacity of input array
stm->input_array_capacity = NBUFS;
@ -1048,7 +1086,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
stm->output_configured_rate = preferred_sampling_rate;
stm->bytespersec = stm->output_configured_rate * stm->framesize;
stm->queuebuf_len = stm->framesize * stm->latency_frames;
stm->queuebuf_len = stm->framesize * stm->buffer_size_frames;
// Calculate the capacity of input array
stm->queuebuf_capacity = NBUFS;
@ -1063,12 +1101,80 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
assert(stm->queuebuf[i]);
}
SLAndroidConfigurationItf playerConfig;
res = (*stm->playerObj)
->GetInterface(stm->playerObj,
stm->context->SL_IID_ANDROIDCONFIGURATION,
&playerConfig);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to get Android configuration interface. Error code: %lu", res);
return CUBEB_ERROR;
}
SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
if (stm->voice) {
streamType = SL_ANDROID_STREAM_VOICE;
}
res = (*playerConfig)->SetConfiguration(playerConfig,
SL_ANDROID_KEY_STREAM_TYPE,
&streamType,
sizeof(streamType));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set Android configuration to %d Error code: %lu",
streamType, res);
return CUBEB_ERROR;
}
SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_LATENCY;
if (stm->buffer_size_frames > POWERSAVE_LATENCY_FRAMES_THRESHOLD) {
performanceMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
}
res = (*playerConfig)->SetConfiguration(playerConfig,
SL_ANDROID_KEY_PERFORMANCE_MODE,
&performanceMode,
sizeof(performanceMode));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set Android performance mode to %d Error code: %lu. This is"
" not fatal", performanceMode, res);
}
res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to realize player object. Error code: %lu", res);
return CUBEB_ERROR;
}
// There are two ways of getting the audio output latency:
// - a configuration value, only available on some devices (notably devices
// running FireOS)
// - A Java method, that we call using JNI.
//
// The first method is prefered, if available, because it can account for more
// latency causes, and is more precise.
// Latency has to be queried after the realization of the interface, when
// using SL_IID_ANDROIDCONFIGURATION.
SLuint32 audioLatency = 0;
SLuint32 paramSize = sizeof(SLuint32);
// The reported latency is in milliseconds.
res = (*playerConfig)->GetConfiguration(playerConfig,
(const SLchar *)"androidGetAudioLatency",
&paramSize,
&audioLatency);
if (res == SL_RESULT_SUCCESS) {
LOG("Got playback latency using android configuration extension");
stm->output_latency_ms = audioLatency;
} else if (cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
LOG("Got playback latency using JNI");
stm->output_latency_ms = cubeb_get_output_latency(stm->context->p_output_latency_function);
} else {
LOG("No alternate latency querying method loaded, A/V sync will be off.");
stm->output_latency_ms = 0;
}
LOG("Audio output latency: %dms", stm->output_latency_ms);
res = (*stm->playerObj)->GetInterface(stm->playerObj,
stm->context->SL_IID_PLAY,
&stm->play);
@ -1148,6 +1254,14 @@ opensl_validate_stream_param(cubeb_stream_params * stream_params)
return CUBEB_OK;
}
int has_pref_set(cubeb_stream_params* input_params,
cubeb_stream_params* output_params,
cubeb_stream_prefs pref)
{
return (input_params && input_params->prefs & pref) ||
(output_params && output_params->prefs & pref);
}
static int
opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
@ -1185,10 +1299,14 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->latency_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
stm->buffer_size_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
stm->input_enabled = (input_stream_params) ? 1 : 0;
stm->output_enabled = (output_stream_params) ? 1 : 0;
stm->shutdown = 1;
stm->voice = has_pref_set(input_stream_params, output_stream_params, CUBEB_STREAM_PREF_VOICE);
LOG("cubeb stream prefs: voice: %s", stm->voice ? "true" : "false");
#ifdef DEBUG
pthread_mutexattr_t attr;
@ -1203,7 +1321,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
if (output_stream_params) {
LOG("Playback params: Rate %d, channels %d, format %d, latency in frames %d.",
output_stream_params->rate, output_stream_params->channels,
output_stream_params->format, stm->latency_frames);
output_stream_params->format, stm->buffer_size_frames);
r = opensl_configure_playback(stm, output_stream_params);
if (r != CUBEB_OK) {
opensl_stream_destroy(stm);
@ -1214,7 +1332,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
if (input_stream_params) {
LOG("Capture params: Rate %d, channels %d, format %d, latency in frames %d.",
input_stream_params->rate, input_stream_params->channels,
input_stream_params->format, stm->latency_frames);
input_stream_params->format, stm->buffer_size_frames);
r = opensl_configure_capture(stm, input_stream_params);
if (r != CUBEB_OK) {
opensl_stream_destroy(stm);
@ -1452,10 +1570,6 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
uint32_t compensation_msec = 0;
SLresult res;
if (!cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
return CUBEB_ERROR_NOT_SUPPORTED;
}
res = (*stm->play)->GetPosition(stm->play, &msec);
if (res != SL_RESULT_SUCCESS)
return CUBEB_ERROR;
@ -1471,22 +1585,22 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
}
uint64_t samplerate = stm->user_output_rate;
uint32_t mixer_latency = cubeb_get_output_latency(stm->context->p_output_latency_function);
uint32_t output_latency = stm->output_latency_ms;
pthread_mutex_lock(&stm->mutex);
int64_t maximum_position = stm->written * (int64_t)stm->user_output_rate / stm->output_configured_rate;
pthread_mutex_unlock(&stm->mutex);
assert(maximum_position >= 0);
if (msec > mixer_latency) {
if (msec > output_latency) {
int64_t unadjusted_position;
if (stm->lastCompensativePosition > msec + compensation_msec) {
// Over compensation, use lastCompensativePosition.
unadjusted_position =
samplerate * (stm->lastCompensativePosition - mixer_latency) / 1000;
samplerate * (stm->lastCompensativePosition - output_latency) / 1000;
} else {
unadjusted_position =
samplerate * (msec - mixer_latency + compensation_msec) / 1000;
samplerate * (msec - output_latency + compensation_msec) / 1000;
stm->lastCompensativePosition = msec + compensation_msec;
}
*position = unadjusted_position < maximum_position ?

Просмотреть файл

@ -141,6 +141,7 @@ int wasapi_stream_stop(cubeb_stream * stm);
int wasapi_stream_start(cubeb_stream * stm);
void close_wasapi_stream(cubeb_stream * stm);
int setup_wasapi_stream(cubeb_stream * stm);
ERole pref_to_role(cubeb_stream_prefs param);
static char const * wstr_to_utf8(wchar_t const * str);
static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
@ -191,6 +192,8 @@ struct cubeb_stream {
* and what will be presented in the callback. */
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE };
/* A MMDevice role for this stream: either communication or console here. */
ERole role;
/* The input and output device, or NULL for default. */
std::unique_ptr<const wchar_t[]> input_device;
std::unique_ptr<const wchar_t[]> output_device;
@ -565,9 +568,10 @@ public:
return S_OK;
}
wasapi_endpoint_notification_client(HANDLE event)
wasapi_endpoint_notification_client(HANDLE event, ERole role)
: ref_count(1)
, reconfigure_event(event)
, role(role)
{ }
virtual ~wasapi_endpoint_notification_client()
@ -579,7 +583,7 @@ public:
LOG("endpoint: Audio device default changed.");
/* we only support a single stream type for now. */
if (flow != eRender && role != eConsole) {
if (flow != eRender && role != this->role) {
return S_OK;
}
@ -622,6 +626,7 @@ private:
/* refcount for this instance, necessary to implement MSCOM semantics. */
LONG ref_count;
HANDLE reconfigure_event;
ERole role;
};
namespace {
@ -1256,7 +1261,7 @@ HRESULT register_notification_client(cubeb_stream * stm)
return hr;
}
stm->notification_client.reset(new wasapi_endpoint_notification_client(stm->reconfigure_event));
stm->notification_client.reset(new wasapi_endpoint_notification_client(stm->reconfigure_event, stm->role));
hr = stm->device_enumerator->RegisterEndpointNotificationCallback(stm->notification_client.get());
if (FAILED(hr)) {
@ -1351,7 +1356,7 @@ HRESULT unregister_collection_notification_client(cubeb * context)
return hr;
}
HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction, ERole role)
{
com_ptr<IMMDeviceEnumerator> enumerator;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
@ -1361,7 +1366,7 @@ HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
LOG("Could not get device enumerator: %lx", hr);
return hr;
}
hr = enumerator->GetDefaultAudioEndpoint(direction, eConsole, device.receive());
hr = enumerator->GetDefaultAudioEndpoint(direction, role, device.receive());
if (FAILED(hr)) {
LOG("Could not get default audio endpoint: %lx", hr);
return hr;
@ -1447,11 +1452,11 @@ int wasapi_init(cubeb ** context, char const * context_name)
so that this backend is not incorrectly enabled on platforms that don't
support WASAPI. */
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
XASSERT(hr != CO_E_NOTINITIALIZED);
LOG("It wasn't able to find a default rendering device: %lx", hr);
hr = get_default_endpoint(device, eCapture);
hr = get_default_endpoint(device, eCapture, eConsole);
if (FAILED(hr)) {
LOG("It wasn't able to find a default capture device: %lx", hr);
return CUBEB_ERROR;
@ -1550,7 +1555,7 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
XASSERT(ctx && max_channels);
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
@ -1582,8 +1587,10 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
return CUBEB_ERROR_INVALID_FORMAT;
}
ERole role = pref_to_role(params.prefs);
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, role);
if (FAILED(hr)) {
LOG("Could not get default endpoint: %lx", hr);
return CUBEB_ERROR;
@ -1623,7 +1630,7 @@ int
wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
@ -1755,7 +1762,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
// If caller has requested loopback but not specified a device, look for
// the default render device. Otherwise look for the default device
// appropriate to the direction.
hr = get_default_endpoint(device, is_loopback ? eRender : direction);
hr = get_default_endpoint(device, is_loopback ? eRender : direction, pref_to_role(stream_params->prefs));
if (FAILED(hr)) {
if (is_loopback) {
LOG("Could not get default render endpoint for loopback, error: %lx\n", hr);
@ -2057,6 +2064,16 @@ int setup_wasapi_stream(cubeb_stream * stm)
return CUBEB_OK;
}
ERole
pref_to_role(cubeb_stream_prefs prefs)
{
if (prefs & CUBEB_STREAM_PREF_VOICE) {
return eCommunications;
}
return eConsole;
}
int
wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
char const * stream_name,
@ -2082,6 +2099,14 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
if (stm->output_stream_params.prefs & CUBEB_STREAM_PREF_VOICE ||
stm->input_stream_params.prefs & CUBEB_STREAM_PREF_VOICE) {
stm->role = eCommunications;
} else {
stm->role = eConsole;
}
if (input_stream_params) {
stm->input_stream_params = *input_stream_params;
stm->input_device = utf8_to_wstr(reinterpret_cast<char const *>(input_device));

Просмотреть файл

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature
android:name="android.hardware.location"

Просмотреть файл

@ -1996,6 +1996,41 @@ public class GeckoAppShell {
return Integer.parseInt(prop);
}
static private int sPreviousAudioMode = -2;
@WrapForJNI(calledFrom = "any")
public static void setCommunicationAudioModeOn(final boolean on) {
final AudioManager am = (AudioManager)getApplicationContext()
.getSystemService(Context.AUDIO_SERVICE);
if (am == null) {
return;
}
if (sPreviousAudioMode == AudioManager.MODE_INVALID) {
sPreviousAudioMode = am.getMode();
}
try {
if (on) {
Log.e(LOGTAG, "Setting communication mode ON");
sPreviousAudioMode = am.getMode();
am.startBluetoothSco();
am.setBluetoothScoOn(true);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
} else {
Log.e(LOGTAG, "Setting communication mode OFF");
am.setMode(sPreviousAudioMode);
sPreviousAudioMode = AudioManager.MODE_INVALID;
am.stopBluetoothSco();
am.setBluetoothScoOn(false);
}
} catch (SecurityException e) {
Log.e(LOGTAG, "could not set communication mode", e);
}
am.setSpeakerphoneOn(!on);
}
private static String getLanguageTag(final Locale locale) {
final StringBuilder out = new StringBuilder(locale.getLanguage());
final String country = locale.getCountry();

Просмотреть файл

@ -1098,13 +1098,26 @@ VARCACHE_PREF(
bool, false
)
#ifdef NIGHTLY_BUILD
# define PREF_VALUE true
#else
# define PREF_VALUE false
#endif
// Is the CSS Scroll Snap Module Level 1 enabled?
VARCACHE_PREF(
"layout.css.scroll-snap-v1.enabled",
layout_css_scroll_snap_v1_enabled,
RelaxedAtomicBool, false
RelaxedAtomicBool, PREF_VALUE
)
// Is support for scroll-snap enabled?
VARCACHE_PREF(
"layout.css.scroll-snap.enabled",
layout_css_scroll_snap_enabled,
bool, !PREF_VALUE
)
#undef PREF_VALUE
// Are shared memory User Agent style sheets enabled?
VARCACHE_PREF(
"layout.css.shared-memory-ua-sheets.enabled",

Просмотреть файл

@ -3167,9 +3167,6 @@ pref("layout.css.scroll-behavior.spring-constant", "250.0");
// at the greatest speed without overshooting.
pref("layout.css.scroll-behavior.damping-ratio", "1.0");
// Is support for scroll-snap enabled?
pref("layout.css.scroll-snap.enabled", true);
// Is support for document.fonts enabled?
pref("layout.css.font-loading-api.enabled", true);

Просмотреть файл

@ -341,6 +341,8 @@ class Longhand(object):
"SVGOpacity",
"SVGPaintOrder",
"ScrollSnapAlign",
"ScrollSnapAxis",
"ScrollSnapStrictness",
"ScrollSnapType",
"TextAlign",
"TextDecorationLine",

Просмотреть файл

@ -427,18 +427,14 @@ ${helpers.predefined_type(
animation_value_type="discrete",
)}
% for axis in ["x", "y"]:
${helpers.predefined_type(
"scroll-snap-type-" + axis,
"ScrollSnapType",
"computed::ScrollSnapType::None",
products="gecko",
needs_context=False,
gecko_pref="layout.css.scroll-snap.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x)",
animation_value_type="discrete",
)}
% endfor
${helpers.predefined_type(
"scroll-snap-type",
"ScrollSnapType",
"computed::ScrollSnapType::none()",
products="gecko",
spec="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type",
animation_value_type="discrete",
)}
% for axis in ["x", "y"]:
${helpers.predefined_type(

Просмотреть файл

@ -303,36 +303,6 @@ macro_rules! try_parse_one {
}
</%helpers:shorthand>
<%helpers:shorthand name="scroll-snap-type" products="gecko"
gecko_pref="layout.css.scroll-snap.enabled"
sub_properties="scroll-snap-type-x scroll-snap-type-y"
spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
use crate::properties::longhands::scroll_snap_type_x;
pub fn parse_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> {
let result = scroll_snap_type_x::parse(context, input)?;
Ok(expanded! {
scroll_snap_type_x: result,
scroll_snap_type_y: result,
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
// Serializes into the single keyword value if both scroll-snap-type-x and scroll-snap-type-y are same.
// Otherwise into an empty string. This is done to match Gecko's behaviour.
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
if self.scroll_snap_type_x == self.scroll_snap_type_y {
self.scroll_snap_type_x.to_css(dest)
} else {
Ok(())
}
}
}
</%helpers:shorthand>
${helpers.two_properties_shorthand(
"overscroll-behavior",
"overscroll-behavior-x",

Просмотреть файл

@ -14,8 +14,8 @@ use crate::values::specified::box_ as specified;
pub use crate::values::specified::box_::{AnimationName, Appearance, BreakBetween, BreakWithin};
pub use crate::values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat};
pub use crate::values::specified::box_::{Contain, Display, Overflow};
pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox};
pub use crate::values::specified::box_::{OverscrollBehavior, ScrollSnapAlign, ScrollSnapType};
pub use crate::values::specified::box_::{OverflowAnchor, OverflowClipBox, OverscrollBehavior};
pub use crate::values::specified::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, ScrollSnapType};
pub use crate::values::specified::box_::{TouchAction, TransitionProperty, WillChange};
/// A computed value for the `vertical-align` property.

Просмотреть файл

@ -42,7 +42,8 @@ pub use self::box_::{AnimationIterationCount, AnimationName, Contain};
pub use self::box_::{Appearance, BreakBetween, BreakWithin, Clear, Float};
pub use self::box_::{Display, Overflow, OverflowAnchor, TransitionProperty};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize};
pub use self::box_::{ScrollSnapAlign, ScrollSnapType, TouchAction, VerticalAlign, WillChange};
pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, ScrollSnapType};
pub use self::box_::{TouchAction, VerticalAlign, WillChange};
pub use self::color::{Color, ColorOrAuto, ColorPropertyValue};
pub use self::column::ColumnCount;
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterSetOrReset};

Просмотреть файл

@ -379,6 +379,7 @@ impl Parse for AnimationName {
}
}
/// https://drafts.csswg.org/css-scroll-snap-1/#snap-axis
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
@ -396,12 +397,104 @@ impl Parse for AnimationName {
ToShmem,
)]
#[repr(u8)]
pub enum ScrollSnapType {
None,
pub enum ScrollSnapAxis {
X,
Y,
Block,
Inline,
Both,
}
/// https://drafts.csswg.org/css-scroll-snap-1/#snap-strictness
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
pub enum ScrollSnapStrictness {
#[css(skip)]
None, // Used to represent scroll-snap-type: none. It's not parsed.
Mandatory,
Proximity,
}
/// https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct ScrollSnapType {
axis: ScrollSnapAxis,
strictness: ScrollSnapStrictness,
}
impl ScrollSnapType {
/// Returns `none`.
#[inline]
pub fn none() -> Self {
Self {
axis: ScrollSnapAxis::Both,
strictness: ScrollSnapStrictness::None,
}
}
}
impl Parse for ScrollSnapType {
/// none | [ x | y | block | inline | both ] [ mandatory | proximity ]?
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(ScrollSnapType::none());
}
let axis = ScrollSnapAxis::parse(input)?;
let strictness = input.try(ScrollSnapStrictness::parse).unwrap_or(ScrollSnapStrictness::Proximity);
Ok(Self { axis, strictness })
}
}
impl ToCss for ScrollSnapType {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.strictness == ScrollSnapStrictness::None {
return dest.write_str("none");
}
self.axis.to_css(dest)?;
if self.strictness != ScrollSnapStrictness::Proximity {
dest.write_str(" ")?;
self.strictness.to_css(dest)?;
}
Ok(())
}
}
/// Specified value of scroll-snap-align keyword value.
#[allow(missing_docs)]
#[derive(

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше