merge mozilla-inbound to mozilla-central. r=merge a=merge
MozReview-Commit-ID: 4W52wcX8xBm
|
@ -2850,8 +2850,10 @@ var JawsScreenReaderVersionCheck = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_checkVersionAndPrompt() {
|
_checkVersionAndPrompt() {
|
||||||
// This executes a JAWS version check.
|
// Make sure we only prompt for versions of JAWS we do not
|
||||||
if (!Services.appinfo.shouldBlockIncompatJaws) {
|
// support and never prompt if e10s is disabled.
|
||||||
|
if (!Services.appinfo.shouldBlockIncompatJaws ||
|
||||||
|
!Services.appinfo.browserTabsRemoteAutostart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,48 +124,6 @@ menuitem.bookmark-item {
|
||||||
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
|
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bookmark items */
|
|
||||||
.bookmark-item {
|
|
||||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container] {
|
|
||||||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] {
|
|
||||||
list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/livemark-item.png");
|
|
||||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item[visited] {
|
|
||||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][query] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/query.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][tagContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/tag.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][dayContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/calendar.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer] {
|
|
||||||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer][open] {
|
|
||||||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[cutting] > .toolbarbutton-icon,
|
.bookmark-item[cutting] > .toolbarbutton-icon,
|
||||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
|
@ -41,14 +41,12 @@ browser.jar:
|
||||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||||
skin/classic/browser/places/bookmarks-menu-arrow.png (places/bookmarks-menu-arrow.png)
|
skin/classic/browser/places/bookmarks-menu-arrow.png (places/bookmarks-menu-arrow.png)
|
||||||
skin/classic/browser/places/calendar.png (places/calendar.png)
|
|
||||||
* skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
* skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||||
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
|
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
|
||||||
skin/classic/browser/places/starred48.png (places/starred48.png)
|
skin/classic/browser/places/starred48.png (places/starred48.png)
|
||||||
* skin/classic/browser/places/places.css (places/places.css)
|
* skin/classic/browser/places/places.css (places/places.css)
|
||||||
skin/classic/browser/places/organizer.css (places/organizer.css)
|
skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||||
skin/classic/browser/places/organizer.xml (places/organizer.xml)
|
skin/classic/browser/places/organizer.xml (places/organizer.xml)
|
||||||
skin/classic/browser/places/query.png (places/query.png)
|
|
||||||
skin/classic/browser/places/tag.png (places/tag.png)
|
skin/classic/browser/places/tag.png (places/tag.png)
|
||||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||||
skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png)
|
skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png)
|
||||||
|
|
Двоичные данные
browser/themes/linux/places/calendar.png
До Ширина: | Высота: | Размер: 670 B |
Двоичные данные
browser/themes/linux/places/query.png
До Ширина: | Высота: | Размер: 678 B |
|
@ -186,79 +186,6 @@
|
||||||
-moz-box-align: center;
|
-moz-box-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----- BOOKMARK BUTTONS ----- */
|
|
||||||
|
|
||||||
.bookmark-item[container] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] {
|
|
||||||
list-style-image: url("chrome://browser/skin/page-livemarks.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/livemark-item.png");
|
|
||||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item[visited] {
|
|
||||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][query] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/query.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][tagContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/tag.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][dayContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/history.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer][open] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-resolution: 2dppx) {
|
|
||||||
.bookmark-item[container] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] {
|
|
||||||
list-style-image: url("chrome://browser/skin/page-livemarks@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/livemark-item.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][query] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/query@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][tagContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/tag@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][dayContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/history@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder@2x.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer][open] {
|
|
||||||
list-style-image: url("chrome://global/skin/tree/folder@2x.png");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Workaround for native menubar inheritance */
|
/* Workaround for native menubar inheritance */
|
||||||
.openintabs-menuitem,
|
.openintabs-menuitem,
|
||||||
.openlivemarksite-menuitem,
|
.openlivemarksite-menuitem,
|
||||||
|
@ -829,10 +756,6 @@ html|span.ac-emphasize-text-url {
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-item {
|
|
||||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
|
|
||||||
}
|
|
||||||
|
|
||||||
.openintabs-menuitem {
|
.openintabs-menuitem {
|
||||||
list-style-image: none;
|
list-style-image: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ browser.jar:
|
||||||
skin/classic/browser/panel-expander-open@2x.png
|
skin/classic/browser/panel-expander-open@2x.png
|
||||||
skin/classic/browser/panel-plus-sign.png
|
skin/classic/browser/panel-plus-sign.png
|
||||||
skin/classic/browser/page-livemarks.png
|
skin/classic/browser/page-livemarks.png
|
||||||
skin/classic/browser/page-livemarks@2x.png
|
|
||||||
skin/classic/browser/pageInfo.css
|
skin/classic/browser/pageInfo.css
|
||||||
skin/classic/browser/searchbar.css
|
skin/classic/browser/searchbar.css
|
||||||
skin/classic/browser/slowStartup-16.png
|
skin/classic/browser/slowStartup-16.png
|
||||||
|
@ -46,13 +45,9 @@ browser.jar:
|
||||||
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
|
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
|
||||||
* skin/classic/browser/places/places.css (places/places.css)
|
* skin/classic/browser/places/places.css (places/places.css)
|
||||||
skin/classic/browser/places/organizer.css (places/organizer.css)
|
skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||||
skin/classic/browser/places/query.png (places/query.png)
|
|
||||||
skin/classic/browser/places/query@2x.png (places/query@2x.png)
|
|
||||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||||
skin/classic/browser/places/bookmarksToolbar@2x.png (places/bookmarksToolbar@2x.png)
|
skin/classic/browser/places/bookmarksToolbar@2x.png (places/bookmarksToolbar@2x.png)
|
||||||
skin/classic/browser/places/history.png (places/history.png)
|
|
||||||
skin/classic/browser/places/history@2x.png (places/history@2x.png)
|
|
||||||
skin/classic/browser/places/toolbar.png (places/toolbar.png)
|
skin/classic/browser/places/toolbar.png (places/toolbar.png)
|
||||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||||
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||||
|
|
Двоичные данные
browser/themes/osx/page-livemarks@2x.png
До Ширина: | Высота: | Размер: 1.1 KiB |
Двоичные данные
browser/themes/osx/places/history.png
До Ширина: | Высота: | Размер: 843 B |
Двоичные данные
browser/themes/osx/places/history@2x.png
До Ширина: | Высота: | Размер: 1.8 KiB |
Двоичные данные
browser/themes/osx/places/query.png
До Ширина: | Высота: | Размер: 549 B |
Двоичные данные
browser/themes/osx/places/query@2x.png
До Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<path d="M13 1H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h11a2 2 0 0 0 2-2V4a3 3 0 0 0-3-3zm1 11a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1z"/>
|
||||||
|
<path d="M9.466 6.269l-.964-1.934-.185-.305-.662.028-1.101 2.211-2.039.364-.329.084-.184.613L5.67 9.123 5.365 11.3l-.023.351.552.356 2.116-1.102 1.844.96.319.138.525-.395-.347-2.485 1.462-1.573.214-.268-.227-.596-2.334-.417z"/>
|
||||||
|
</svg>
|
После Ширина: | Высота: | Размер: 688 B |
|
@ -1,6 +0,0 @@
|
||||||
<!-- 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">
|
|
||||||
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 1H3a3.007 3.007 0 0 0-3 3v8a3.009 3.009 0 0 0 3 3h10a3.005 3.005 0 0 0 3-3V4a3.012 3.012 0 0 0-3-3zM3 3h10a1 1 0 0 1 1 1v1H2V4a1 1 0 0 1 1-1zm11 3v1H2V6zm-1 7H3a1 1 0 0 1-1-1V8h12v4a1 1 0 0 1-1 1z"/>
|
|
||||||
</svg>
|
|
До Ширина: | Высота: | Размер: 574 B |
|
@ -170,7 +170,7 @@
|
||||||
skin/classic/browser/stop-to-reload.svg (../shared/icons/stop-to-reload.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/sync.svg (../shared/icons/sync.svg)
|
||||||
skin/classic/browser/synced-tabs.svg (../shared/icons/synced-tabs.svg)
|
skin/classic/browser/synced-tabs.svg (../shared/icons/synced-tabs.svg)
|
||||||
skin/classic/browser/toolbar.svg (../shared/icons/toolbar.svg)
|
skin/classic/browser/bookmarks-toolbar.svg (../shared/icons/bookmarks-toolbar.svg)
|
||||||
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
|
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
|
||||||
skin/classic/browser/window.svg (../shared/icons/window.svg)
|
skin/classic/browser/window.svg (../shared/icons/window.svg)
|
||||||
skin/classic/browser/zoom-in.svg (../shared/icons/zoom-in.svg)
|
skin/classic/browser/zoom-in.svg (../shared/icons/zoom-in.svg)
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#panelMenu_viewBookmarksToolbar {
|
#panelMenu_viewBookmarksToolbar {
|
||||||
list-style-image: url("chrome://browser/skin/toolbar.svg");
|
list-style-image: url("chrome://browser/skin/bookmarks-toolbar.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
#appMenu-library-bookmarks-button,
|
#appMenu-library-bookmarks-button,
|
||||||
|
|
|
@ -186,7 +186,7 @@ toolbar[brighttext] {
|
||||||
|
|
||||||
#bookmarks-toolbar-button,
|
#bookmarks-toolbar-button,
|
||||||
#bookmarks-toolbar-placeholder {
|
#bookmarks-toolbar-placeholder {
|
||||||
list-style-image: url("chrome://browser/skin/bookmark-hollow.svg");
|
list-style-image: url("chrome://browser/skin/bookmarks-toolbar.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
#bookmarks-menu-button {
|
#bookmarks-menu-button {
|
||||||
|
@ -521,3 +521,54 @@ toolbar[brighttext] {
|
||||||
animation-duration: 2s;
|
animation-duration: 2s;
|
||||||
animation-timing-function: ease-out;
|
animation-timing-function: ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----- BOOKMARK BUTTONS ----- */
|
||||||
|
|
||||||
|
.bookmark-item {
|
||||||
|
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[container] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/folder.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[container][livemark] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/folder-live.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[container][livemark] .bookmark-item {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/livemark-item.png");
|
||||||
|
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[container][livemark] .bookmark-item[visited] {
|
||||||
|
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[container][query] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/folder-smart.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[query][tagContainer] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/tag.png");
|
||||||
|
-moz-image-region: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[query][dayContainer] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/history.svg");
|
||||||
|
-moz-image-region: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-item[query][hostContainer] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/folder.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
%ifdef XP_MACOSX
|
||||||
|
@media (min-resolution: 2dppx) {
|
||||||
|
.bookmark-item[query][tagContainer] {
|
||||||
|
list-style-image: url("chrome://browser/skin/places/tag@2x.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%endif
|
||||||
|
|
|
@ -340,60 +340,6 @@ menuitem.bookmark-item {
|
||||||
padding-inline-start: 0px;
|
padding-inline-start: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ::::: bookmark items ::::: */
|
|
||||||
|
|
||||||
.bookmark-item {
|
|
||||||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container] {
|
|
||||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
|
||||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][open] {
|
|
||||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] {
|
|
||||||
list-style-image: url("chrome://browser/skin/livemark-folder.png");
|
|
||||||
-moz-image-region: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/livemark-item.png");
|
|
||||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][livemark] .bookmark-item[visited] {
|
|
||||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[container][query] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/query.png");
|
|
||||||
-moz-image-region: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][tagContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/tag.png");
|
|
||||||
-moz-image-region: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][dayContainer] {
|
|
||||||
list-style-image: url("chrome://browser/skin/places/calendar.png");
|
|
||||||
-moz-image-region: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer] {
|
|
||||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
|
||||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[query][hostContainer][open] {
|
|
||||||
list-style-image: url("chrome://global/skin/icons/folder-item.png");
|
|
||||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmark-item[cutting] > .toolbarbutton-icon,
|
.bookmark-item[cutting] > .toolbarbutton-icon,
|
||||||
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
.bookmark-item[cutting] > .menu-iconic-left > .menu-iconic-icon {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
|
@ -10,7 +10,6 @@ browser.jar:
|
||||||
* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css)
|
* skin/classic/browser/syncedtabs/sidebar.css (syncedtabs/sidebar.css)
|
||||||
* skin/classic/browser/browser.css
|
* skin/classic/browser/browser.css
|
||||||
* skin/classic/browser/compacttheme.css
|
* skin/classic/browser/compacttheme.css
|
||||||
skin/classic/browser/livemark-folder.png
|
|
||||||
skin/classic/browser/menuPanel-customize.png
|
skin/classic/browser/menuPanel-customize.png
|
||||||
skin/classic/browser/menuPanel-customize@2x.png
|
skin/classic/browser/menuPanel-customize@2x.png
|
||||||
skin/classic/browser/menuPanel-exit.png
|
skin/classic/browser/menuPanel-exit.png
|
||||||
|
@ -42,10 +41,8 @@ browser.jar:
|
||||||
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
||||||
* skin/classic/browser/places/places.css (places/places.css)
|
* skin/classic/browser/places/places.css (places/places.css)
|
||||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||||
skin/classic/browser/places/query.png (places/query.png)
|
|
||||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||||
skin/classic/browser/places/calendar.png (places/calendar.png)
|
|
||||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||||
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||||
skin/classic/browser/places/libraryToolbar.png (places/libraryToolbar.png)
|
skin/classic/browser/places/libraryToolbar.png (places/libraryToolbar.png)
|
||||||
|
|
Двоичные данные
browser/themes/windows/livemark-folder.png
До Ширина: | Высота: | Размер: 619 B |
Двоичные данные
browser/themes/windows/places/calendar.png
До Ширина: | Высота: | Размер: 567 B |
Двоичные данные
browser/themes/windows/places/query.png
До Ширина: | Высота: | Размер: 601 B |
|
@ -308,7 +308,12 @@ exports.WebConsoleCommands = WebConsoleCommands;
|
||||||
* The result of calling document.querySelector(selector).
|
* The result of calling document.querySelector(selector).
|
||||||
*/
|
*/
|
||||||
WebConsoleCommands._registerOriginal("$", function (owner, selector) {
|
WebConsoleCommands._registerOriginal("$", function (owner, selector) {
|
||||||
|
try {
|
||||||
return owner.window.document.querySelector(selector);
|
return owner.window.document.querySelector(selector);
|
||||||
|
} catch (err) {
|
||||||
|
// Throw an error like `err` but that belongs to `owner.window`.
|
||||||
|
throw new owner.window.DOMException(err.message, err.name);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -320,7 +325,13 @@ WebConsoleCommands._registerOriginal("$", function (owner, selector) {
|
||||||
* Returns the result of document.querySelectorAll(selector).
|
* Returns the result of document.querySelectorAll(selector).
|
||||||
*/
|
*/
|
||||||
WebConsoleCommands._registerOriginal("$$", function (owner, selector) {
|
WebConsoleCommands._registerOriginal("$$", function (owner, selector) {
|
||||||
let nodes = owner.window.document.querySelectorAll(selector);
|
let nodes;
|
||||||
|
try {
|
||||||
|
nodes = owner.window.document.querySelectorAll(selector);
|
||||||
|
} catch (err) {
|
||||||
|
// Throw an error like `err` but that belongs to `owner.window`.
|
||||||
|
throw new owner.window.DOMException(err.message, err.name);
|
||||||
|
}
|
||||||
|
|
||||||
// Calling owner.window.Array.from() doesn't work without accessing the
|
// Calling owner.window.Array.from() doesn't work without accessing the
|
||||||
// wrappedJSObject, so just loop through the results instead.
|
// wrappedJSObject, so just loop through the results instead.
|
||||||
|
|
|
@ -34,6 +34,7 @@ function startTest() {
|
||||||
checkQuerySelector,
|
checkQuerySelector,
|
||||||
checkQuerySelectorAll,
|
checkQuerySelectorAll,
|
||||||
checkQuerySelectorAllNotExist,
|
checkQuerySelectorAllNotExist,
|
||||||
|
checkQuerySelectorException,
|
||||||
checkQuerySelectorAllException
|
checkQuerySelectorAllException
|
||||||
];
|
];
|
||||||
runTests(tests, testEnd);
|
runTests(tests, testEnd);
|
||||||
|
@ -87,6 +88,25 @@ let checkQuerySelectorAllNotExist = Task.async(function*() {
|
||||||
nextTest();
|
nextTest();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let checkQuerySelectorException = Task.async(function*() {
|
||||||
|
info ("$ returns an exception if an invalid selector was provided");
|
||||||
|
let response = yield evaluateJS("$(':foo')");
|
||||||
|
checkObject(response, {
|
||||||
|
input: "$(':foo')",
|
||||||
|
exceptionMessage: "SyntaxError: ':foo' is not a valid selector",
|
||||||
|
exception: {
|
||||||
|
type: "object",
|
||||||
|
class: "DOMException",
|
||||||
|
preview: {
|
||||||
|
kind: "DOMException",
|
||||||
|
name: "SyntaxError",
|
||||||
|
message: "':foo' is not a valid selector"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nextTest();
|
||||||
|
});
|
||||||
|
|
||||||
let checkQuerySelectorAllException = Task.async(function*() {
|
let checkQuerySelectorAllException = Task.async(function*() {
|
||||||
info ("$$ returns an exception if an invalid selector was provided");
|
info ("$$ returns an exception if an invalid selector was provided");
|
||||||
let response = yield evaluateJS("$$(':foo')");
|
let response = yield evaluateJS("$$(':foo')");
|
||||||
|
@ -94,6 +114,8 @@ let checkQuerySelectorAllException = Task.async(function*() {
|
||||||
input: "$$(':foo')",
|
input: "$$(':foo')",
|
||||||
exceptionMessage: "SyntaxError: ':foo' is not a valid selector",
|
exceptionMessage: "SyntaxError: ':foo' is not a valid selector",
|
||||||
exception: {
|
exception: {
|
||||||
|
type: "object",
|
||||||
|
class: "DOMException",
|
||||||
preview: {
|
preview: {
|
||||||
kind: "DOMException",
|
kind: "DOMException",
|
||||||
name: "SyntaxError",
|
name: "SyntaxError",
|
||||||
|
|
|
@ -36,8 +36,20 @@ CustomElementCallback::Call()
|
||||||
// enqueue attached callback for ELEMENT.
|
// enqueue attached callback for ELEMENT.
|
||||||
nsIDocument* document = mThisObject->GetComposedDoc();
|
nsIDocument* document = mThisObject->GetComposedDoc();
|
||||||
if (document && document->GetDocShell()) {
|
if (document && document->GetDocShell()) {
|
||||||
|
NodeInfo* ni = mThisObject->NodeInfo();
|
||||||
|
nsDependentAtomString extType(mOwnerData->mType);
|
||||||
|
|
||||||
|
// We need to do this because at this point, CustomElementDefinition is
|
||||||
|
// not set to CustomElementData yet, so EnqueueLifecycleCallback will
|
||||||
|
// fail to find the CE definition for this custom element.
|
||||||
|
// This will go away eventually since there is no created callback in v1.
|
||||||
|
CustomElementDefinition* definition =
|
||||||
|
nsContentUtils::LookupCustomElementDefinition(document,
|
||||||
|
ni->LocalName(), ni->NamespaceID(),
|
||||||
|
extType.IsEmpty() ? nullptr : &extType);
|
||||||
|
|
||||||
nsContentUtils::EnqueueLifecycleCallback(
|
nsContentUtils::EnqueueLifecycleCallback(
|
||||||
document, nsIDocument::eAttached, mThisObject);
|
document, nsIDocument::eAttached, mThisObject, nullptr, definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
|
static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv);
|
||||||
|
@ -158,46 +170,15 @@ private:
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry)
|
||||||
tmp->mCustomDefinitions.Clear();
|
|
||||||
tmp->mConstructors.clear();
|
tmp->mConstructors.clear();
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomDefinitions)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
|
||||||
for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomDefinitions)
|
||||||
auto& callbacks = iter.UserData()->mCallbacks;
|
|
||||||
|
|
||||||
if (callbacks->mAttributeChangedCallback.WasPassed()) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
||||||
"mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
|
|
||||||
cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callbacks->mCreatedCallback.WasPassed()) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
||||||
"mCustomDefinitions->mCallbacks->mCreatedCallback");
|
|
||||||
cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callbacks->mAttachedCallback.WasPassed()) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
||||||
"mCustomDefinitions->mCallbacks->mAttachedCallback");
|
|
||||||
cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callbacks->mDetachedCallback.WasPassed()) {
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
||||||
"mCustomDefinitions->mCallbacks->mDetachedCallback");
|
|
||||||
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
||||||
"mCustomDefinitions->mConstructor");
|
|
||||||
cb.NoteXPCOMChild(iter.UserData()->mConstructor);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
@ -248,7 +229,7 @@ CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName
|
||||||
nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName);
|
nsCOMPtr<nsIAtom> localNameAtom = NS_Atomize(aLocalName);
|
||||||
nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
|
nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom;
|
||||||
|
|
||||||
CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom);
|
CustomElementDefinition* data = mCustomDefinitions.GetWeak(typeAtom);
|
||||||
if (data && data->mLocalName == localNameAtom) {
|
if (data && data->mLocalName == localNameAtom) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -267,7 +248,7 @@ CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomElementDefinition* definition = mCustomDefinitions.Get(ptr->value());
|
CustomElementDefinition* definition = mCustomDefinitions.GetWeak(ptr->value());
|
||||||
MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions");
|
MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions");
|
||||||
|
|
||||||
return definition;
|
return definition;
|
||||||
|
@ -286,7 +267,7 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
|
||||||
typeName = info->NameAtom();
|
typeName = info->NameAtom();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCustomDefinitions.Get(typeName)) {
|
if (mCustomDefinitions.GetWeak(typeName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,51 +326,35 @@ CustomElementRegistry::CreateCustomElementCallback(
|
||||||
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
||||||
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
|
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(aDefinition, "CustomElementDefinition should not be null");
|
||||||
|
|
||||||
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
|
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
|
||||||
MOZ_ASSERT(elementData, "CustomElementData should exist");
|
MOZ_ASSERT(elementData, "CustomElementData should exist");
|
||||||
|
|
||||||
// Let DEFINITION be ELEMENT's definition
|
|
||||||
CustomElementDefinition* definition = aDefinition;
|
|
||||||
if (!definition) {
|
|
||||||
mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
|
|
||||||
|
|
||||||
// Make sure we get the correct definition in case the element
|
|
||||||
// is a extended custom element e.g. <button is="x-button">.
|
|
||||||
nsCOMPtr<nsIAtom> typeAtom = elementData ?
|
|
||||||
elementData->mType.get() : info->NameAtom();
|
|
||||||
|
|
||||||
definition = mCustomDefinitions.Get(typeAtom);
|
|
||||||
if (!definition || definition->mLocalName != info->NameAtom()) {
|
|
||||||
// Trying to enqueue a callback for an element that is not
|
|
||||||
// a custom element. We are done, nothing to do.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
|
// Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
|
||||||
CallbackFunction* func = nullptr;
|
CallbackFunction* func = nullptr;
|
||||||
switch (aType) {
|
switch (aType) {
|
||||||
case nsIDocument::eCreated:
|
case nsIDocument::eCreated:
|
||||||
if (definition->mCallbacks->mCreatedCallback.WasPassed()) {
|
if (aDefinition->mCallbacks->mCreatedCallback.WasPassed()) {
|
||||||
func = definition->mCallbacks->mCreatedCallback.Value();
|
func = aDefinition->mCallbacks->mCreatedCallback.Value();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nsIDocument::eAttached:
|
case nsIDocument::eAttached:
|
||||||
if (definition->mCallbacks->mAttachedCallback.WasPassed()) {
|
if (aDefinition->mCallbacks->mAttachedCallback.WasPassed()) {
|
||||||
func = definition->mCallbacks->mAttachedCallback.Value();
|
func = aDefinition->mCallbacks->mAttachedCallback.Value();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nsIDocument::eDetached:
|
case nsIDocument::eDetached:
|
||||||
if (definition->mCallbacks->mDetachedCallback.WasPassed()) {
|
if (aDefinition->mCallbacks->mDetachedCallback.WasPassed()) {
|
||||||
func = definition->mCallbacks->mDetachedCallback.Value();
|
func = aDefinition->mCallbacks->mDetachedCallback.Value();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nsIDocument::eAttributeChanged:
|
case nsIDocument::eAttributeChanged:
|
||||||
if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
|
if (aDefinition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
|
||||||
func = definition->mCallbacks->mAttributeChangedCallback.Value();
|
func = aDefinition->mCallbacks->mAttributeChangedCallback.Value();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -445,21 +410,11 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
||||||
LifecycleCallbackArgs* aArgs,
|
LifecycleCallbackArgs* aArgs,
|
||||||
CustomElementDefinition* aDefinition)
|
CustomElementDefinition* aDefinition)
|
||||||
{
|
{
|
||||||
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
|
|
||||||
MOZ_ASSERT(elementData, "CustomElementData should exist");
|
|
||||||
|
|
||||||
// Let DEFINITION be ELEMENT's definition
|
|
||||||
CustomElementDefinition* definition = aDefinition;
|
CustomElementDefinition* definition = aDefinition;
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
|
definition = aCustomElement->GetCustomElementDefinition();
|
||||||
|
if (!definition ||
|
||||||
// Make sure we get the correct definition in case the element
|
definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) {
|
||||||
// is a extended custom element e.g. <button is="x-button">.
|
|
||||||
nsCOMPtr<nsIAtom> typeAtom = elementData ?
|
|
||||||
elementData->mType.get() : info->NameAtom();
|
|
||||||
|
|
||||||
definition = mCustomDefinitions.Get(typeAtom);
|
|
||||||
if (!definition || definition->mLocalName != info->NameAtom()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,7 +448,8 @@ void
|
||||||
CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
|
CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
|
||||||
JS::MutableHandle<JSObject*> aPrototype)
|
JS::MutableHandle<JSObject*> aPrototype)
|
||||||
{
|
{
|
||||||
mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom);
|
mozilla::dom::CustomElementDefinition* definition =
|
||||||
|
mCustomDefinitions.GetWeak(aAtom);
|
||||||
if (definition) {
|
if (definition) {
|
||||||
aPrototype.set(definition->mPrototype);
|
aPrototype.set(definition->mPrototype);
|
||||||
} else {
|
} else {
|
||||||
|
@ -631,7 +587,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||||
* 3. If this CustomElementRegistry contains an entry with name name, then
|
* 3. If this CustomElementRegistry contains an entry with name name, then
|
||||||
* throw a "NotSupportedError" DOMException and abort these steps.
|
* throw a "NotSupportedError" DOMException and abort these steps.
|
||||||
*/
|
*/
|
||||||
if (mCustomDefinitions.Get(nameAtom)) {
|
if (mCustomDefinitions.GetWeak(nameAtom)) {
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -642,7 +598,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||||
*/
|
*/
|
||||||
const auto& ptr = mConstructors.lookup(constructorUnwrapped);
|
const auto& ptr = mConstructors.lookup(constructorUnwrapped);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
MOZ_ASSERT(mCustomDefinitions.Get(ptr->value()),
|
MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()),
|
||||||
"Definition must be found in mCustomDefinitions");
|
"Definition must be found in mCustomDefinitions");
|
||||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return;
|
return;
|
||||||
|
@ -834,7 +790,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomElementDefinition* definition =
|
RefPtr<CustomElementDefinition> definition =
|
||||||
new CustomElementDefinition(nameAtom,
|
new CustomElementDefinition(nameAtom,
|
||||||
localNameAtom,
|
localNameAtom,
|
||||||
&aFunctionConstructor,
|
&aFunctionConstructor,
|
||||||
|
@ -843,7 +799,8 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||||
callbacks,
|
callbacks,
|
||||||
0 /* TODO dependent on HTML imports. Bug 877072 */);
|
0 /* TODO dependent on HTML imports. Bug 877072 */);
|
||||||
|
|
||||||
mCustomDefinitions.Put(nameAtom, definition);
|
CustomElementDefinition* def = definition.get();
|
||||||
|
mCustomDefinitions.Put(nameAtom, definition.forget());
|
||||||
|
|
||||||
MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
|
MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
|
||||||
"Number of entries should be the same");
|
"Number of entries should be the same");
|
||||||
|
@ -851,7 +808,7 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||||
/**
|
/**
|
||||||
* 13. 14. 15. Upgrade candidates
|
* 13. 14. 15. Upgrade candidates
|
||||||
*/
|
*/
|
||||||
UpgradeCandidates(nameAtom, definition, aRv);
|
UpgradeCandidates(nameAtom, def, aRv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 16. If this CustomElementRegistry's when-defined promise map contains an
|
* 16. If this CustomElementRegistry's when-defined promise map contains an
|
||||||
|
@ -874,7 +831,7 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName,
|
||||||
JS::MutableHandle<JS::Value> aRetVal)
|
JS::MutableHandle<JS::Value> aRetVal)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
|
nsCOMPtr<nsIAtom> nameAtom(NS_Atomize(aName));
|
||||||
CustomElementDefinition* data = mCustomDefinitions.Get(nameAtom);
|
CustomElementDefinition* data = mCustomDefinitions.GetWeak(nameAtom);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
aRetVal.setUndefined();
|
aRetVal.setUndefined();
|
||||||
|
@ -900,7 +857,7 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
|
||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCustomDefinitions.Get(nameAtom)) {
|
if (mCustomDefinitions.GetWeak(nameAtom)) {
|
||||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
@ -1004,6 +961,9 @@ CustomElementRegistry::Upgrade(Element* aElement,
|
||||||
// Step 8.
|
// Step 8.
|
||||||
data->mState = CustomElementData::State::eCustom;
|
data->mState = CustomElementData::State::eCustom;
|
||||||
|
|
||||||
|
// Step 9.
|
||||||
|
aElement->SetCustomElementDefinition(aDefinition);
|
||||||
|
|
||||||
// This is for old spec.
|
// This is for old spec.
|
||||||
nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
|
nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
|
||||||
nsIDocument::eCreated,
|
nsIDocument::eCreated,
|
||||||
|
@ -1156,6 +1116,50 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue,
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
// CustomElementDefinition
|
// CustomElementDefinition
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementDefinition)
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementDefinition)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructor)
|
||||||
|
tmp->mPrototype = nullptr;
|
||||||
|
tmp->mCallbacks = nullptr;
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementDefinition)
|
||||||
|
mozilla::dom::LifecycleCallbacks* callbacks = tmp->mCallbacks.get();
|
||||||
|
|
||||||
|
if (callbacks->mAttributeChangedCallback.WasPassed()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||||
|
"mCallbacks->mAttributeChangedCallback");
|
||||||
|
cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callbacks->mCreatedCallback.WasPassed()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mCreatedCallback");
|
||||||
|
cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callbacks->mAttachedCallback.WasPassed()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mAttachedCallback");
|
||||||
|
cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callbacks->mDetachedCallback.WasPassed()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mDetachedCallback");
|
||||||
|
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mConstructor");
|
||||||
|
cb.NoteXPCOMChild(tmp->mConstructor);
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementDefinition)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPrototype)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CustomElementDefinition, AddRef)
|
||||||
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CustomElementDefinition, Release)
|
||||||
|
|
||||||
|
|
||||||
CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
||||||
nsIAtom* aLocalName,
|
nsIAtom* aLocalName,
|
||||||
Function* aConstructor,
|
Function* aConstructor,
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
#include "mozilla/dom/BindingDeclarations.h"
|
#include "mozilla/dom/BindingDeclarations.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
#include "mozilla/dom/FunctionBinding.h"
|
#include "mozilla/dom/FunctionBinding.h"
|
||||||
|
#include "mozilla/dom/WebComponentsBinding.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsGenericHTMLElement.h"
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
|
||||||
|
@ -25,7 +27,6 @@ namespace dom {
|
||||||
|
|
||||||
struct CustomElementData;
|
struct CustomElementData;
|
||||||
struct ElementDefinitionOptions;
|
struct ElementDefinitionOptions;
|
||||||
struct LifecycleCallbacks;
|
|
||||||
class CallbackFunction;
|
class CallbackFunction;
|
||||||
class CustomElementReaction;
|
class CustomElementReaction;
|
||||||
class Function;
|
class Function;
|
||||||
|
@ -117,6 +118,22 @@ struct CustomElementData
|
||||||
// e.g., create an element, insert a node.
|
// e.g., create an element, insert a node.
|
||||||
AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
|
AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
|
||||||
|
|
||||||
|
RefPtr<CustomElementDefinition> mCustomElementDefinition;
|
||||||
|
|
||||||
|
void
|
||||||
|
SetCustomElementDefinition(CustomElementDefinition* aDefinition)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mCustomElementDefinition);
|
||||||
|
|
||||||
|
mCustomElementDefinition = aDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomElementDefinition*
|
||||||
|
GetCustomElementDefinition()
|
||||||
|
{
|
||||||
|
return mCustomElementDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~CustomElementData() {}
|
virtual ~CustomElementData() {}
|
||||||
};
|
};
|
||||||
|
@ -127,6 +144,9 @@ private:
|
||||||
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
|
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
|
||||||
struct CustomElementDefinition
|
struct CustomElementDefinition
|
||||||
{
|
{
|
||||||
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition)
|
||||||
|
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition)
|
||||||
|
|
||||||
CustomElementDefinition(nsIAtom* aType,
|
CustomElementDefinition(nsIAtom* aType,
|
||||||
nsIAtom* aLocalName,
|
nsIAtom* aLocalName,
|
||||||
Function* aConstructor,
|
Function* aConstructor,
|
||||||
|
@ -172,6 +192,9 @@ struct CustomElementDefinition
|
||||||
|
|
||||||
return mObservedAttributes.Contains(aName);
|
return mObservedAttributes.Contains(aName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~CustomElementDefinition() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CustomElementReaction
|
class CustomElementReaction
|
||||||
|
@ -394,7 +417,7 @@ private:
|
||||||
CustomElementDefinition* aDefinition,
|
CustomElementDefinition* aDefinition,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition>
|
typedef nsRefPtrHashtable<nsISupportsHashKey, CustomElementDefinition>
|
||||||
DefinitionMap;
|
DefinitionMap;
|
||||||
typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
|
typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
|
||||||
CandidateMap;
|
CandidateMap;
|
||||||
|
|
|
@ -3581,7 +3581,7 @@ Element::GetTransformToAncestor(Element& aAncestor)
|
||||||
// then the call to GetTransformToAncestor will return the transform
|
// then the call to GetTransformToAncestor will return the transform
|
||||||
// all the way up through the parent chain.
|
// all the way up through the parent chain.
|
||||||
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
||||||
ancestorFrame, true);
|
ancestorFrame, nsIFrame::IN_CSS_UNITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
||||||
|
@ -3598,7 +3598,7 @@ Element::GetTransformToParent()
|
||||||
if (primaryFrame) {
|
if (primaryFrame) {
|
||||||
nsIFrame* parentFrame = primaryFrame->GetParent();
|
nsIFrame* parentFrame = primaryFrame->GetParent();
|
||||||
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
||||||
parentFrame, true);
|
parentFrame, nsIFrame::IN_CSS_UNITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
||||||
|
@ -3613,7 +3613,7 @@ Element::GetTransformToViewport()
|
||||||
Matrix4x4 transform;
|
Matrix4x4 transform;
|
||||||
if (primaryFrame) {
|
if (primaryFrame) {
|
||||||
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
transform = nsLayoutUtils::GetTransformToAncestor(primaryFrame,
|
||||||
nsLayoutUtils::GetDisplayRootFrame(primaryFrame), true);
|
nsLayoutUtils::GetDisplayRootFrame(primaryFrame), nsIFrame::IN_CSS_UNITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
DOMMatrixReadOnly* matrix = new DOMMatrix(this, transform);
|
||||||
|
@ -4214,6 +4214,26 @@ Element::SetCustomElementData(CustomElementData* aData)
|
||||||
slots->mCustomElementData = aData;
|
slots->mCustomElementData = aData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CustomElementDefinition*
|
||||||
|
Element::GetCustomElementDefinition() const
|
||||||
|
{
|
||||||
|
CustomElementData* data = GetCustomElementData();
|
||||||
|
if (!data) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data->GetCustomElementDefinition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Element::SetCustomElementDefinition(CustomElementDefinition* aDefinition)
|
||||||
|
{
|
||||||
|
CustomElementData* data = GetCustomElementData();
|
||||||
|
MOZ_ASSERT(data);
|
||||||
|
|
||||||
|
data->SetCustomElementDefinition(aDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_DEFINE_MALLOC_SIZE_OF(ServoElementMallocSizeOf)
|
MOZ_DEFINE_MALLOC_SIZE_OF(ServoElementMallocSizeOf)
|
||||||
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoElementMallocEnclosingSizeOf)
|
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoElementMallocEnclosingSizeOf)
|
||||||
|
|
||||||
|
|
|
@ -556,6 +556,22 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetCustomElementData(CustomElementData* aData);
|
void SetCustomElementData(CustomElementData* aData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the custom element definition used by web components custom element.
|
||||||
|
*
|
||||||
|
* @return The custom element definition or null if element is not a custom
|
||||||
|
* element or custom element is not defined yet.
|
||||||
|
*/
|
||||||
|
CustomElementDefinition* GetCustomElementDefinition() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the custom element definition, called when custom element is created
|
||||||
|
* or upgraded.
|
||||||
|
*
|
||||||
|
* @param aDefinition The custom element definition.
|
||||||
|
*/
|
||||||
|
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Method to get the _intrinsic_ content state of this element. This is the
|
* Method to get the _intrinsic_ content state of this element. This is the
|
||||||
|
|
|
@ -812,6 +812,13 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||||
mExtendedSlots->mCustomElementData->mReactionQueue[i]->Traverse(cb);
|
mExtendedSlots->mCustomElementData->mReactionQueue[i]->Traverse(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mExtendedSlots->mCustomElementData->mCustomElementDefinition) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||||
|
"mExtendedSlots->mCustomElementData->mCustomElementDefinition");
|
||||||
|
cb.NoteNativeChild(mExtendedSlots->mCustomElementData->mCustomElementDefinition,
|
||||||
|
NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter();
|
for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter();
|
||||||
|
@ -848,7 +855,12 @@ FragmentOrElement::nsDOMSlots::Unlink()
|
||||||
mExtendedSlots->mContainingShadow = nullptr;
|
mExtendedSlots->mContainingShadow = nullptr;
|
||||||
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
|
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
|
||||||
mExtendedSlots->mXBLInsertionParent = nullptr;
|
mExtendedSlots->mXBLInsertionParent = nullptr;
|
||||||
|
if (mExtendedSlots->mCustomElementData) {
|
||||||
|
if (mExtendedSlots->mCustomElementData->mCustomElementDefinition) {
|
||||||
|
mExtendedSlots->mCustomElementData->mCustomElementDefinition = nullptr;
|
||||||
|
}
|
||||||
mExtendedSlots->mCustomElementData = nullptr;
|
mExtendedSlots->mCustomElementData = nullptr;
|
||||||
|
}
|
||||||
mExtendedSlots->mRegisteredIntersectionObservers.Clear();
|
mExtendedSlots->mRegisteredIntersectionObservers.Clear();
|
||||||
nsCOMPtr<nsIFrameLoader> frameLoader =
|
nsCOMPtr<nsIFrameLoader> frameLoader =
|
||||||
do_QueryInterface(mExtendedSlots->mFrameLoaderOrOpener);
|
do_QueryInterface(mExtendedSlots->mFrameLoaderOrOpener);
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_RangeBoundary_h
|
||||||
|
#define mozilla_RangeBoundary_h
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
// This class will maintain a reference to the child immediately
|
||||||
|
// before the boundary's offset. We try to avoid computing the
|
||||||
|
// offset as much as possible and just ensure mRef points to the
|
||||||
|
// correct child.
|
||||||
|
//
|
||||||
|
// mParent
|
||||||
|
// |
|
||||||
|
// [child0] [child1] [child2]
|
||||||
|
// / |
|
||||||
|
// mRef mOffset=2
|
||||||
|
//
|
||||||
|
// If mOffset == 0, mRef is null.
|
||||||
|
// For text nodes, mRef will always be null and the offset will
|
||||||
|
// be kept up-to-date.
|
||||||
|
|
||||||
|
template<typename ParentType, typename RefType>
|
||||||
|
class RangeBoundaryBase;
|
||||||
|
|
||||||
|
typedef RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>> RangeBoundary;
|
||||||
|
typedef RangeBoundaryBase<nsINode*, nsIContent*> RawRangeBoundary;
|
||||||
|
|
||||||
|
// This class has two specializations, one using reference counting
|
||||||
|
// pointers and one using raw pointers. This helps us avoid unnecessary
|
||||||
|
// AddRef/Release calls.
|
||||||
|
template<typename ParentType, typename RefType>
|
||||||
|
class RangeBoundaryBase
|
||||||
|
{
|
||||||
|
template<typename T, typename U>
|
||||||
|
friend class RangeBoundaryBase;
|
||||||
|
|
||||||
|
friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
|
||||||
|
RangeBoundary&, const char*,
|
||||||
|
uint32_t);
|
||||||
|
friend void ImplCycleCollectionUnlink(RangeBoundary&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef)
|
||||||
|
: mParent(aContainer)
|
||||||
|
, mRef(aRef)
|
||||||
|
{
|
||||||
|
if (!mRef) {
|
||||||
|
mOffset = mozilla::Some(0);
|
||||||
|
} else {
|
||||||
|
mOffset.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeBoundaryBase(nsINode* aContainer, int32_t aOffset)
|
||||||
|
: mParent(aContainer)
|
||||||
|
, mRef(nullptr)
|
||||||
|
, mOffset(mozilla::Some(aOffset))
|
||||||
|
{
|
||||||
|
if (mParent && mParent->IsContainerNode()) {
|
||||||
|
// Find a reference node
|
||||||
|
if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) {
|
||||||
|
mRef = aContainer->GetLastChild();
|
||||||
|
} else if (aOffset != 0) {
|
||||||
|
mRef = mParent->GetChildAt(aOffset - 1);
|
||||||
|
MOZ_ASSERT(mRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(!mRef, aOffset == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(mRef, mRef->GetParentNode() == mParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeBoundaryBase()
|
||||||
|
: mParent(nullptr)
|
||||||
|
, mRef(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed for initializing RawRangeBoundary from an existing RangeBoundary.
|
||||||
|
template<typename PT, typename RT>
|
||||||
|
explicit RangeBoundaryBase(const RangeBoundaryBase<PT, RT>& aOther)
|
||||||
|
: mParent(aOther.mParent)
|
||||||
|
, mRef(aOther.mRef)
|
||||||
|
, mOffset(aOther.mOffset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent*
|
||||||
|
Ref() const
|
||||||
|
{
|
||||||
|
return mRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsINode*
|
||||||
|
Container() const
|
||||||
|
{
|
||||||
|
return mParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent*
|
||||||
|
GetChildAtOffset() const
|
||||||
|
{
|
||||||
|
if (!mParent || !mParent->IsContainerNode()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!mRef) {
|
||||||
|
MOZ_ASSERT(Offset() == 0);
|
||||||
|
return mParent->GetFirstChild();
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(mParent->GetChildAt(Offset()) == mRef->GetNextSibling());
|
||||||
|
return mRef->GetNextSibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
Offset() const
|
||||||
|
{
|
||||||
|
if (mOffset.isSome()) {
|
||||||
|
return mOffset.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mParent) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mRef);
|
||||||
|
MOZ_ASSERT(mRef->GetParentNode() == mParent);
|
||||||
|
mOffset = mozilla::Some(mParent->IndexOf(mRef) + 1);
|
||||||
|
|
||||||
|
return mOffset.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InvalidateOffset()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mParent);
|
||||||
|
MOZ_ASSERT(mParent->IsContainerNode(), "Range is positioned on a text node!");
|
||||||
|
|
||||||
|
if (!mRef) {
|
||||||
|
MOZ_ASSERT(mOffset.isSome() && mOffset.value() == 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mOffset.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Set(nsINode* aContainer, int32_t aOffset)
|
||||||
|
{
|
||||||
|
mParent = aContainer;
|
||||||
|
if (mParent && mParent->IsContainerNode()) {
|
||||||
|
// Find a reference node
|
||||||
|
if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) {
|
||||||
|
mRef = aContainer->GetLastChild();
|
||||||
|
} else if (aOffset == 0) {
|
||||||
|
mRef = nullptr;
|
||||||
|
} else {
|
||||||
|
mRef = mParent->GetChildAt(aOffset - 1);
|
||||||
|
MOZ_ASSERT(mRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(!mRef, aOffset == 0);
|
||||||
|
} else {
|
||||||
|
mRef = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOffset = mozilla::Some(aOffset);
|
||||||
|
MOZ_ASSERT_IF(mRef, mRef->GetParentNode() == mParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetAfterRef(nsINode* aParent, nsIContent* aRef)
|
||||||
|
{
|
||||||
|
mParent = aParent;
|
||||||
|
mRef = aRef;
|
||||||
|
if (!mRef) {
|
||||||
|
mOffset = mozilla::Some(0);
|
||||||
|
} else {
|
||||||
|
mOffset.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsSet() const
|
||||||
|
{
|
||||||
|
return mParent && (mRef || mOffset.isSome());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsSetAndValid() const
|
||||||
|
{
|
||||||
|
if (!IsSet()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Ref()) {
|
||||||
|
return Ref()->GetParentNode() == Container();
|
||||||
|
}
|
||||||
|
return Offset() <= Container()->Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience methods for switching between the two types
|
||||||
|
// of RangeBoundary.
|
||||||
|
RangeBoundaryBase<nsINode*, nsIContent*>
|
||||||
|
AsRaw() const
|
||||||
|
{
|
||||||
|
return RangeBoundaryBase<nsINode*, nsIContent*>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A, typename B>
|
||||||
|
RangeBoundaryBase& operator=(const RangeBoundaryBase<A,B>& aOther)
|
||||||
|
{
|
||||||
|
mParent = aOther.mParent;
|
||||||
|
mRef = aOther.mRef;
|
||||||
|
mOffset = aOther.mOffset;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A, typename B>
|
||||||
|
bool operator==(const RangeBoundaryBase<A, B>& aOther) const
|
||||||
|
{
|
||||||
|
return mParent == aOther.mParent &&
|
||||||
|
(mRef ? mRef == aOther.mRef : mOffset == aOther.mOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParentType mParent;
|
||||||
|
RefType mRef;
|
||||||
|
|
||||||
|
mutable mozilla::Maybe<uint32_t> mOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ImplCycleCollectionUnlink(RangeBoundary& aField)
|
||||||
|
{
|
||||||
|
ImplCycleCollectionUnlink(aField.mParent);
|
||||||
|
ImplCycleCollectionUnlink(aField.mRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||||
|
RangeBoundary& aField,
|
||||||
|
const char* aName,
|
||||||
|
uint32_t aFlags)
|
||||||
|
{
|
||||||
|
ImplCycleCollectionTraverse(aCallback, aField.mParent, "mParent", 0);
|
||||||
|
ImplCycleCollectionTraverse(aCallback, aField.mRef, "mRef", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // defined(mozilla_RangeBoundary_h)
|
|
@ -140,6 +140,7 @@ EXPORTS.mozilla += [
|
||||||
'CORSMode.h',
|
'CORSMode.h',
|
||||||
'FeedWriterEnabled.h',
|
'FeedWriterEnabled.h',
|
||||||
'FlushType.h',
|
'FlushType.h',
|
||||||
|
'RangeBoundary.h',
|
||||||
'TextInputProcessor.h',
|
'TextInputProcessor.h',
|
||||||
'UseCounter.h',
|
'UseCounter.h',
|
||||||
]
|
]
|
||||||
|
|
|
@ -10122,13 +10122,8 @@ nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement,
|
||||||
nsIAtom* aExtensionType,
|
nsIAtom* aExtensionType,
|
||||||
nsIAtom* aAttrName)
|
nsIAtom* aAttrName)
|
||||||
{
|
{
|
||||||
nsString extType = nsDependentAtomString(aExtensionType);
|
|
||||||
NodeInfo *ni = aCustomElement->NodeInfo();
|
|
||||||
|
|
||||||
CustomElementDefinition* definition =
|
CustomElementDefinition* definition =
|
||||||
LookupCustomElementDefinition(aCustomElement->OwnerDoc(), ni->LocalName(),
|
aCustomElement->GetCustomElementDefinition();
|
||||||
ni->NamespaceID(),
|
|
||||||
extType.IsEmpty() ? nullptr : &extType);
|
|
||||||
|
|
||||||
// Custom element not defined yet or attribute is not in the observed
|
// Custom element not defined yet or attribute is not in the observed
|
||||||
// attribute list.
|
// attribute list.
|
||||||
|
|
|
@ -3039,37 +3039,6 @@ nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
|
||||||
return presShell->RenderDocument(aRect, aFlags, aBackgroundColor, aThebesContext);
|
return presShell->RenderDocument(aRect, aFlags, aBackgroundColor, aThebesContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsDOMWindowUtils::GetCursorType(int16_t *aCursor)
|
|
||||||
{
|
|
||||||
NS_ENSURE_ARG_POINTER(aCursor);
|
|
||||||
|
|
||||||
nsIDocument* doc = GetDocument();
|
|
||||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
bool isSameDoc = false;
|
|
||||||
do {
|
|
||||||
if (EventStateManager::sMouseOverDocument == doc) {
|
|
||||||
isSameDoc = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while ((doc = doc->GetParentDocument()));
|
|
||||||
|
|
||||||
if (!isSameDoc) {
|
|
||||||
*aCursor = eCursor_none;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
|
||||||
if (!widget)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
// fetch cursor value from window's widget
|
|
||||||
*aCursor = widget->GetCursor();
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDOMWindowUtils::GetDisplayDPI(float *aDPI)
|
nsDOMWindowUtils::GetDisplayDPI(float *aDPI)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6313,7 +6313,8 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
|
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
|
||||||
CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom);
|
CustomElementDefinition* definition =
|
||||||
|
registry->mCustomDefinitions.GetWeak(typeAtom);
|
||||||
if (!definition) {
|
if (!definition) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6383,6 +6384,8 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value*
|
||||||
new CustomElementData(definition->mType,
|
new CustomElementData(definition->mType,
|
||||||
CustomElementData::State::eCustom));
|
CustomElementData::State::eCustom));
|
||||||
|
|
||||||
|
element->SetCustomElementDefinition(definition);
|
||||||
|
|
||||||
// It'll be removed when we deprecate custom elements v0.
|
// It'll be removed when we deprecate custom elements v0.
|
||||||
nsContentUtils::SyncInvokeReactions(nsIDocument::eCreated, element,
|
nsContentUtils::SyncInvokeReactions(nsIDocument::eCreated, element,
|
||||||
definition);
|
definition);
|
||||||
|
|
|
@ -357,10 +357,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStart.mParent)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStart)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStart.mRef)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEnd)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEnd.mParent)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEnd.mRef)
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/GuardObjects.h"
|
#include "mozilla/GuardObjects.h"
|
||||||
#include "mozilla/LinkedList.h"
|
#include "mozilla/LinkedList.h"
|
||||||
|
#include "mozilla/RangeBoundary.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
class ErrorResult;
|
class ErrorResult;
|
||||||
|
@ -44,6 +45,8 @@ class nsRange final : public nsIDOMRange,
|
||||||
typedef mozilla::ErrorResult ErrorResult;
|
typedef mozilla::ErrorResult ErrorResult;
|
||||||
typedef mozilla::dom::DOMRect DOMRect;
|
typedef mozilla::dom::DOMRect DOMRect;
|
||||||
typedef mozilla::dom::DOMRectList DOMRectList;
|
typedef mozilla::dom::DOMRectList DOMRectList;
|
||||||
|
typedef mozilla::RangeBoundary RangeBoundary;
|
||||||
|
typedef mozilla::RawRangeBoundary RawRangeBoundary;
|
||||||
|
|
||||||
virtual ~nsRange();
|
virtual ~nsRange();
|
||||||
|
|
||||||
|
@ -82,11 +85,21 @@ public:
|
||||||
return mRoot;
|
return mRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RangeBoundary& StartRef() const
|
||||||
|
{
|
||||||
|
return mStart;
|
||||||
|
}
|
||||||
|
|
||||||
nsINode* GetStartContainer() const
|
nsINode* GetStartContainer() const
|
||||||
{
|
{
|
||||||
return mStart.Container();
|
return mStart.Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RangeBoundary& EndRef() const
|
||||||
|
{
|
||||||
|
return mEnd;
|
||||||
|
}
|
||||||
|
|
||||||
nsINode* GetEndContainer() const
|
nsINode* GetEndContainer() const
|
||||||
{
|
{
|
||||||
return mEnd.Container();
|
return mEnd.Container();
|
||||||
|
@ -412,215 +425,6 @@ public:
|
||||||
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
|
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// This class has two specializations, one using reference counting
|
|
||||||
// pointers and one using raw pointers. This helps us avoid unnecessary
|
|
||||||
// AddRef/Release calls.
|
|
||||||
template<typename ParentType, typename RefType>
|
|
||||||
class RangeBoundaryBase
|
|
||||||
{
|
|
||||||
// This class will maintain a reference to the child immediately
|
|
||||||
// before the boundary's offset. We try to avoid computing the
|
|
||||||
// offset as much as possible and just ensure mRef points to the
|
|
||||||
// correct child.
|
|
||||||
//
|
|
||||||
// mParent
|
|
||||||
// |
|
|
||||||
// [child0] [child1] [child2]
|
|
||||||
// / |
|
|
||||||
// mRef mOffset=2
|
|
||||||
//
|
|
||||||
// If mOffset == 0, mRef is null.
|
|
||||||
// For text nodes, mRef will always be null and the offset will
|
|
||||||
// be kept up-to-date.
|
|
||||||
|
|
||||||
// for cycle collecting mParent and mRef;
|
|
||||||
friend class nsRange;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef)
|
|
||||||
: mParent(aContainer)
|
|
||||||
, mRef(aRef)
|
|
||||||
{
|
|
||||||
if (!mRef) {
|
|
||||||
mOffset = mozilla::Some(0);
|
|
||||||
} else {
|
|
||||||
mOffset.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RangeBoundaryBase(nsINode* aContainer, int32_t aOffset)
|
|
||||||
: mParent(aContainer)
|
|
||||||
, mRef(nullptr)
|
|
||||||
, mOffset(mozilla::Some(aOffset))
|
|
||||||
{
|
|
||||||
if (mParent && mParent->IsContainerNode()) {
|
|
||||||
// Find a reference node
|
|
||||||
if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) {
|
|
||||||
mRef = aContainer->GetLastChild();
|
|
||||||
} else if (aOffset != 0) {
|
|
||||||
mRef = mParent->GetChildAt(aOffset - 1);
|
|
||||||
MOZ_ASSERT(mRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(!mRef, aOffset == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(mRef, mRef->GetParentNode() == mParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
RangeBoundaryBase()
|
|
||||||
: mParent(nullptr)
|
|
||||||
, mRef(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed for initializing RawRangeBoundary from an existing RangeBoundary.
|
|
||||||
explicit RangeBoundaryBase(const RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>>& aOther)
|
|
||||||
: mParent(aOther.mParent)
|
|
||||||
, mRef(aOther.mRef)
|
|
||||||
, mOffset(aOther.mOffset)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIContent*
|
|
||||||
Ref() const
|
|
||||||
{
|
|
||||||
return mRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsINode*
|
|
||||||
Container() const
|
|
||||||
{
|
|
||||||
return mParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIContent*
|
|
||||||
GetChildAtOffset() const
|
|
||||||
{
|
|
||||||
if (!mParent || !mParent->IsContainerNode()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!mRef) {
|
|
||||||
MOZ_ASSERT(Offset() == 0);
|
|
||||||
return mParent->GetFirstChild();
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(mParent->GetChildAt(Offset()) == mRef->GetNextSibling());
|
|
||||||
return mRef->GetNextSibling();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
Offset() const
|
|
||||||
{
|
|
||||||
if (mOffset.isSome()) {
|
|
||||||
return mOffset.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mParent) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mRef);
|
|
||||||
MOZ_ASSERT(mRef->GetParentNode() == mParent);
|
|
||||||
mOffset = mozilla::Some(mParent->IndexOf(mRef) + 1);
|
|
||||||
|
|
||||||
return mOffset.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
InvalidateOffset()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mParent);
|
|
||||||
MOZ_ASSERT(mParent->IsContainerNode(), "Range is positioned on a text node!");
|
|
||||||
|
|
||||||
if (!mRef) {
|
|
||||||
MOZ_ASSERT(mOffset.isSome() && mOffset.value() == 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mOffset.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AdjustOffset(int32_t aDelta)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRef);
|
|
||||||
mOffset = mozilla::Some(Offset() + aDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Set(nsINode* aContainer, int32_t aOffset)
|
|
||||||
{
|
|
||||||
mParent = aContainer;
|
|
||||||
if (mParent && mParent->IsContainerNode()) {
|
|
||||||
// Find a reference node
|
|
||||||
if (aOffset == static_cast<int32_t>(aContainer->GetChildCount())) {
|
|
||||||
mRef = aContainer->GetLastChild();
|
|
||||||
} else if (aOffset == 0) {
|
|
||||||
mRef = nullptr;
|
|
||||||
} else {
|
|
||||||
mRef = mParent->GetChildAt(aOffset - 1);
|
|
||||||
MOZ_ASSERT(mRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(!mRef, aOffset == 0);
|
|
||||||
} else {
|
|
||||||
mRef = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
mOffset = mozilla::Some(aOffset);
|
|
||||||
MOZ_ASSERT_IF(mRef, mRef->GetParentNode() == mParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SetAfterRef(nsINode* aParent, nsIContent* aRef)
|
|
||||||
{
|
|
||||||
mParent = aParent;
|
|
||||||
mRef = aRef;
|
|
||||||
if (!mRef) {
|
|
||||||
mOffset = mozilla::Some(0);
|
|
||||||
} else {
|
|
||||||
mOffset.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IsSet() const
|
|
||||||
{
|
|
||||||
return mParent && (mRef || mOffset.isSome());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convenience methods for switching between the two types
|
|
||||||
// of RangeBoundary.
|
|
||||||
RangeBoundaryBase<nsINode*, nsIContent*>
|
|
||||||
AsRaw() const
|
|
||||||
{
|
|
||||||
return RangeBoundaryBase<nsINode*, nsIContent*>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename A, typename B>
|
|
||||||
RangeBoundaryBase& operator=(const RangeBoundaryBase<A,B>& aOther)
|
|
||||||
{
|
|
||||||
// Since the member variables may be nsCOMPtrs, better to try to avoid
|
|
||||||
// extra Release/AddRef calls.
|
|
||||||
if (mParent != aOther.mParent) {
|
|
||||||
mParent = aOther.mParent;
|
|
||||||
}
|
|
||||||
if (mRef != aOther.mRef) {
|
|
||||||
mRef = aOther.mRef;
|
|
||||||
}
|
|
||||||
mOffset = aOther.mOffset;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ParentType mParent;
|
|
||||||
RefType mRef;
|
|
||||||
|
|
||||||
mutable mozilla::Maybe<uint32_t> mOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef RangeBoundaryBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent>> RangeBoundary;
|
|
||||||
typedef RangeBoundaryBase<nsINode*, nsIContent*> RawRangeBoundary;
|
|
||||||
|
|
||||||
void RegisterCommonAncestor(nsINode* aNode);
|
void RegisterCommonAncestor(nsINode* aNode);
|
||||||
void UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking);
|
void UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking);
|
||||||
nsINode* IsValidBoundary(nsINode* aNode) const
|
nsINode* IsValidBoundary(nsINode* aNode) const
|
||||||
|
|
|
@ -3682,6 +3682,8 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
|
||||||
newElement->SetCustomElementData(
|
newElement->SetCustomElementData(
|
||||||
new CustomElementData(definition->mType, CustomElementData::State::eCustom));
|
new CustomElementData(definition->mType, CustomElementData::State::eCustom));
|
||||||
|
|
||||||
|
newElement->SetCustomElementDefinition(definition);
|
||||||
|
|
||||||
return newElement.forget();
|
return newElement.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,69 +47,56 @@ void
|
||||||
ContentEventHandler::RawRange::AssertStartIsBeforeOrEqualToEnd()
|
ContentEventHandler::RawRange::AssertStartIsBeforeOrEqualToEnd()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(
|
||||||
nsContentUtils::ComparePoints(mStartContainer,
|
nsContentUtils::ComparePoints(mStart.Container(),
|
||||||
static_cast<int32_t>(mStartOffset),
|
static_cast<int32_t>(mStart.Offset()),
|
||||||
mEndContainer,
|
mEnd.Container(),
|
||||||
static_cast<int32_t>(mEndOffset)) <= 0);
|
static_cast<int32_t>(mEnd.Offset())) <= 0);
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ContentEventHandler::RawRange::IsValidOffset(nsINode* aContainer,
|
|
||||||
uint32_t aOffset) const
|
|
||||||
{
|
|
||||||
return aContainer && aOffset <= aContainer->Length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ContentEventHandler::RawRange::SetStart(nsINode* aStartContainer,
|
ContentEventHandler::RawRange::SetStart(const RawRangeBoundary& aStart)
|
||||||
uint32_t aStartOffset)
|
|
||||||
{
|
{
|
||||||
nsINode* newRoot = nsRange::ComputeRootNode(aStartContainer);
|
nsINode* newRoot = nsRange::ComputeRootNode(aStart.Container());
|
||||||
if (!newRoot) {
|
if (!newRoot) {
|
||||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidOffset(aStartContainer, aStartOffset)) {
|
if (!aStart.IsSetAndValid()) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapse if not positioned yet, or if positioned in another document.
|
// Collapse if not positioned yet, or if positioned in another document.
|
||||||
if (!IsPositioned() || newRoot != mRoot) {
|
if (!IsPositioned() || newRoot != mRoot) {
|
||||||
mRoot = newRoot;
|
mRoot = newRoot;
|
||||||
mStartContainer = mEndContainer = aStartContainer;
|
mStart = mEnd = aStart;
|
||||||
mStartOffset = mEndOffset = aStartOffset;
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
mStartContainer = aStartContainer;
|
mStart = aStart;
|
||||||
mStartOffset = aStartOffset;
|
|
||||||
AssertStartIsBeforeOrEqualToEnd();
|
AssertStartIsBeforeOrEqualToEnd();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ContentEventHandler::RawRange::SetEnd(nsINode* aEndContainer,
|
ContentEventHandler::RawRange::SetEnd(const RawRangeBoundary& aEnd)
|
||||||
uint32_t aEndOffset)
|
|
||||||
{
|
{
|
||||||
nsINode* newRoot = nsRange::ComputeRootNode(aEndContainer);
|
nsINode* newRoot = nsRange::ComputeRootNode(aEnd.Container());
|
||||||
if (!newRoot) {
|
if (!newRoot) {
|
||||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidOffset(aEndContainer, aEndOffset)) {
|
if (!aEnd.IsSetAndValid()) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapse if not positioned yet, or if positioned in another document.
|
// Collapse if not positioned yet, or if positioned in another document.
|
||||||
if (!IsPositioned() || newRoot != mRoot) {
|
if (!IsPositioned() || newRoot != mRoot) {
|
||||||
mRoot = newRoot;
|
mRoot = newRoot;
|
||||||
mStartContainer = mEndContainer = aEndContainer;
|
mStart = mEnd = aEnd;
|
||||||
mStartOffset = mEndOffset = aEndOffset;
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
mEndContainer = aEndContainer;
|
mEnd = aEnd;
|
||||||
mEndOffset = aEndOffset;
|
|
||||||
AssertStartIsBeforeOrEqualToEnd();
|
AssertStartIsBeforeOrEqualToEnd();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -126,61 +113,53 @@ ContentEventHandler::RawRange::SetEndAfter(nsINode* aEndContainer)
|
||||||
void
|
void
|
||||||
ContentEventHandler::RawRange::SetStartAndEnd(const nsRange* aRange)
|
ContentEventHandler::RawRange::SetStartAndEnd(const nsRange* aRange)
|
||||||
{
|
{
|
||||||
DebugOnly<nsresult> rv = SetStartAndEnd(aRange->GetStartContainer(),
|
DebugOnly<nsresult> rv = SetStartAndEnd(aRange->StartRef().AsRaw(),
|
||||||
aRange->StartOffset(),
|
aRange->EndRef().AsRaw());
|
||||||
aRange->GetEndContainer(),
|
|
||||||
aRange->EndOffset());
|
|
||||||
MOZ_ASSERT(!aRange->IsPositioned() || NS_SUCCEEDED(rv));
|
MOZ_ASSERT(!aRange->IsPositioned() || NS_SUCCEEDED(rv));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ContentEventHandler::RawRange::SetStartAndEnd(nsINode* aStartContainer,
|
ContentEventHandler::RawRange::SetStartAndEnd(const RawRangeBoundary& aStart,
|
||||||
uint32_t aStartOffset,
|
const RawRangeBoundary& aEnd)
|
||||||
nsINode* aEndContainer,
|
|
||||||
uint32_t aEndOffset)
|
|
||||||
{
|
{
|
||||||
nsINode* newStartRoot = nsRange::ComputeRootNode(aStartContainer);
|
nsINode* newStartRoot = nsRange::ComputeRootNode(aStart.Container());
|
||||||
if (!newStartRoot) {
|
if (!newStartRoot) {
|
||||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
}
|
}
|
||||||
if (!IsValidOffset(aStartContainer, aStartOffset)) {
|
if (!aStart.IsSetAndValid()) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aStartContainer == aEndContainer) {
|
if (aStart.Container() == aEnd.Container()) {
|
||||||
if (!IsValidOffset(aEndContainer, aEndOffset)) {
|
if (!aEnd.IsSetAndValid()) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(aStartOffset <= aEndOffset);
|
MOZ_ASSERT(aStart.Offset() <= aEnd.Offset());
|
||||||
mRoot = newStartRoot;
|
mRoot = newStartRoot;
|
||||||
mStartContainer = mEndContainer = aStartContainer;
|
mStart = aStart;
|
||||||
mStartOffset = aStartOffset;
|
mEnd = aEnd;
|
||||||
mEndOffset = aEndOffset;
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* newEndRoot = nsRange::ComputeRootNode(aEndContainer);
|
nsINode* newEndRoot = nsRange::ComputeRootNode(aEnd.Container());
|
||||||
if (!newEndRoot) {
|
if (!newEndRoot) {
|
||||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
}
|
}
|
||||||
if (!IsValidOffset(aEndContainer, aEndOffset)) {
|
if (!aEnd.IsSetAndValid()) {
|
||||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If they have different root, this should be collapsed at the end point.
|
// If they have different root, this should be collapsed at the end point.
|
||||||
if (newStartRoot != newEndRoot) {
|
if (newStartRoot != newEndRoot) {
|
||||||
mRoot = newEndRoot;
|
mRoot = newEndRoot;
|
||||||
mStartContainer = mEndContainer = aEndContainer;
|
mStart = mEnd = aEnd;
|
||||||
mStartOffset = mEndOffset = aEndOffset;
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, set the range as specified.
|
// Otherwise, set the range as specified.
|
||||||
mRoot = newStartRoot;
|
mRoot = newStartRoot;
|
||||||
mStartContainer = aStartContainer;
|
mStart = aStart;
|
||||||
mStartOffset = aStartOffset;
|
mEnd = aEnd;
|
||||||
mEndContainer = aEndContainer;
|
|
||||||
mEndOffset = aEndOffset;
|
|
||||||
AssertStartIsBeforeOrEqualToEnd();
|
AssertStartIsBeforeOrEqualToEnd();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -194,9 +173,9 @@ ContentEventHandler::RawRange::SelectNodeContents(
|
||||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||||
}
|
}
|
||||||
mRoot = newRoot;
|
mRoot = newRoot;
|
||||||
mStartContainer = mEndContainer = aNodeToSelectContents;
|
mStart = RawRangeBoundary(aNodeToSelectContents, nullptr);
|
||||||
mStartOffset = 0;
|
mEnd = RawRangeBoundary(aNodeToSelectContents,
|
||||||
mEndOffset = aNodeToSelectContents->Length();
|
aNodeToSelectContents->GetLastChild());
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +395,7 @@ ContentEventHandler::InitCommon(SelectionType aSelectionType)
|
||||||
|
|
||||||
// But otherwise, we need to assume that there is a selection range at the
|
// But otherwise, we need to assume that there is a selection range at the
|
||||||
// beginning of the root content if aSelectionType is eNormal.
|
// beginning of the root content if aSelectionType is eNormal.
|
||||||
rv = mFirstSelectedRawRange.CollapseTo(mRootContent, 0);
|
rv = mFirstSelectedRawRange.CollapseTo(RawRangeBoundary(mRootContent, 0));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
@ -1160,7 +1139,7 @@ ContentEventHandler::SetRawRangeFromFlatTextOffset(
|
||||||
|
|
||||||
// Special case like <br contenteditable>
|
// Special case like <br contenteditable>
|
||||||
if (!mRootContent->HasChildren()) {
|
if (!mRootContent->HasChildren()) {
|
||||||
nsresult rv = aRawRange->CollapseTo(mRootContent, 0);
|
nsresult rv = aRawRange->CollapseTo(RawRangeBoundary(mRootContent, 0));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1615,8 +1594,8 @@ ContentEventHandler::NodePosition
|
||||||
ContentEventHandler::GetNodePositionHavingFlatText(
|
ContentEventHandler::GetNodePositionHavingFlatText(
|
||||||
const NodePosition& aNodePosition)
|
const NodePosition& aNodePosition)
|
||||||
{
|
{
|
||||||
return GetNodePositionHavingFlatText(aNodePosition.mNode,
|
return GetNodePositionHavingFlatText(aNodePosition.Container(),
|
||||||
aNodePosition.mOffset);
|
aNodePosition.Offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentEventHandler::NodePosition
|
ContentEventHandler::NodePosition
|
||||||
|
@ -1644,10 +1623,11 @@ ContentEventHandler::GetNodePositionHavingFlatText(nsINode* aNode,
|
||||||
// child of it. For example, if a range is |<p>[<br>]</p>|, then, the
|
// child of it. For example, if a range is |<p>[<br>]</p>|, then, the
|
||||||
// end point is {<p>, 1}. In such case, callers need the <br> node.
|
// end point is {<p>, 1}. In such case, callers need the <br> node.
|
||||||
if (aNodeOffset == childCount) {
|
if (aNodeOffset == childCount) {
|
||||||
NodePosition result;
|
nsINode* node = aNode->GetChildAt(childCount - 1);
|
||||||
result.mNode = aNode->GetChildAt(childCount - 1);
|
return NodePosition(node,
|
||||||
result.mOffset = result.mNode->IsNodeOfType(nsINode::eTEXT) ?
|
node->IsNodeOfType(nsINode::eTEXT)
|
||||||
static_cast<int32_t>(result.mNode->AsContent()->TextLength()) : 1;
|
? static_cast<int32_t>(node->AsContent()->TextLength())
|
||||||
|
: 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_WARNING("aNodeOffset is invalid value");
|
NS_WARNING("aNodeOffset is invalid value");
|
||||||
|
@ -1681,8 +1661,7 @@ ContentEventHandler::GetFirstFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
int32_t offsetInNode =
|
int32_t offsetInNode =
|
||||||
node == aRawRange.GetStartContainer() ? aRawRange.StartOffset() : 0;
|
node == aRawRange.GetStartContainer() ? aRawRange.StartOffset() : 0;
|
||||||
if (static_cast<uint32_t>(offsetInNode) < node->Length()) {
|
if (static_cast<uint32_t>(offsetInNode) < node->Length()) {
|
||||||
nodePosition.mNode = node;
|
nodePosition.Set(node, offsetInNode);
|
||||||
nodePosition.mOffset = offsetInNode;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -1692,19 +1671,18 @@ ContentEventHandler::GetFirstFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
// node causing text.
|
// node causing text.
|
||||||
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
|
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
|
||||||
IsMozBR(node->AsContent())) {
|
IsMozBR(node->AsContent())) {
|
||||||
nodePosition.mNode = node;
|
nodePosition.Set(node, 0);
|
||||||
nodePosition.mOffset = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodePosition.IsValid()) {
|
if (!nodePosition.IsSet()) {
|
||||||
return FrameAndNodeOffset();
|
return FrameAndNodeOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame* firstFrame = nullptr;
|
nsIFrame* firstFrame = nullptr;
|
||||||
GetFrameForTextRect(nodePosition.mNode, nodePosition.mOffset,
|
GetFrameForTextRect(nodePosition.Container(), nodePosition.Offset(),
|
||||||
true, &firstFrame);
|
true, &firstFrame);
|
||||||
return FrameAndNodeOffset(firstFrame, nodePosition.mOffset);
|
return FrameAndNodeOffset(firstFrame, nodePosition.Offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentEventHandler::FrameAndNodeOffset
|
ContentEventHandler::FrameAndNodeOffset
|
||||||
|
@ -1761,17 +1739,19 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
nodePosition.mNode = node;
|
uint32_t offset;
|
||||||
if (node == aRawRange.GetEndContainer()) {
|
if (node == aRawRange.GetEndContainer()) {
|
||||||
nodePosition.mOffset = aRawRange.EndOffset();
|
offset = aRawRange.EndOffset();
|
||||||
} else {
|
} else {
|
||||||
nodePosition.mOffset = node->Length();
|
offset = node->Length();
|
||||||
}
|
}
|
||||||
|
nodePosition.Set(node, offset);
|
||||||
|
|
||||||
// If the text node is empty or the last node of the range but the index
|
// If the text node is empty or the last node of the range but the index
|
||||||
// is 0, we should store current position but continue looking for
|
// is 0, we should store current position but continue looking for
|
||||||
// previous node (If there are no nodes before it, we should use current
|
// previous node (If there are no nodes before it, we should use current
|
||||||
// node position for returning its frame).
|
// node position for returning its frame).
|
||||||
if (!nodePosition.mOffset) {
|
if (!nodePosition.Offset()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1779,18 +1759,18 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
|
|
||||||
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
|
if (ShouldBreakLineBefore(node->AsContent(), mRootContent) ||
|
||||||
IsMozBR(node->AsContent())) {
|
IsMozBR(node->AsContent())) {
|
||||||
nodePosition.mNode = node;
|
nodePosition.Set(node, 0);
|
||||||
nodePosition.mOffset = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodePosition.IsValid()) {
|
if (!nodePosition.IsSet()) {
|
||||||
return FrameAndNodeOffset();
|
return FrameAndNodeOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame* lastFrame = nullptr;
|
nsIFrame* lastFrame = nullptr;
|
||||||
GetFrameForTextRect(nodePosition.mNode, nodePosition.mOffset,
|
GetFrameForTextRect(nodePosition.Container(),
|
||||||
|
nodePosition.Offset(),
|
||||||
true, &lastFrame);
|
true, &lastFrame);
|
||||||
if (!lastFrame) {
|
if (!lastFrame) {
|
||||||
return FrameAndNodeOffset();
|
return FrameAndNodeOffset();
|
||||||
|
@ -1800,7 +1780,7 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
// includes at least one character in the range. Therefore, if it's not a
|
// includes at least one character in the range. Therefore, if it's not a
|
||||||
// text frame, we need to do nothing anymore.
|
// text frame, we need to do nothing anymore.
|
||||||
if (!lastFrame->IsTextFrame()) {
|
if (!lastFrame->IsTextFrame()) {
|
||||||
return FrameAndNodeOffset(lastFrame, nodePosition.mOffset);
|
return FrameAndNodeOffset(lastFrame, nodePosition.Offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t start, end;
|
int32_t start, end;
|
||||||
|
@ -1812,15 +1792,16 @@ ContentEventHandler::GetLastFrameInRangeForTextRect(const RawRange& aRawRange)
|
||||||
// node and it's not 0, the frame shouldn't be added to the text rect. So,
|
// node and it's not 0, the frame shouldn't be added to the text rect. So,
|
||||||
// this should return previous text frame and its last offset if there is
|
// this should return previous text frame and its last offset if there is
|
||||||
// at least one text frame.
|
// at least one text frame.
|
||||||
if (nodePosition.mOffset && nodePosition.mOffset == start) {
|
if (nodePosition.Offset() && nodePosition.Offset() == static_cast<uint32_t>(start)) {
|
||||||
GetFrameForTextRect(nodePosition.mNode, --nodePosition.mOffset,
|
nodePosition.Set(nodePosition.Container(), nodePosition.Offset() - 1);
|
||||||
true, &lastFrame);
|
GetFrameForTextRect(nodePosition.Container(), nodePosition.Offset(), true,
|
||||||
|
&lastFrame);
|
||||||
if (NS_WARN_IF(!lastFrame)) {
|
if (NS_WARN_IF(!lastFrame)) {
|
||||||
return FrameAndNodeOffset();
|
return FrameAndNodeOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FrameAndNodeOffset(lastFrame, nodePosition.mOffset);
|
return FrameAndNodeOffset(lastFrame, nodePosition.Offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentEventHandler::FrameRelativeRect
|
ContentEventHandler::FrameRelativeRect
|
||||||
|
@ -2873,8 +2854,8 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
LineBreakType aLineBreakType,
|
LineBreakType aLineBreakType,
|
||||||
bool aIsRemovingNode /* = false */)
|
bool aIsRemovingNode /* = false */)
|
||||||
{
|
{
|
||||||
if (NS_WARN_IF(!aRootContent) || NS_WARN_IF(!aStartPosition.IsValid()) ||
|
if (NS_WARN_IF(!aRootContent) || NS_WARN_IF(!aStartPosition.IsSet()) ||
|
||||||
NS_WARN_IF(!aEndPosition.IsValid()) || NS_WARN_IF(!aLength)) {
|
NS_WARN_IF(!aEndPosition.IsSet()) || NS_WARN_IF(!aLength)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2896,49 +2877,49 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
// be called after here. However, the node was already removed from the
|
// be called after here. However, the node was already removed from the
|
||||||
// array of children of its parent. So, be careful to handle this case.
|
// array of children of its parent. So, be careful to handle this case.
|
||||||
if (aIsRemovingNode) {
|
if (aIsRemovingNode) {
|
||||||
DebugOnly<nsIContent*> parent = aStartPosition.mNode->GetParent();
|
DebugOnly<nsIContent*> parent = aStartPosition.Container()->GetParent();
|
||||||
MOZ_ASSERT(parent && parent->IndexOf(aStartPosition.mNode) == -1,
|
MOZ_ASSERT(parent && parent->IndexOf(aStartPosition.Container()) == -1,
|
||||||
"At removing the node, the node shouldn't be in the array of children "
|
"At removing the node, the node shouldn't be in the array of children "
|
||||||
"of its parent");
|
"of its parent");
|
||||||
MOZ_ASSERT(aStartPosition.mNode == endPosition.mNode,
|
MOZ_ASSERT(aStartPosition.Container() == endPosition.Container(),
|
||||||
"At removing the node, start and end node should be same");
|
"At removing the node, start and end node should be same");
|
||||||
MOZ_ASSERT(aStartPosition.mOffset == 0,
|
MOZ_ASSERT(aStartPosition.Offset() == 0,
|
||||||
"When the node is being removed, the start offset should be 0");
|
"When the node is being removed, the start offset should be 0");
|
||||||
MOZ_ASSERT(static_cast<uint32_t>(endPosition.mOffset) ==
|
MOZ_ASSERT(static_cast<uint32_t>(endPosition.Offset()) ==
|
||||||
endPosition.mNode->GetChildCount(),
|
endPosition.Container()->GetChildCount(),
|
||||||
"When the node is being removed, the end offset should be child count");
|
"When the node is being removed, the end offset should be child count");
|
||||||
iter = NS_NewPreContentIterator();
|
iter = NS_NewPreContentIterator();
|
||||||
nsresult rv = iter->Init(aStartPosition.mNode);
|
nsresult rv = iter->Init(aStartPosition.Container());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RawRange prevRawRange;
|
RawRange prevRawRange;
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
prevRawRange.SetStart(aStartPosition.mNode, aStartPosition.mOffset);
|
prevRawRange.SetStart(aStartPosition.AsRaw());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the end position is immediately after non-root element's open tag,
|
// When the end position is immediately after non-root element's open tag,
|
||||||
// we need to include a line break caused by the open tag.
|
// we need to include a line break caused by the open tag.
|
||||||
if (endPosition.mNode != aRootContent &&
|
if (endPosition.Container() != aRootContent &&
|
||||||
endPosition.IsImmediatelyAfterOpenTag()) {
|
endPosition.IsImmediatelyAfterOpenTag()) {
|
||||||
if (endPosition.mNode->HasChildren()) {
|
if (endPosition.Container()->HasChildren()) {
|
||||||
// When the end node has some children, move the end position to before
|
// When the end node has some children, move the end position to before
|
||||||
// the open tag of its first child.
|
// the open tag of its first child.
|
||||||
nsINode* firstChild = endPosition.mNode->GetFirstChild();
|
nsINode* firstChild = endPosition.Container()->GetFirstChild();
|
||||||
if (NS_WARN_IF(!firstChild)) {
|
if (NS_WARN_IF(!firstChild)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
endPosition = NodePositionBefore(firstChild, 0);
|
endPosition = NodePositionBefore(firstChild, 0);
|
||||||
} else {
|
} else {
|
||||||
// When the end node is empty, move the end position after the node.
|
// When the end node is empty, move the end position after the node.
|
||||||
nsIContent* parentContent = endPosition.mNode->GetParent();
|
nsIContent* parentContent = endPosition.Container()->GetParent();
|
||||||
if (NS_WARN_IF(!parentContent)) {
|
if (NS_WARN_IF(!parentContent)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
int32_t indexInParent = parentContent->IndexOf(endPosition.mNode);
|
int32_t indexInParent = parentContent->IndexOf(endPosition.Container());
|
||||||
if (NS_WARN_IF(indexInParent < 0)) {
|
if (NS_WARN_IF(indexInParent < 0)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -2946,9 +2927,9 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endPosition.OffsetIsValid()) {
|
if (endPosition.IsSetAndValid()) {
|
||||||
// Offset is within node's length; set end of range to that offset
|
// Offset is within node's length; set end of range to that offset
|
||||||
rv = prevRawRange.SetEnd(endPosition.mNode, endPosition.mOffset);
|
rv = prevRawRange.SetEnd(endPosition.AsRaw());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2959,9 +2940,9 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
} else if (endPosition.mNode != aRootContent) {
|
} else if (endPosition.Container() != aRootContent) {
|
||||||
// Offset is past node's length; set end of range to end of node
|
// Offset is past node's length; set end of range to end of node
|
||||||
rv = prevRawRange.SetEndAfter(endPosition.mNode);
|
rv = prevRawRange.SetEndAfter(endPosition.Container());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2995,21 +2976,23 @@ ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
|
|
||||||
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
if (node->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
// Note: our range always starts from offset 0
|
// Note: our range always starts from offset 0
|
||||||
if (node == endPosition.mNode) {
|
if (node == endPosition.Container()) {
|
||||||
|
// NOTE: We should have an offset here, as endPosition.Container() is a
|
||||||
|
// nsINode::eTEXT, which always has an offset.
|
||||||
*aLength += GetTextLength(content, aLineBreakType,
|
*aLength += GetTextLength(content, aLineBreakType,
|
||||||
endPosition.mOffset);
|
endPosition.Offset());
|
||||||
} else {
|
} else {
|
||||||
*aLength += GetTextLength(content, aLineBreakType);
|
*aLength += GetTextLength(content, aLineBreakType);
|
||||||
}
|
}
|
||||||
} else if (ShouldBreakLineBefore(content, aRootContent)) {
|
} else if (ShouldBreakLineBefore(content, aRootContent)) {
|
||||||
// If the start position is start of this node but doesn't include the
|
// If the start position is start of this node but doesn't include the
|
||||||
// open tag, don't append the line break length.
|
// open tag, don't append the line break length.
|
||||||
if (node == aStartPosition.mNode && !aStartPosition.IsBeforeOpenTag()) {
|
if (node == aStartPosition.Container() && !aStartPosition.IsBeforeOpenTag()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// If the end position is before the open tag, don't append the line
|
// If the end position is before the open tag, don't append the line
|
||||||
// break length.
|
// break length.
|
||||||
if (node == endPosition.mNode && endPosition.IsBeforeOpenTag()) {
|
if (node == endPosition.Container() && endPosition.IsBeforeOpenTag()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*aLength += GetBRLength(aLineBreakType);
|
*aLength += GetBRLength(aLineBreakType);
|
||||||
|
@ -3096,7 +3079,8 @@ ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(RawRange& aRawRange)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = aRawRange.CollapseTo(childNode, offsetInChildNode);
|
nsresult rv =
|
||||||
|
aRawRange.CollapseTo(RawRangeBoundary(childNode, offsetInChildNode));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,56 +46,62 @@ private:
|
||||||
class MOZ_STACK_CLASS RawRange final
|
class MOZ_STACK_CLASS RawRange final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RawRange()
|
RawRange() {}
|
||||||
: mStartOffset(0)
|
|
||||||
, mEndOffset(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
mRoot = mStartContainer = mEndContainer = nullptr;
|
mRoot = nullptr;
|
||||||
mStartOffset = mEndOffset = 0;
|
mStart = RangeBoundary();
|
||||||
|
mEnd = RangeBoundary();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPositioned() const
|
bool IsPositioned() const
|
||||||
{
|
{
|
||||||
return mStartContainer && mEndContainer;
|
return mStart.IsSet() && mEnd.IsSet();
|
||||||
}
|
}
|
||||||
bool Collapsed() const
|
bool Collapsed() const
|
||||||
{
|
{
|
||||||
return mStartContainer == mEndContainer &&
|
return mStart == mEnd && IsPositioned();
|
||||||
mStartOffset == mEndOffset &&
|
|
||||||
IsPositioned();
|
|
||||||
}
|
}
|
||||||
nsINode* GetStartContainer() const { return mStartContainer; }
|
nsINode* GetStartContainer() const { return mStart.Container(); }
|
||||||
nsINode* GetEndContainer() const { return mEndContainer; }
|
nsINode* GetEndContainer() const { return mEnd.Container(); }
|
||||||
uint32_t StartOffset() const { return mStartOffset; }
|
uint32_t StartOffset() const { return mStart.Offset(); }
|
||||||
uint32_t EndOffset() const { return mEndOffset; }
|
uint32_t EndOffset() const { return mEnd.Offset(); }
|
||||||
|
nsIContent* StartRef() const { return mStart.Ref(); }
|
||||||
|
nsIContent* EndRef() const { return mEnd.Ref(); }
|
||||||
|
|
||||||
nsresult CollapseTo(nsINode* aContainer, uint32_t aOffset)
|
// XXX: Make these use RangeBoundaries...
|
||||||
|
nsresult CollapseTo(const RawRangeBoundary& aBoundary)
|
||||||
{
|
{
|
||||||
return SetStartAndEnd(aContainer, aOffset, aContainer, aOffset);
|
return SetStartAndEnd(aBoundary, aBoundary);
|
||||||
}
|
}
|
||||||
nsresult SetStart(nsINode* aStartContainer, uint32_t aStartOffset);
|
nsresult SetStart(const RawRangeBoundary& aStart);
|
||||||
nsresult SetEnd(nsINode* aEndContainer, uint32_t aEndOffset);
|
nsresult SetEnd(const RawRangeBoundary& aEnd);
|
||||||
|
|
||||||
|
// NOTE: These helpers can hide performance problems, as they perform a
|
||||||
|
// search to find aStartOffset in aStartContainer.
|
||||||
|
nsresult SetStart(nsINode* aStartContainer, uint32_t aStartOffset) {
|
||||||
|
return SetStart(RawRangeBoundary(aStartContainer, aStartOffset));
|
||||||
|
}
|
||||||
|
nsresult SetEnd(nsINode* aEndContainer, uint32_t aEndOffset) {
|
||||||
|
return SetEnd(RawRangeBoundary(aEndContainer, aEndOffset));
|
||||||
|
}
|
||||||
|
|
||||||
nsresult SetEndAfter(nsINode* aEndContainer);
|
nsresult SetEndAfter(nsINode* aEndContainer);
|
||||||
void SetStartAndEnd(const nsRange* aRange);
|
void SetStartAndEnd(const nsRange* aRange);
|
||||||
nsresult SetStartAndEnd(nsINode* aStartContainer, uint32_t aStartOffset,
|
nsresult SetStartAndEnd(const RawRangeBoundary& aStart,
|
||||||
nsINode* aEndContainer, uint32_t aEndOffset);
|
const RawRangeBoundary& aEnd);
|
||||||
|
|
||||||
nsresult SelectNodeContents(nsINode* aNodeToSelectContents);
|
nsresult SelectNodeContents(nsINode* aNodeToSelectContents);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsValidOffset(nsINode* aContainer, uint32_t aOffset) const;
|
|
||||||
nsINode* IsValidBoundary(nsINode* aNode) const;
|
nsINode* IsValidBoundary(nsINode* aNode) const;
|
||||||
inline void AssertStartIsBeforeOrEqualToEnd();
|
inline void AssertStartIsBeforeOrEqualToEnd();
|
||||||
|
|
||||||
nsCOMPtr<nsINode> mRoot;
|
nsCOMPtr<nsINode> mRoot;
|
||||||
nsCOMPtr<nsINode> mStartContainer;
|
|
||||||
nsCOMPtr<nsINode> mEndContainer;
|
RangeBoundary mStart;
|
||||||
uint32_t mStartOffset;
|
RangeBoundary mEnd;
|
||||||
uint32_t mEndOffset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -163,76 +169,72 @@ public:
|
||||||
// When mNode is an element and mOffset is 0, the start position means after
|
// When mNode is an element and mOffset is 0, the start position means after
|
||||||
// the open tag of mNode.
|
// the open tag of mNode.
|
||||||
// This is useful to receive one or more sets of them instead of nsRange.
|
// This is useful to receive one or more sets of them instead of nsRange.
|
||||||
struct NodePosition
|
// This type is intended to be used for short-lived operations, and is thus
|
||||||
|
// marked MOZ_STACK_CLASS.
|
||||||
|
struct MOZ_STACK_CLASS NodePosition : public RangeBoundary
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsINode> mNode;
|
|
||||||
int32_t mOffset;
|
|
||||||
// Only when mNode is an element node and mOffset is 0, mAfterOpenTag is
|
// Only when mNode is an element node and mOffset is 0, mAfterOpenTag is
|
||||||
// referred.
|
// referred.
|
||||||
bool mAfterOpenTag;
|
bool mAfterOpenTag = true;
|
||||||
|
|
||||||
NodePosition()
|
NodePosition()
|
||||||
: mOffset(-1)
|
: RangeBoundary()
|
||||||
, mAfterOpenTag(true)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NodePosition(nsINode* aNode, int32_t aOffset)
|
NodePosition(nsINode* aContainer, int32_t aOffset)
|
||||||
: mNode(aNode)
|
: RangeBoundary(aContainer, aOffset)
|
||||||
, mOffset(aOffset)
|
{
|
||||||
, mAfterOpenTag(true)
|
}
|
||||||
|
|
||||||
|
NodePosition(nsINode* aContainer, nsIContent* aRef)
|
||||||
|
: RangeBoundary(aContainer, aRef)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit NodePosition(const nsIFrame::ContentOffsets& aContentOffsets)
|
explicit NodePosition(const nsIFrame::ContentOffsets& aContentOffsets)
|
||||||
: mNode(aContentOffsets.content)
|
: RangeBoundary(aContentOffsets.content, aContentOffsets.offset)
|
||||||
, mOffset(aContentOffsets.offset)
|
|
||||||
, mAfterOpenTag(true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NodePosition(nsINode* aNode, int32_t aOffset, bool aAfterOpenTag)
|
|
||||||
: mNode(aNode)
|
|
||||||
, mOffset(aOffset)
|
|
||||||
, mAfterOpenTag(aAfterOpenTag)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool operator==(const NodePosition& aOther) const
|
bool operator==(const NodePosition& aOther) const
|
||||||
{
|
{
|
||||||
return mNode == aOther.mNode &&
|
return RangeBoundary::operator==(aOther) &&
|
||||||
mOffset == aOther.mOffset &&
|
|
||||||
mAfterOpenTag == aOther.mAfterOpenTag;
|
mAfterOpenTag == aOther.mAfterOpenTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const
|
|
||||||
{
|
|
||||||
return mNode && mOffset >= 0;
|
|
||||||
}
|
|
||||||
bool OffsetIsValid() const
|
|
||||||
{
|
|
||||||
return IsValid() && static_cast<uint32_t>(mOffset) <= mNode->Length();
|
|
||||||
}
|
|
||||||
bool IsBeforeOpenTag() const
|
bool IsBeforeOpenTag() const
|
||||||
{
|
{
|
||||||
return IsValid() && mNode->IsElement() && !mOffset && !mAfterOpenTag;
|
return IsSet() &&
|
||||||
|
Container()->IsElement() &&
|
||||||
|
!Ref() &&
|
||||||
|
!mAfterOpenTag;
|
||||||
}
|
}
|
||||||
bool IsImmediatelyAfterOpenTag() const
|
bool IsImmediatelyAfterOpenTag() const
|
||||||
{
|
{
|
||||||
return IsValid() && mNode->IsElement() && !mOffset && mAfterOpenTag;
|
return IsSet() &&
|
||||||
|
Container()->IsElement() &&
|
||||||
|
!Ref() &&
|
||||||
|
mAfterOpenTag;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// NodePositionBefore isn't good name if mNode isn't an element node nor
|
// NodePositionBefore isn't good name if Container() isn't an element node nor
|
||||||
// mOffset is not 0, though, when mNode is an element node and mOffset is 0,
|
// Offset() is not 0, though, when Container() is an element node and mOffset
|
||||||
// this is treated as before the open tag of mNode.
|
// is 0, this is treated as before the open tag of Container().
|
||||||
struct NodePositionBefore final : public NodePosition
|
struct NodePositionBefore final : public NodePosition
|
||||||
{
|
{
|
||||||
NodePositionBefore(nsINode* aNode, int32_t aOffset)
|
NodePositionBefore(nsINode* aContainer, int32_t aOffset)
|
||||||
: NodePosition(aNode, aOffset, false)
|
: NodePosition(aContainer, aOffset)
|
||||||
{
|
{
|
||||||
|
mAfterOpenTag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodePositionBefore(nsINode* aContainer, nsIContent* aRef)
|
||||||
|
: NodePosition(aContainer, aRef)
|
||||||
|
{
|
||||||
|
mAfterOpenTag = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,29 @@ ToChar(bool aBool)
|
||||||
return aBool ? "true" : "false";
|
return aBool ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method determines the node to use for the point before the current node.
|
||||||
|
// If you have the following aContent and aContainer, and want to represent the
|
||||||
|
// following point for `NodePosition` or `RangeBoundary`:
|
||||||
|
//
|
||||||
|
// <parent> {node} {node} | {node} </parent>
|
||||||
|
// ^ ^ ^
|
||||||
|
// aContainer point aContent
|
||||||
|
//
|
||||||
|
// This function will shift `aContent` to the left into the format which
|
||||||
|
// `NodePosition` and `RangeBoundary` use:
|
||||||
|
//
|
||||||
|
// <parent> {node} {node} | {node} </parent>
|
||||||
|
// ^ ^ ^
|
||||||
|
// aContainer result point
|
||||||
|
static nsIContent*
|
||||||
|
PointBefore(nsINode* aContainer, nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (aContent) {
|
||||||
|
return aContent->GetPreviousSibling();
|
||||||
|
}
|
||||||
|
return aContainer->GetLastChild();
|
||||||
|
}
|
||||||
|
|
||||||
class WritingModeToString final : public nsAutoCString
|
class WritingModeToString final : public nsAutoCString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -123,8 +146,8 @@ public:
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
|
||||||
|
|
||||||
// Note that we don't need to add mFirstAddedNodeContainer nor
|
// Note that we don't need to add mFirstAddedContainer nor
|
||||||
// mLastAddedNodeContainer to cycle collection because they are non-null only
|
// mLastAddedContainer to cycle collection because they are non-null only
|
||||||
// during short time and shouldn't be touched while they are non-null.
|
// during short time and shouldn't be touched while they are non-null.
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
|
||||||
|
@ -174,9 +197,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
|
||||||
|
|
||||||
IMEContentObserver::IMEContentObserver()
|
IMEContentObserver::IMEContentObserver()
|
||||||
: mFirstAddedNodeOffset(0)
|
: mESM(nullptr)
|
||||||
, mLastAddedNodeOffset(0)
|
|
||||||
, mESM(nullptr)
|
|
||||||
, mIMENotificationRequests(nullptr)
|
, mIMENotificationRequests(nullptr)
|
||||||
, mSuppressNotifications(0)
|
, mSuppressNotifications(0)
|
||||||
, mPreCharacterDataChangeLength(-1)
|
, mPreCharacterDataChangeLength(-1)
|
||||||
|
@ -1001,13 +1022,16 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
|
||||||
|
|
||||||
void
|
void
|
||||||
IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
int32_t aStartIndex,
|
nsIContent* aFirstContent,
|
||||||
int32_t aEndIndex)
|
nsIContent* aLastContent)
|
||||||
{
|
{
|
||||||
if (!NeedsTextChangeNotification()) {
|
if (!NeedsTextChangeNotification()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT_IF(aFirstContent, aFirstContent->GetParentNode() == aContainer);
|
||||||
|
MOZ_ASSERT_IF(aLastContent, aLastContent->GetParentNode() == aContainer);
|
||||||
|
|
||||||
mStartOfRemovingTextRangeCache.Clear();
|
mStartOfRemovingTextRangeCache.Clear();
|
||||||
|
|
||||||
// If it's in a document change, nodes are added consecutively. Therefore,
|
// If it's in a document change, nodes are added consecutively. Therefore,
|
||||||
|
@ -1019,9 +1043,9 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
// the last node in mEndOfAddedTextCache. Clear it.
|
// the last node in mEndOfAddedTextCache. Clear it.
|
||||||
mEndOfAddedTextCache.Clear();
|
mEndOfAddedTextCache.Clear();
|
||||||
if (!HasAddedNodesDuringDocumentChange()) {
|
if (!HasAddedNodesDuringDocumentChange()) {
|
||||||
mFirstAddedNodeContainer = mLastAddedNodeContainer = aContainer;
|
mFirstAddedContainer = mLastAddedContainer = aContainer;
|
||||||
mFirstAddedNodeOffset = aStartIndex;
|
mFirstAddedContent = aFirstContent;
|
||||||
mLastAddedNodeOffset = aEndIndex;
|
mLastAddedContent = aLastContent;
|
||||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||||
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
||||||
"consecutive added nodes", this));
|
"consecutive added nodes", this));
|
||||||
|
@ -1030,17 +1054,17 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
// If first node being added is not next node of the last node,
|
// If first node being added is not next node of the last node,
|
||||||
// notify IME of the previous range first, then, restart to cache the
|
// notify IME of the previous range first, then, restart to cache the
|
||||||
// range.
|
// range.
|
||||||
if (NS_WARN_IF(!IsNextNodeOfLastAddedNode(aContainer, aStartIndex))) {
|
if (NS_WARN_IF(!IsNextNodeOfLastAddedNode(aContainer, aFirstContent))) {
|
||||||
// Flush the old range first.
|
// Flush the old range first.
|
||||||
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
||||||
mFirstAddedNodeContainer = aContainer;
|
mFirstAddedContainer = aContainer;
|
||||||
mFirstAddedNodeOffset = aStartIndex;
|
mFirstAddedContent = aFirstContent;
|
||||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||||
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
||||||
"consecutive added nodes", this));
|
"consecutive added nodes", this));
|
||||||
}
|
}
|
||||||
mLastAddedNodeContainer = aContainer;
|
mLastAddedContainer = aContainer;
|
||||||
mLastAddedNodeOffset = aEndIndex;
|
mLastAddedContent = aLastContent;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(!HasAddedNodesDuringDocumentChange(),
|
MOZ_ASSERT(!HasAddedNodesDuringDocumentChange(),
|
||||||
|
@ -1048,11 +1072,14 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
|
if (!mEndOfAddedTextCache.Match(aContainer,
|
||||||
|
aFirstContent->GetPreviousSibling())) {
|
||||||
mEndOfAddedTextCache.Clear();
|
mEndOfAddedTextCache.Clear();
|
||||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
NodePosition(mRootContent, 0),
|
NodePosition(mRootContent, 0),
|
||||||
NodePositionBefore(aContainer, aStartIndex),
|
NodePositionBefore(aContainer,
|
||||||
|
PointBefore(aContainer,
|
||||||
|
aFirstContent)),
|
||||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||||
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
||||||
return;
|
return;
|
||||||
|
@ -1064,8 +1091,10 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
// get offset at the end of the last added node
|
// get offset at the end of the last added node
|
||||||
uint32_t addingLength = 0;
|
uint32_t addingLength = 0;
|
||||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
NodePositionBefore(aContainer, aStartIndex),
|
NodePositionBefore(aContainer,
|
||||||
NodePosition(aContainer, aEndIndex),
|
PointBefore(aContainer,
|
||||||
|
aFirstContent)),
|
||||||
|
NodePosition(aContainer, aLastContent),
|
||||||
mRootContent, &addingLength,
|
mRootContent, &addingLength,
|
||||||
LINE_BREAK_TYPE_NATIVE);
|
LINE_BREAK_TYPE_NATIVE);
|
||||||
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
||||||
|
@ -1077,7 +1106,7 @@ IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
||||||
// NotifyContentAdded() is for adding next node. Therefore, caching the text
|
// NotifyContentAdded() is for adding next node. Therefore, caching the text
|
||||||
// length can skip to compute the text length before the adding node and
|
// length can skip to compute the text length before the adding node and
|
||||||
// before of it.
|
// before of it.
|
||||||
mEndOfAddedTextCache.Cache(aContainer, aEndIndex, offset + addingLength);
|
mEndOfAddedTextCache.Cache(aContainer, aLastContent, offset + addingLength);
|
||||||
|
|
||||||
if (!addingLength) {
|
if (!addingLength) {
|
||||||
return;
|
return;
|
||||||
|
@ -1093,27 +1122,27 @@ void
|
||||||
IMEContentObserver::ContentAppended(nsIDocument* aDocument,
|
IMEContentObserver::ContentAppended(nsIDocument* aDocument,
|
||||||
nsIContent* aContainer,
|
nsIContent* aContainer,
|
||||||
nsIContent* aFirstNewContent,
|
nsIContent* aFirstNewContent,
|
||||||
int32_t aNewIndexInContainer)
|
int32_t /* unused */)
|
||||||
{
|
{
|
||||||
NotifyContentAdded(aContainer, aNewIndexInContainer,
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||||
aContainer->GetChildCount());
|
aFirstNewContent, aContainer->GetLastChild());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
||||||
nsIContent* aContainer,
|
nsIContent* aContainer,
|
||||||
nsIContent* aChild,
|
nsIContent* aChild,
|
||||||
int32_t aIndexInContainer)
|
int32_t /* unused */)
|
||||||
{
|
{
|
||||||
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
||||||
aIndexInContainer, aIndexInContainer + 1);
|
aChild, aChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
||||||
nsIContent* aContainer,
|
nsIContent* aContainer,
|
||||||
nsIContent* aChild,
|
nsIContent* aChild,
|
||||||
int32_t aIndexInContainer,
|
int32_t /* unused */,
|
||||||
nsIContent* aPreviousSibling)
|
nsIContent* aPreviousSibling)
|
||||||
{
|
{
|
||||||
if (!NeedsTextChangeNotification()) {
|
if (!NeedsTextChangeNotification()) {
|
||||||
|
@ -1127,18 +1156,19 @@ IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
||||||
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) {
|
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aPreviousSibling)) {
|
||||||
// At removing a child node of aContainer, we need the line break caused
|
// At removing a child node of aContainer, we need the line break caused
|
||||||
// by open tag of aContainer. Be careful when aIndexInContainer is 0.
|
// by open tag of aContainer. Be careful when aPreviousSibling is nullptr.
|
||||||
|
|
||||||
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
NodePosition(mRootContent, 0),
|
NodePosition(mRootContent, 0),
|
||||||
NodePosition(containerNode, aIndexInContainer),
|
NodePosition(containerNode, aPreviousSibling),
|
||||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
mStartOfRemovingTextRangeCache.Clear();
|
mStartOfRemovingTextRangeCache.Clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mStartOfRemovingTextRangeCache.Cache(containerNode, aIndexInContainer,
|
mStartOfRemovingTextRangeCache.Cache(containerNode, aPreviousSibling,
|
||||||
offset);
|
offset);
|
||||||
} else {
|
} else {
|
||||||
offset = mStartOfRemovingTextRangeCache.mFlatTextLength;
|
offset = mStartOfRemovingTextRangeCache.mFlatTextLength;
|
||||||
|
@ -1230,8 +1260,8 @@ IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
|
||||||
void
|
void
|
||||||
IMEContentObserver::ClearAddedNodesDuringDocumentChange()
|
IMEContentObserver::ClearAddedNodesDuringDocumentChange()
|
||||||
{
|
{
|
||||||
mFirstAddedNodeContainer = mLastAddedNodeContainer = nullptr;
|
mFirstAddedContainer = mLastAddedContainer = nullptr;
|
||||||
mFirstAddedNodeOffset = mLastAddedNodeOffset = 0;
|
mFirstAddedContent = mLastAddedContent = nullptr;
|
||||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||||
("0x%p IMEContentObserver::ClearAddedNodesDuringDocumentChange()"
|
("0x%p IMEContentObserver::ClearAddedNodesDuringDocumentChange()"
|
||||||
", finished storing consecutive nodes", this));
|
", finished storing consecutive nodes", this));
|
||||||
|
@ -1256,66 +1286,46 @@ IMEContentObserver::GetChildNode(nsINode* aParent, int32_t aOffset)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IMEContentObserver::IsNextNodeOfLastAddedNode(nsINode* aParent,
|
IMEContentObserver::IsNextNodeOfLastAddedNode(nsINode* aParent,
|
||||||
int32_t aOffset) const
|
nsIContent* aChild) const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aParent);
|
MOZ_ASSERT(aParent);
|
||||||
MOZ_ASSERT(aOffset >= 0 &&
|
MOZ_ASSERT(aChild && aChild->GetParentNode() == aParent);
|
||||||
aOffset <= static_cast<int32_t>(aParent->Length()));
|
|
||||||
MOZ_ASSERT(mRootContent);
|
MOZ_ASSERT(mRootContent);
|
||||||
MOZ_ASSERT(HasAddedNodesDuringDocumentChange());
|
MOZ_ASSERT(HasAddedNodesDuringDocumentChange());
|
||||||
|
|
||||||
// If the parent node isn't changed, we can check it only with offset.
|
// If the parent node isn't changed, we can check that mLastAddedContent has
|
||||||
if (aParent == mLastAddedNodeContainer) {
|
// aChild as its next sibling.
|
||||||
if (NS_WARN_IF(mLastAddedNodeOffset != aOffset)) {
|
if (aParent == mLastAddedContainer) {
|
||||||
|
if (NS_WARN_IF(mLastAddedContent->GetNextSibling() != aChild)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the parent node is changed, that means that given offset should be the
|
// If the parent node is changed, that means that the recorded last added node
|
||||||
// last added node not having next sibling.
|
// shouldn't have a sibling.
|
||||||
if (NS_WARN_IF(mLastAddedNodeOffset !=
|
if (NS_WARN_IF(mLastAddedContent->GetNextSibling())) {
|
||||||
static_cast<int32_t>(mLastAddedNodeContainer->Length()))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node is aParent is a descendant of mLastAddedNodeContainer,
|
// If the node is aParent is a descendant of mLastAddedContainer,
|
||||||
// aOffset should be 0.
|
// aChild should be the first child in the new container.
|
||||||
if (mLastAddedNodeContainer == aParent->GetParent()) {
|
if (mLastAddedContainer == aParent->GetParent()) {
|
||||||
if (NS_WARN_IF(aOffset)) {
|
if (NS_WARN_IF(aChild->GetPreviousSibling())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we need to check it even with slow path.
|
// Otherwise, we need to check it even with slow path.
|
||||||
nsIContent* lastAddedContent =
|
|
||||||
GetChildNode(mLastAddedNodeContainer, mLastAddedNodeOffset - 1);
|
|
||||||
if (NS_WARN_IF(!lastAddedContent)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIContent* nextContentOfLastAddedContent =
|
nsIContent* nextContentOfLastAddedContent =
|
||||||
lastAddedContent->GetNextNode(mRootContent->GetParentNode());
|
mLastAddedContent->GetNextNode(mRootContent->GetParentNode());
|
||||||
if (NS_WARN_IF(!nextContentOfLastAddedContent)) {
|
if (NS_WARN_IF(!nextContentOfLastAddedContent)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (NS_WARN_IF(nextContentOfLastAddedContent != aChild)) {
|
||||||
nsIContent* startContent = GetChildNode(aParent, aOffset);
|
|
||||||
if (NS_WARN_IF(!startContent) ||
|
|
||||||
NS_WARN_IF(nextContentOfLastAddedContent != startContent)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
|
||||||
NS_WARNING_ASSERTION(
|
|
||||||
!aOffset || aOffset == static_cast<int32_t>(aParent->Length() - 1),
|
|
||||||
"Used slow path for aParent");
|
|
||||||
NS_WARNING_ASSERTION(
|
|
||||||
!(mLastAddedNodeOffset - 1) ||
|
|
||||||
mLastAddedNodeOffset ==
|
|
||||||
static_cast<int32_t>(mLastAddedNodeContainer->Length()),
|
|
||||||
"Used slow path for mLastAddedNodeContainer");
|
|
||||||
#endif // #ifdef DEBUG
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1338,8 +1348,9 @@ IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange()
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
ContentEventHandler::GetFlatTextLengthInRange(
|
ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
NodePosition(mRootContent, 0),
|
NodePosition(mRootContent, 0),
|
||||||
NodePosition(mFirstAddedNodeContainer,
|
NodePosition(mFirstAddedContainer,
|
||||||
mFirstAddedNodeOffset),
|
PointBefore(mFirstAddedContainer,
|
||||||
|
mFirstAddedContent)),
|
||||||
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
ClearAddedNodesDuringDocumentChange();
|
ClearAddedNodesDuringDocumentChange();
|
||||||
|
@ -1350,10 +1361,10 @@ IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange()
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
rv =
|
rv =
|
||||||
ContentEventHandler::GetFlatTextLengthInRange(
|
ContentEventHandler::GetFlatTextLengthInRange(
|
||||||
NodePosition(mFirstAddedNodeContainer,
|
NodePosition(mFirstAddedContainer,
|
||||||
mFirstAddedNodeOffset),
|
PointBefore(mFirstAddedContainer,
|
||||||
NodePosition(mLastAddedNodeContainer,
|
mFirstAddedContent)),
|
||||||
mLastAddedNodeOffset),
|
NodePosition(mLastAddedContainer, mLastAddedContent),
|
||||||
mRootContent, &length, LINE_BREAK_TYPE_NATIVE);
|
mRootContent, &length, LINE_BREAK_TYPE_NATIVE);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
ClearAddedNodesDuringDocumentChange();
|
ClearAddedNodesDuringDocumentChange();
|
||||||
|
|
|
@ -202,9 +202,9 @@ private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MaybeNotifyIMEOfAddedTextDuringDocumentChange() may send text change
|
* MaybeNotifyIMEOfAddedTextDuringDocumentChange() may send text change
|
||||||
* notification caused by the nodes added between mFirstAddedNodeOffset in
|
* notification caused by the nodes added between mFirstAddedContent in
|
||||||
* mFirstAddedNodeContainer and mLastAddedNodeOffset in
|
* mFirstAddedContainer and mLastAddedContent in
|
||||||
* mLastAddedNodeContainer and forgets the range.
|
* mLastAddedContainer and forgets the range.
|
||||||
*/
|
*/
|
||||||
void MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
void MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
||||||
|
|
||||||
|
@ -232,15 +232,14 @@ private:
|
||||||
*/
|
*/
|
||||||
bool HasAddedNodesDuringDocumentChange() const
|
bool HasAddedNodesDuringDocumentChange() const
|
||||||
{
|
{
|
||||||
return mFirstAddedNodeContainer && mLastAddedNodeContainer;
|
return mFirstAddedContainer && mLastAddedContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the node at aOffset in aParent is next node of the node at
|
* Returns true if the passed-in node in aParent is the next node of
|
||||||
* mLastAddedNodeOffset in mLastAddedNodeContainer in pre-order tree
|
* mLastAddedContent in pre-order tree traversal of the DOM.
|
||||||
* traversal of the DOM.
|
|
||||||
*/
|
*/
|
||||||
bool IsNextNodeOfLastAddedNode(nsINode* aParent, int32_t aOffset) const;
|
bool IsNextNodeOfLastAddedNode(nsINode* aParent, nsIContent* aChild) const;
|
||||||
|
|
||||||
void PostFocusSetNotification();
|
void PostFocusSetNotification();
|
||||||
void MaybeNotifyIMEOfFocusSet();
|
void MaybeNotifyIMEOfFocusSet();
|
||||||
|
@ -256,7 +255,9 @@ private:
|
||||||
void CancelNotifyingIMEOfPositionChange();
|
void CancelNotifyingIMEOfPositionChange();
|
||||||
void PostCompositionEventHandledNotification();
|
void PostCompositionEventHandledNotification();
|
||||||
|
|
||||||
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
|
void NotifyContentAdded(nsINode* aContainer,
|
||||||
|
nsIContent* aFirstContent,
|
||||||
|
nsIContent* aLastContent);
|
||||||
void ObserveEditableNode();
|
void ObserveEditableNode();
|
||||||
/**
|
/**
|
||||||
* NotifyIMEOfBlur() notifies IME of blur.
|
* NotifyIMEOfBlur() notifies IME of blur.
|
||||||
|
@ -431,42 +432,43 @@ private:
|
||||||
*/
|
*/
|
||||||
struct FlatTextCache
|
struct FlatTextCache
|
||||||
{
|
{
|
||||||
// mContainerNode and mNodeOffset represent a point in DOM tree. E.g.,
|
// mContainerNode and mNode represent a point in DOM tree. E.g.,
|
||||||
// if mContainerNode is a div element, mNodeOffset is index of its child.
|
// if mContainerNode is a div element, mNode is a child.
|
||||||
nsCOMPtr<nsINode> mContainerNode;
|
nsCOMPtr<nsINode> mContainerNode;
|
||||||
int32_t mNodeOffset;
|
// mNode points to the last child which participates in the current
|
||||||
|
// mFlatTextLength. If mNode is null, then that means that the end point for
|
||||||
|
// mFlatTextLength is immediately before the first child of mContainerNode.
|
||||||
|
nsCOMPtr<nsINode> mNode;
|
||||||
// Length of flat text generated from contents between the start of content
|
// Length of flat text generated from contents between the start of content
|
||||||
// and a child node whose index is mNodeOffset of mContainerNode.
|
// and a child node whose index is mNodeOffset of mContainerNode.
|
||||||
uint32_t mFlatTextLength;
|
uint32_t mFlatTextLength;
|
||||||
|
|
||||||
FlatTextCache()
|
FlatTextCache()
|
||||||
: mNodeOffset(0)
|
: mFlatTextLength(0)
|
||||||
, mFlatTextLength(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
mContainerNode = nullptr;
|
mContainerNode = nullptr;
|
||||||
mNodeOffset = 0;
|
mNode = nullptr;
|
||||||
mFlatTextLength = 0;
|
mFlatTextLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cache(nsINode* aContainer, int32_t aNodeOffset,
|
void Cache(nsINode* aContainer, nsINode* aNode,
|
||||||
uint32_t aFlatTextLength)
|
uint32_t aFlatTextLength)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aContainer, "aContainer must not be null");
|
MOZ_ASSERT(aContainer, "aContainer must not be null");
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(!aNode || aNode->GetParentNode() == aContainer,
|
||||||
aNodeOffset <= static_cast<int32_t>(aContainer->GetChildCount()),
|
"aNode must be either null or a child of aContainer");
|
||||||
"aNodeOffset must be same as or less than the count of children");
|
|
||||||
mContainerNode = aContainer;
|
mContainerNode = aContainer;
|
||||||
mNodeOffset = aNodeOffset;
|
mNode = aNode;
|
||||||
mFlatTextLength = aFlatTextLength;
|
mFlatTextLength = aFlatTextLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Match(nsINode* aContainer, int32_t aNodeOffset) const
|
bool Match(nsINode* aContainer, nsINode* aNode) const
|
||||||
{
|
{
|
||||||
return aContainer == mContainerNode && aNodeOffset == mNodeOffset;
|
return aContainer == mContainerNode && aNode == mNode;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// mEndOfAddedTextCache caches text length from the start of content to
|
// mEndOfAddedTextCache caches text length from the start of content to
|
||||||
|
@ -479,26 +481,25 @@ private:
|
||||||
// handled by the editor and no other mutation (e.g., adding node) occur.
|
// handled by the editor and no other mutation (e.g., adding node) occur.
|
||||||
FlatTextCache mStartOfRemovingTextRangeCache;
|
FlatTextCache mStartOfRemovingTextRangeCache;
|
||||||
|
|
||||||
// mFirstAddedNodeContainer is parent node of first added node in current
|
// mFirstAddedContainer is parent node of first added node in current
|
||||||
// document change. So, this is not nullptr only when a node was added
|
// document change. So, this is not nullptr only when a node was added
|
||||||
// during a document change and the change has not been included into
|
// during a document change and the change has not been included into
|
||||||
// mTextChangeData yet.
|
// mTextChangeData yet.
|
||||||
// Note that this shouldn't be in cycle collection since this is not nullptr
|
// Note that this shouldn't be in cycle collection since this is not nullptr
|
||||||
// only during a document change.
|
// only during a document change.
|
||||||
nsCOMPtr<nsINode> mFirstAddedNodeContainer;
|
nsCOMPtr<nsINode> mFirstAddedContainer;
|
||||||
// mLastAddedNodeContainer is parent node of last added node in current
|
// mLastAddedContainer is parent node of last added node in current
|
||||||
// document change. So, this is not nullptr only when a node was added
|
// document change. So, this is not nullptr only when a node was added
|
||||||
// during a document change and the change has not been included into
|
// during a document change and the change has not been included into
|
||||||
// mTextChangeData yet.
|
// mTextChangeData yet.
|
||||||
// Note that this shouldn't be in cycle collection since this is not nullptr
|
// Note that this shouldn't be in cycle collection since this is not nullptr
|
||||||
// only during a document change.
|
// only during a document change.
|
||||||
nsCOMPtr<nsINode> mLastAddedNodeContainer;
|
nsCOMPtr<nsINode> mLastAddedContainer;
|
||||||
// mFirstAddedNodeOffset is offset of first added node in
|
|
||||||
// mFirstAddedNodeContainer.
|
// mFirstAddedContent is the first node added in mFirstAddedContainer.
|
||||||
int32_t mFirstAddedNodeOffset;
|
nsCOMPtr<nsIContent> mFirstAddedContent;
|
||||||
// mLastAddedNodeOffset is offset of *after* last added node in
|
// mLastAddedContent is the last node added in mLastAddedContainer;
|
||||||
// mLastAddedNodeContainer. I.e., the index of last added node + 1.
|
nsCOMPtr<nsIContent> mLastAddedContent;
|
||||||
int32_t mLastAddedNodeOffset;
|
|
||||||
|
|
||||||
TextChangeData mTextChangeData;
|
TextChangeData mTextChangeData;
|
||||||
|
|
||||||
|
|
|
@ -80,12 +80,6 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||||
*/
|
*/
|
||||||
readonly attribute boolean docCharsetIsForced;
|
readonly attribute boolean docCharsetIsForced;
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current cursor type from this window
|
|
||||||
* @return the current value of nsCursor
|
|
||||||
*/
|
|
||||||
short getCursorType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to get metadata associated with the window's current document
|
* Function to get metadata associated with the window's current document
|
||||||
* @param aName the name of the metadata. This should be all lowercase.
|
* @param aName the name of the metadata. This should be all lowercase.
|
||||||
|
|
|
@ -126,6 +126,15 @@ ImageContainerListener::ClearImageContainer()
|
||||||
mImageContainer = nullptr;
|
mImageContainer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ImageContainerListener::DropImageClient()
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
if (mImageContainer) {
|
||||||
|
mImageContainer->DropImageClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<ImageClient>
|
already_AddRefed<ImageClient>
|
||||||
ImageContainer::GetImageClient()
|
ImageContainer::GetImageClient()
|
||||||
{
|
{
|
||||||
|
@ -162,12 +171,10 @@ ImageContainer::EnsureImageClient()
|
||||||
mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this);
|
mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this);
|
||||||
if (mImageClient) {
|
if (mImageClient) {
|
||||||
mAsyncContainerHandle = mImageClient->GetAsyncHandle();
|
mAsyncContainerHandle = mImageClient->GetAsyncHandle();
|
||||||
mNotifyCompositeListener = new ImageContainerListener(this);
|
|
||||||
} else {
|
} else {
|
||||||
// It's okay to drop the async container handle since the ImageBridgeChild
|
// It's okay to drop the async container handle since the ImageBridgeChild
|
||||||
// is going to die anyway.
|
// is going to die anyway.
|
||||||
mAsyncContainerHandle = CompositableHandle();
|
mAsyncContainerHandle = CompositableHandle();
|
||||||
mNotifyCompositeListener = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,6 +190,7 @@ ImageContainer::ImageContainer(Mode flag)
|
||||||
mCurrentProducerID(-1)
|
mCurrentProducerID(-1)
|
||||||
{
|
{
|
||||||
if (flag == ASYNCHRONOUS) {
|
if (flag == ASYNCHRONOUS) {
|
||||||
|
mNotifyCompositeListener = new ImageContainerListener(this);
|
||||||
EnsureImageClient();
|
EnsureImageClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,6 +389,7 @@ CompositableHandle ImageContainer::GetAsyncContainerHandle()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(IsAsync(), "Shared image ID is only relevant to async ImageContainers");
|
NS_ASSERTION(IsAsync(), "Shared image ID is only relevant to async ImageContainers");
|
||||||
NS_ASSERTION(mAsyncContainerHandle, "Should have a shared image ID");
|
NS_ASSERTION(mAsyncContainerHandle, "Should have a shared image ID");
|
||||||
|
RecursiveMutexAutoLock mon(mRecursiveMutex);
|
||||||
EnsureImageClient();
|
EnsureImageClient();
|
||||||
return mAsyncContainerHandle;
|
return mAsyncContainerHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,6 +344,7 @@ public:
|
||||||
|
|
||||||
void NotifyComposite(const ImageCompositeNotification& aNotification);
|
void NotifyComposite(const ImageCompositeNotification& aNotification);
|
||||||
void ClearImageContainer();
|
void ClearImageContainer();
|
||||||
|
void DropImageClient();
|
||||||
private:
|
private:
|
||||||
typedef mozilla::Mutex Mutex;
|
typedef mozilla::Mutex Mutex;
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
mCanSend = false;
|
mCanSend = false;
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
mImageContainers.Clear();
|
mImageContainerListeners.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,8 +322,8 @@ ImageBridgeChild::Connect(CompositableClient* aCompositable,
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
MOZ_ASSERT(!mImageContainers.Contains(id));
|
MOZ_ASSERT(!mImageContainerListeners.Contains(id));
|
||||||
mImageContainers.Put(id, aImageContainer);
|
mImageContainerListeners.Put(id, aImageContainer->GetImageContainerListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositableHandle handle(id);
|
CompositableHandle handle(id);
|
||||||
|
@ -335,7 +335,7 @@ void
|
||||||
ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
|
ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
mImageContainers.Remove(aHandle.Value());
|
mImageContainerListeners.Remove(aHandle.Value());
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread* ImageBridgeChild::GetThread() const
|
Thread* ImageBridgeChild::GetThread() const
|
||||||
|
@ -739,9 +739,16 @@ ImageBridgeChild::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier&
|
||||||
if (disablingWebRender) {
|
if (disablingWebRender) {
|
||||||
// ImageHost is incompatible between WebRender enabled and WebRender disabled.
|
// ImageHost is incompatible between WebRender enabled and WebRender disabled.
|
||||||
// Then drop all ImageContainers' ImageClients during disabling WebRender.
|
// Then drop all ImageContainers' ImageClients during disabling WebRender.
|
||||||
|
nsTArray<RefPtr<ImageContainerListener> > listeners;
|
||||||
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
for (auto iter = mImageContainers.Iter(); !iter.Done(); iter.Next()) {
|
for (auto iter = mImageContainerListeners.Iter(); !iter.Done(); iter.Next()) {
|
||||||
ImageContainer* container = iter.Data();
|
RefPtr<ImageContainerListener>& listener = iter.Data();
|
||||||
|
listeners.AppendElement(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Drop ImageContainer's ImageClient whithout holding mContainerMapLock to avoid deadlock.
|
||||||
|
for (auto container : listeners) {
|
||||||
container->DropImageClient();
|
container->DropImageClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1014,10 +1021,8 @@ ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&
|
||||||
RefPtr<ImageContainerListener> listener;
|
RefPtr<ImageContainerListener> listener;
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
ImageContainer* imageContainer;
|
if (auto entry = mImageContainerListeners.Lookup(n.compositable().Value())) {
|
||||||
imageContainer = mImageContainers.Get(n.compositable().Value());
|
listener = entry.Data();
|
||||||
if (imageContainer) {
|
|
||||||
listener = imageContainer->GetImageContainerListener();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (listener) {
|
if (listener) {
|
||||||
|
@ -1128,7 +1133,7 @@ ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mContainerMapLock);
|
MutexAutoLock lock(mContainerMapLock);
|
||||||
mImageContainers.Remove(aHandle.Value());
|
mImageContainerListeners.Remove(aHandle.Value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace layers {
|
||||||
class AsyncCanvasRenderer;
|
class AsyncCanvasRenderer;
|
||||||
class ImageClient;
|
class ImageClient;
|
||||||
class ImageContainer;
|
class ImageContainer;
|
||||||
|
class ImageContainerListener;
|
||||||
class ImageBridgeParent;
|
class ImageBridgeParent;
|
||||||
class CompositableClient;
|
class CompositableClient;
|
||||||
struct CompositableTransaction;
|
struct CompositableTransaction;
|
||||||
|
@ -398,7 +399,7 @@ private:
|
||||||
* Mapping from async compositable IDs to image containers.
|
* Mapping from async compositable IDs to image containers.
|
||||||
*/
|
*/
|
||||||
Mutex mContainerMapLock;
|
Mutex mContainerMapLock;
|
||||||
nsDataHashtable<nsUint64HashKey, ImageContainer*> mImageContainers;
|
nsRefPtrHashtable<nsUint64HashKey, ImageContainerListener> mImageContainerListeners;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|
|
@ -394,6 +394,26 @@ public:
|
||||||
|
|
||||||
RectIterator RectIter() const { return RectIterator(*this); }
|
RectIterator RectIter() const { return RectIterator(*this); }
|
||||||
|
|
||||||
|
static inline pixman_box32_t RectToBox(const nsRect &aRect)
|
||||||
|
{
|
||||||
|
pixman_box32_t box = { aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost() };
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline pixman_box32_t RectToBox(const mozilla::gfx::IntRect &aRect)
|
||||||
|
{
|
||||||
|
pixman_box32_t box = { aRect.X(), aRect.Y(), aRect.XMost(), aRect.YMost() };
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline nsRect BoxToRect(const pixman_box32_t &aBox)
|
||||||
|
{
|
||||||
|
return nsRect(aBox.x1, aBox.y1,
|
||||||
|
aBox.x2 - aBox.x1,
|
||||||
|
aBox.y2 - aBox.y1);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pixman_region32_t mImpl;
|
pixman_region32_t mImpl;
|
||||||
|
|
||||||
|
@ -431,26 +451,6 @@ private:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline pixman_box32_t RectToBox(const nsRect &aRect)
|
|
||||||
{
|
|
||||||
pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline pixman_box32_t RectToBox(const mozilla::gfx::IntRect &aRect)
|
|
||||||
{
|
|
||||||
pixman_box32_t box = { aRect.x, aRect.y, aRect.XMost(), aRect.YMost() };
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline nsRect BoxToRect(const pixman_box32_t &aBox)
|
|
||||||
{
|
|
||||||
return nsRect(aBox.x1, aBox.y1,
|
|
||||||
aBox.x2 - aBox.x1,
|
|
||||||
aBox.y2 - aBox.y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pixman_region32_t* Impl() const
|
pixman_region32_t* Impl() const
|
||||||
{
|
{
|
||||||
return const_cast<pixman_region32_t*>(&mImpl);
|
return const_cast<pixman_region32_t*>(&mImpl);
|
||||||
|
|
|
@ -673,13 +673,17 @@ MessageChannel::CanSend() const
|
||||||
void
|
void
|
||||||
MessageChannel::WillDestroyCurrentMessageLoop()
|
MessageChannel::WillDestroyCurrentMessageLoop()
|
||||||
{
|
{
|
||||||
#if !defined(ANDROID)
|
#if defined(DEBUG)
|
||||||
#if defined(MOZ_CRASHREPORTER)
|
#if defined(MOZ_CRASHREPORTER)
|
||||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"),
|
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProtocolName"),
|
||||||
nsDependentCString(mName));
|
nsDependentCString(mName));
|
||||||
#endif
|
#endif
|
||||||
MOZ_CRASH("MessageLoop destroyed before MessageChannel that's bound to it");
|
MOZ_CRASH("MessageLoop destroyed before MessageChannel that's bound to it");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Clear mWorkerThread to avoid posting to it in the future.
|
||||||
|
MonitorAutoLock lock(*mMonitor);
|
||||||
|
mWorkerLoop = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1964,7 +1968,7 @@ MessageChannel::MessageTask::Post()
|
||||||
|
|
||||||
if (eventTarget) {
|
if (eventTarget) {
|
||||||
eventTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
|
eventTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
|
||||||
} else {
|
} else if (mChannel->mWorkerLoop) {
|
||||||
mChannel->mWorkerLoop->PostTask(self.forget());
|
mChannel->mWorkerLoop->PostTask(self.forget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2406,8 +2410,10 @@ MessageChannel::OnChannelConnected(int32_t peer_id)
|
||||||
mPeerPidSet = true;
|
mPeerPidSet = true;
|
||||||
mPeerPid = peer_id;
|
mPeerPid = peer_id;
|
||||||
RefPtr<CancelableRunnable> task = mOnChannelConnectedTask;
|
RefPtr<CancelableRunnable> task = mOnChannelConnectedTask;
|
||||||
|
if (mWorkerLoop) {
|
||||||
mWorkerLoop->PostTask(task.forget());
|
mWorkerLoop->PostTask(task.forget());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MessageChannel::DispatchOnChannelConnected()
|
MessageChannel::DispatchOnChannelConnected()
|
||||||
|
@ -2599,7 +2605,9 @@ MessageChannel::OnNotifyMaybeChannelError()
|
||||||
&MessageChannel::OnNotifyMaybeChannelError);
|
&MessageChannel::OnNotifyMaybeChannelError);
|
||||||
RefPtr<Runnable> task = mChannelErrorTask;
|
RefPtr<Runnable> task = mChannelErrorTask;
|
||||||
// 10 ms delay is completely arbitrary
|
// 10 ms delay is completely arbitrary
|
||||||
|
if (mWorkerLoop) {
|
||||||
mWorkerLoop->PostDelayedTask(task.forget(), 10);
|
mWorkerLoop->PostDelayedTask(task.forget(), 10);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2611,7 +2619,7 @@ MessageChannel::PostErrorNotifyTask()
|
||||||
{
|
{
|
||||||
mMonitor->AssertCurrentThreadOwns();
|
mMonitor->AssertCurrentThreadOwns();
|
||||||
|
|
||||||
if (mChannelErrorTask)
|
if (mChannelErrorTask || !mWorkerLoop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// This must be the last code that runs on this thread!
|
// This must be the last code that runs on this thread!
|
||||||
|
|
|
@ -40,6 +40,14 @@ function isMatchingDestructor(constructor, edge)
|
||||||
if (variable.Name[1].charAt(0) != '~')
|
if (variable.Name[1].charAt(0) != '~')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Note that in some situations, a regular function can begin with '~', so
|
||||||
|
// we don't necessarily have a destructor in hand. This is probably a
|
||||||
|
// sixgill artifact, but in js::wasm::ModuleGenerator::~ModuleGenerator, a
|
||||||
|
// templatized static inline EraseIf is invoked, and it gets named ~EraseIf
|
||||||
|
// for some reason.
|
||||||
|
if (!("PEdgeCallInstance" in edge))
|
||||||
|
return false;
|
||||||
|
|
||||||
var constructExp = constructor.PEdgeCallInstance.Exp;
|
var constructExp = constructor.PEdgeCallInstance.Exp;
|
||||||
assert(constructExp.Kind == "Var");
|
assert(constructExp.Kind == "Var");
|
||||||
|
|
||||||
|
@ -55,7 +63,7 @@ function isMatchingDestructor(constructor, edge)
|
||||||
// treat each instance separately, such as when different regions of a function
|
// treat each instance separately, such as when different regions of a function
|
||||||
// body were guarded by these constructors and you needed to do something
|
// body were guarded by these constructors and you needed to do something
|
||||||
// different with each.)
|
// different with each.)
|
||||||
function allRAIIGuardedCallPoints(bodies, body, isConstructor)
|
function allRAIIGuardedCallPoints(typeInfo, bodies, body, isConstructor)
|
||||||
{
|
{
|
||||||
if (!("PEdge" in body))
|
if (!("PEdge" in body))
|
||||||
return [];
|
return [];
|
||||||
|
@ -70,7 +78,7 @@ function allRAIIGuardedCallPoints(bodies, body, isConstructor)
|
||||||
continue;
|
continue;
|
||||||
var variable = callee.Variable;
|
var variable = callee.Variable;
|
||||||
assert(variable.Kind == "Func");
|
assert(variable.Kind == "Func");
|
||||||
if (!isConstructor(edge.Type, variable.Name))
|
if (!isConstructor(typeInfo, edge.Type, variable.Name))
|
||||||
continue;
|
continue;
|
||||||
if (!("PEdgeCallInstance" in edge))
|
if (!("PEdgeCallInstance" in edge))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
loadRelativeToScript('utility.js');
|
loadRelativeToScript('utility.js');
|
||||||
loadRelativeToScript('annotations.js');
|
loadRelativeToScript('annotations.js');
|
||||||
loadRelativeToScript('CFG.js');
|
loadRelativeToScript('CFG.js');
|
||||||
|
loadRelativeToScript('dumpCFG.js');
|
||||||
|
|
||||||
var sourceRoot = (os.getenv('SOURCE') || '') + '/'
|
var sourceRoot = (os.getenv('SOURCE') || '') + '/'
|
||||||
|
|
||||||
|
@ -29,8 +30,6 @@ var batch = (scriptArgs[5]|0) || 1;
|
||||||
var numBatches = (scriptArgs[6]|0) || 1;
|
var numBatches = (scriptArgs[6]|0) || 1;
|
||||||
var tmpfile = scriptArgs[7] || "tmp.txt";
|
var tmpfile = scriptArgs[7] || "tmp.txt";
|
||||||
|
|
||||||
GCSuppressionTypes = loadTypeInfo(typeInfoFile)["Suppress GC"] || [];
|
|
||||||
|
|
||||||
var gcFunctions = {};
|
var gcFunctions = {};
|
||||||
var text = snarf("gcFunctions.lst").split("\n");
|
var text = snarf("gcFunctions.lst").split("\n");
|
||||||
assert(text.pop().length == 0);
|
assert(text.pop().length == 0);
|
||||||
|
@ -45,6 +44,8 @@ for (var line of text) {
|
||||||
}
|
}
|
||||||
text = null;
|
text = null;
|
||||||
|
|
||||||
|
var typeInfo = loadTypeInfo(typeInfoFile);
|
||||||
|
|
||||||
var gcEdges = {};
|
var gcEdges = {};
|
||||||
text = snarf(gcEdgesFile).split('\n');
|
text = snarf(gcEdgesFile).split('\n');
|
||||||
assert(text.pop().length == 0);
|
assert(text.pop().length == 0);
|
||||||
|
@ -749,7 +750,8 @@ function printEntryTrace(functionName, entry)
|
||||||
|
|
||||||
function isRootedType(type)
|
function isRootedType(type)
|
||||||
{
|
{
|
||||||
return type.Kind == "CSU" && isRootedTypeName(type.Name);
|
return type.Kind == "CSU" && ((type.Name in typeInfo.RootedPointers) ||
|
||||||
|
(type.Name in typeInfo.RootedGCThings));
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeDesc(type)
|
function typeDesc(type)
|
||||||
|
@ -841,7 +843,7 @@ function process(name, json) {
|
||||||
for (var body of functionBodies)
|
for (var body of functionBodies)
|
||||||
body.suppressed = [];
|
body.suppressed = [];
|
||||||
for (var body of functionBodies) {
|
for (var body of functionBodies) {
|
||||||
for (var [pbody, id] of allRAIIGuardedCallPoints(functionBodies, body, isSuppressConstructor))
|
for (var [pbody, id] of allRAIIGuardedCallPoints(typeInfo, functionBodies, body, isSuppressConstructor))
|
||||||
pbody.suppressed[id] = true;
|
pbody.suppressed[id] = true;
|
||||||
}
|
}
|
||||||
processBodies(functionName);
|
processBodies(functionName);
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// RAII types within which we should assume GC is suppressed, eg
|
|
||||||
// AutoSuppressGC.
|
|
||||||
var GCSuppressionTypes = [];
|
|
||||||
|
|
||||||
// Ignore calls made through these function pointers
|
// Ignore calls made through these function pointers
|
||||||
var ignoreIndirectCalls = {
|
var ignoreIndirectCalls = {
|
||||||
"mallocSizeOf" : true,
|
"mallocSizeOf" : true,
|
||||||
|
@ -43,11 +39,20 @@ function indirectCallCannotGC(fullCaller, fullVariable)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// template method called during marking and hence cannot GC
|
// template method called during marking and hence cannot GC
|
||||||
if (name == "op" && caller.indexOf("bool js::WeakMap<Key, Value, HashPolicy>::keyNeedsMark(JSObject*)") != -1)
|
if (name == "op" && caller.includes("bool js::WeakMap<Key, Value, HashPolicy>::keyNeedsMark(JSObject*)"))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call through a 'callback' function pointer, in a place where we're going
|
||||||
|
// to be throwing a JS exception.
|
||||||
|
if (name == "callback" && caller.includes("js::ErrorToException"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The math cache only gets called with non-GC math functions.
|
||||||
|
if (name == "f" && caller.includes("js::MathCache::lookup"))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +223,8 @@ var ignoreFunctions = {
|
||||||
"uint32 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true,
|
"uint32 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true,
|
||||||
"void js::Nursery::freeMallocedBuffers()" : true,
|
"void js::Nursery::freeMallocedBuffers()" : true,
|
||||||
|
|
||||||
|
"void js::AutoEnterOOMUnsafeRegion::crash(uint64, int8*)" : true,
|
||||||
|
|
||||||
// It would be cool to somehow annotate that nsTHashtable<T> will use
|
// It would be cool to somehow annotate that nsTHashtable<T> will use
|
||||||
// nsTHashtable<T>::s_MatchEntry for its matchEntry function pointer, but
|
// nsTHashtable<T>::s_MatchEntry for its matchEntry function pointer, but
|
||||||
// there is no mechanism for that. So we will just annotate a particularly
|
// there is no mechanism for that. So we will just annotate a particularly
|
||||||
|
@ -287,11 +294,11 @@ function ignoreGCFunction(mangled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Templatized function
|
// Templatized function
|
||||||
if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0)
|
if (fun.includes("void nsCOMPtr<T>::Assert_NoQueryNeeded()"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// These call through an 'op' function pointer.
|
// These call through an 'op' function pointer.
|
||||||
if (fun.indexOf("js::WeakMap<Key, Value, HashPolicy>::getDelegate(") >= 0)
|
if (fun.includes("js::WeakMap<Key, Value, HashPolicy>::getDelegate("))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// XXX modify refillFreeList<NoGC> to not need data flow analysis to understand it cannot GC.
|
// XXX modify refillFreeList<NoGC> to not need data flow analysis to understand it cannot GC.
|
||||||
|
@ -307,9 +314,27 @@ function stripUCSAndNamespace(name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRootedGCTypeName(name)
|
function extraRootedGCThings()
|
||||||
{
|
{
|
||||||
return (name == "JSAddonId");
|
return [ 'JSAddonId' ];
|
||||||
|
}
|
||||||
|
|
||||||
|
function extraRootedPointers()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'ModuleValidator',
|
||||||
|
'JSErrorResult',
|
||||||
|
'WrappableJSErrorResult',
|
||||||
|
|
||||||
|
// These are not actually rooted, but are only used in the context of
|
||||||
|
// AutoKeepAtoms.
|
||||||
|
'js::frontend::TokenStream',
|
||||||
|
'js::frontend::TokenStream::Position',
|
||||||
|
|
||||||
|
'mozilla::ErrorResult',
|
||||||
|
'mozilla::IgnoredErrorResult',
|
||||||
|
'mozilla::dom::binding_detail::FastErrorResult',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRootedGCPointerTypeName(name)
|
function isRootedGCPointerTypeName(name)
|
||||||
|
@ -319,33 +344,16 @@ function isRootedGCPointerTypeName(name)
|
||||||
if (name.startsWith('MaybeRooted<'))
|
if (name.startsWith('MaybeRooted<'))
|
||||||
return /\(js::AllowGC\)1u>::RootType/.test(name);
|
return /\(js::AllowGC\)1u>::RootType/.test(name);
|
||||||
|
|
||||||
if (name == "ErrorResult" ||
|
|
||||||
name == "JSErrorResult" ||
|
|
||||||
name == "WrappableJSErrorResult" ||
|
|
||||||
name == "binding_detail::FastErrorResult" ||
|
|
||||||
name == "IgnoredErrorResult" ||
|
|
||||||
name == "frontend::TokenStream" ||
|
|
||||||
name == "frontend::TokenStream::Position" ||
|
|
||||||
name == "ModuleValidator")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
|
return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRootedTypeName(name)
|
|
||||||
{
|
|
||||||
return isRootedGCTypeName(name) || isRootedGCPointerTypeName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isUnsafeStorage(typeName)
|
function isUnsafeStorage(typeName)
|
||||||
{
|
{
|
||||||
typeName = stripUCSAndNamespace(typeName);
|
typeName = stripUCSAndNamespace(typeName);
|
||||||
return typeName.startsWith('UniquePtr<');
|
return typeName.startsWith('UniquePtr<');
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSuppressConstructor(edgeType, varName)
|
function isSuppressConstructor(typeInfo, edgeType, varName)
|
||||||
{
|
{
|
||||||
// Check whether this could be a constructor
|
// Check whether this could be a constructor
|
||||||
if (edgeType.Kind != 'Function')
|
if (edgeType.Kind != 'Function')
|
||||||
|
@ -357,7 +365,7 @@ function isSuppressConstructor(edgeType, varName)
|
||||||
|
|
||||||
// Check whether the type is a known suppression type.
|
// Check whether the type is a known suppression type.
|
||||||
var type = edgeType.TypeFunctionCSU.Type.Name;
|
var type = edgeType.TypeFunctionCSU.Type.Name;
|
||||||
if (GCSuppressionTypes.indexOf(type) == -1)
|
if (!(type in typeInfo.GCSuppressors))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// And now make sure this is the constructor, not some other method on a
|
// And now make sure this is the constructor, not some other method on a
|
||||||
|
|
|
@ -128,7 +128,7 @@ function processBody(functionName, body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GCSuppressionTypes = loadTypeInfo(typeInfo_filename)["Suppress GC"] || [];
|
var typeInfo = loadTypeInfo(typeInfo_filename);
|
||||||
|
|
||||||
loadTypes("src_comp.xdb");
|
loadTypes("src_comp.xdb");
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ function process(functionName, functionBodies)
|
||||||
body.suppressed = [];
|
body.suppressed = [];
|
||||||
|
|
||||||
for (var body of functionBodies) {
|
for (var body of functionBodies) {
|
||||||
for (var [pbody, id] of allRAIIGuardedCallPoints(functionBodies, body, isSuppressConstructor))
|
for (var [pbody, id] of allRAIIGuardedCallPoints(typeInfo, functionBodies, body, isSuppressConstructor))
|
||||||
pbody.suppressed[id] = true;
|
pbody.suppressed[id] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,16 @@ loadRelativeToScript('annotations.js');
|
||||||
var gcTypes_filename = scriptArgs[0] || "gcTypes.txt";
|
var gcTypes_filename = scriptArgs[0] || "gcTypes.txt";
|
||||||
var typeInfo_filename = scriptArgs[1] || "typeInfo.txt";
|
var typeInfo_filename = scriptArgs[1] || "typeInfo.txt";
|
||||||
|
|
||||||
var annotations = {
|
var typeInfo = {
|
||||||
'GCPointers': [],
|
'GCPointers': [],
|
||||||
'GCThings': [],
|
'GCThings': [],
|
||||||
'NonGCTypes': {}, // unused
|
'NonGCTypes': {}, // unused
|
||||||
'NonGCPointers': {},
|
'NonGCPointers': {},
|
||||||
|
'RootedGCThings': {},
|
||||||
'RootedPointers': {},
|
'RootedPointers': {},
|
||||||
|
|
||||||
|
// RAII types within which we should assume GC is suppressed, eg
|
||||||
|
// AutoSuppressGC.
|
||||||
'GCSuppressors': {},
|
'GCSuppressors': {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,6 +26,7 @@ var gDescriptors = new Map; // Map from descriptor string => Set of typeName
|
||||||
var structureParents = {}; // Map from field => list of <parent, fieldName>
|
var structureParents = {}; // Map from field => list of <parent, fieldName>
|
||||||
var pointerParents = {}; // Map from field => list of <parent, fieldName>
|
var pointerParents = {}; // Map from field => list of <parent, fieldName>
|
||||||
var baseClasses = {}; // Map from struct name => list of base class name strings
|
var baseClasses = {}; // Map from struct name => list of base class name strings
|
||||||
|
var subClasses = {}; // Map from struct name => list of subclass name strings
|
||||||
|
|
||||||
var gcTypes = {}; // map from parent struct => Set of GC typed children
|
var gcTypes = {}; // map from parent struct => Set of GC typed children
|
||||||
var gcPointers = {}; // map from parent struct => Set of GC typed children
|
var gcPointers = {}; // map from parent struct => Set of GC typed children
|
||||||
|
@ -61,17 +66,17 @@ function processCSU(csu, body)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (tag == 'GC Pointer')
|
if (tag == 'GC Pointer')
|
||||||
annotations.GCPointers.push(csu);
|
typeInfo.GCPointers.push(csu);
|
||||||
else if (tag == 'Invalidated by GC')
|
else if (tag == 'Invalidated by GC')
|
||||||
annotations.GCPointers.push(csu);
|
typeInfo.GCPointers.push(csu);
|
||||||
else if (tag == 'GC Thing')
|
else if (tag == 'GC Thing')
|
||||||
annotations.GCThings.push(csu);
|
typeInfo.GCThings.push(csu);
|
||||||
else if (tag == 'Suppressed GC Pointer')
|
else if (tag == 'Suppressed GC Pointer')
|
||||||
annotations.NonGCPointers[csu] = true;
|
typeInfo.NonGCPointers[csu] = true;
|
||||||
else if (tag == 'Rooted Pointer')
|
else if (tag == 'Rooted Pointer')
|
||||||
annotations.RootedPointers[csu] = true;
|
typeInfo.RootedPointers[csu] = true;
|
||||||
else if (tag == 'Suppress GC')
|
else if (tag == 'Suppress GC')
|
||||||
annotations.GCSuppressors[csu] = true;
|
typeInfo.GCSuppressors[csu] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +96,9 @@ function addBaseClass(csu, base) {
|
||||||
if (!(csu in baseClasses))
|
if (!(csu in baseClasses))
|
||||||
baseClasses[csu] = [];
|
baseClasses[csu] = [];
|
||||||
baseClasses[csu].push(base);
|
baseClasses[csu].push(base);
|
||||||
|
if (!(base in subClasses))
|
||||||
|
subClasses[base] = [];
|
||||||
|
subClasses[base].push(csu);
|
||||||
var k = baseClasses[csu].length;
|
var k = baseClasses[csu].length;
|
||||||
addNestedStructure(csu, base, `<base-${k}>`);
|
addNestedStructure(csu, base, `<base-${k}>`);
|
||||||
}
|
}
|
||||||
|
@ -119,22 +127,24 @@ for (var csuIndex = minStream; csuIndex <= maxStream; csuIndex++) {
|
||||||
xdb.free_string(data);
|
xdb.free_string(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const typename of extraRootedGCThings())
|
||||||
|
typeInfo.RootedGCThings[typename] = true;
|
||||||
|
|
||||||
|
for (const typename of extraRootedPointers())
|
||||||
|
typeInfo.RootedPointers[typename] = true;
|
||||||
|
|
||||||
// Now that we have the whole hierarchy set up, add all the types and propagate
|
// Now that we have the whole hierarchy set up, add all the types and propagate
|
||||||
// info.
|
// info.
|
||||||
for (let csu of annotations.GCThings)
|
for (const csu of typeInfo.GCThings)
|
||||||
addGCType(csu);
|
addGCType(csu);
|
||||||
for (let csu of annotations.GCPointers)
|
for (const csu of typeInfo.GCPointers)
|
||||||
addGCPointer(csu);
|
addGCPointer(csu);
|
||||||
|
|
||||||
function stars(n) { return n ? '*' + stars(n-1) : '' };
|
|
||||||
|
|
||||||
// "typeName is a (pointer to a)^'typePtrLevel' GC type because it contains a field
|
// "typeName is a (pointer to a)^'typePtrLevel' GC type because it contains a field
|
||||||
// named 'child' of type 'why' (or pointer to 'why' if fieldPtrLevel == 1), which is
|
// named 'child' of type 'why' (or pointer to 'why' if fieldPtrLevel == 1), which is
|
||||||
// itself a GCThing or GCPointer."
|
// itself a GCThing or GCPointer."
|
||||||
function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent)
|
function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent)
|
||||||
{
|
{
|
||||||
//printErr(`${indent}${typeName}${stars(typePtrLevel)} may be a gctype/ptr because of its child '${child}' of type ${why}${stars(fieldPtrLevel)}`);
|
|
||||||
|
|
||||||
// Some types, like UniquePtr, do not mark/trace/relocate their contained
|
// Some types, like UniquePtr, do not mark/trace/relocate their contained
|
||||||
// pointers and so should not hold them live across a GC. UniquePtr in
|
// pointers and so should not hold them live across a GC. UniquePtr in
|
||||||
// particular should be the only thing pointing to a structure containing a
|
// particular should be the only thing pointing to a structure containing a
|
||||||
|
@ -166,19 +176,22 @@ function markGCType(typeName, child, why, typePtrLevel, fieldPtrLevel, indent)
|
||||||
if (ptrLevel > 2)
|
if (ptrLevel > 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ptrLevel == 0 && isRootedGCTypeName(typeName))
|
if (isRootedGCPointerTypeName(typeName) && !(typeName in typeInfo.RootedPointers))
|
||||||
|
printErr("FIXME: use in-source annotation for " + typeName);
|
||||||
|
|
||||||
|
if (ptrLevel == 0 && (typeName in typeInfo.RootedGCThings))
|
||||||
return;
|
return;
|
||||||
if (ptrLevel == 1 && isRootedGCPointerTypeName(typeName))
|
if (ptrLevel == 1 && (isRootedGCPointerTypeName(typeName) || (typeName in typeInfo.RootedPointers)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ptrLevel == 0) {
|
if (ptrLevel == 0) {
|
||||||
if (typeName in annotations.NonGCTypes)
|
if (typeName in typeInfo.NonGCTypes)
|
||||||
return;
|
return;
|
||||||
if (!(typeName in gcTypes))
|
if (!(typeName in gcTypes))
|
||||||
gcTypes[typeName] = new Set();
|
gcTypes[typeName] = new Set();
|
||||||
gcTypes[typeName].add(why);
|
gcTypes[typeName].add(why);
|
||||||
} else if (ptrLevel == 1) {
|
} else if (ptrLevel == 1) {
|
||||||
if (typeName in annotations.NonGCPointers)
|
if (typeName in typeInfo.NonGCPointers)
|
||||||
return;
|
return;
|
||||||
if (!(typeName in gcPointers))
|
if (!(typeName in gcPointers))
|
||||||
gcPointers[typeName] = new Set();
|
gcPointers[typeName] = new Set();
|
||||||
|
@ -215,28 +228,34 @@ function addGCPointer(typeName)
|
||||||
markGCType(typeName, '<pointer-annotation>', '(annotation)', 1, 0, "");
|
markGCType(typeName, '<pointer-annotation>', '(annotation)', 1, 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an arbitrary descriptor to a type, and apply it recursively to all base
|
// Call a function for a type and every type that contains the type in a field
|
||||||
// structs and structs that contain the given typeName as a field.
|
// or as a base class (which internally is pretty much the same thing --
|
||||||
function addDescriptor(typeName, descriptor)
|
// sublcasses are structs beginning with the base class and adding on their
|
||||||
|
// local fields.)
|
||||||
|
function foreachContainingStruct(typeName, func, seen = new Set())
|
||||||
{
|
{
|
||||||
if (!gDescriptors.has(descriptor))
|
function recurse(container, typeName) {
|
||||||
gDescriptors.set(descriptor, new Set);
|
if (seen.has(typeName))
|
||||||
let descriptorTypes = gDescriptors.get(descriptor);
|
return;
|
||||||
if (!descriptorTypes.has(typeName)) {
|
seen.add(typeName);
|
||||||
descriptorTypes.add(typeName);
|
|
||||||
|
func(container, typeName);
|
||||||
|
|
||||||
|
if (typeName in subClasses) {
|
||||||
|
for (const sub of subClasses[typeName])
|
||||||
|
recurse("subclass of " + typeName, sub);
|
||||||
|
}
|
||||||
if (typeName in structureParents) {
|
if (typeName in structureParents) {
|
||||||
for (let [holder, field] of structureParents[typeName])
|
for (const [holder, field] of structureParents[typeName])
|
||||||
addDescriptor(holder, descriptor);
|
recurse(field + " : " + typeName, holder);
|
||||||
}
|
|
||||||
if (typeName in baseClasses) {
|
|
||||||
for (let base of baseClasses[typeName])
|
|
||||||
addDescriptor(base, descriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recurse('<annotation>', typeName);
|
||||||
|
}
|
||||||
|
|
||||||
for (var type of listNonGCPointers())
|
for (var type of listNonGCPointers())
|
||||||
annotations.NonGCPointers[type] = true;
|
typeInfo.NonGCPointers[type] = true;
|
||||||
|
|
||||||
function explain(csu, indent, seen) {
|
function explain(csu, indent, seen) {
|
||||||
if (!seen)
|
if (!seen)
|
||||||
|
@ -288,12 +307,14 @@ for (var csu in gcPointers) {
|
||||||
// Redirect output to the typeInfo file and close the gcTypes file.
|
// Redirect output to the typeInfo file and close the gcTypes file.
|
||||||
os.file.close(os.file.redirect(typeInfo_filename));
|
os.file.close(os.file.redirect(typeInfo_filename));
|
||||||
|
|
||||||
for (let csu in annotations.GCSuppressors)
|
// Compute the set of types that suppress GC within their RAII scopes (eg
|
||||||
addDescriptor(csu, 'Suppress GC');
|
// AutoSuppressGC, AutoSuppressGCForAnalysis).
|
||||||
|
var seen = new Set();
|
||||||
|
for (let csu in typeInfo.GCSuppressors)
|
||||||
|
foreachContainingStruct(csu,
|
||||||
|
(holder, typeName) => { typeInfo.GCSuppressors[typeName] = holder },
|
||||||
|
seen);
|
||||||
|
|
||||||
for (let [descriptor, types] of gDescriptors) {
|
print(JSON.stringify(typeInfo, null, 4));
|
||||||
for (let csu of types)
|
|
||||||
print(descriptor + "$$" + csu);
|
|
||||||
}
|
|
||||||
|
|
||||||
os.file.close(os.file.redirect(origOut));
|
os.file.close(os.file.redirect(origOut));
|
||||||
|
|
|
@ -241,7 +241,10 @@ function str_edge(edge, env) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function str(unknown) {
|
function str(unknown) {
|
||||||
if ("Index" in unknown) {
|
if ("Name" in unknown) {
|
||||||
|
return str_Variable(unknown);
|
||||||
|
} else if ("Index" in unknown) {
|
||||||
|
// Note: Variable also has .Index, with a different meaning.
|
||||||
return str_edge(unknown);
|
return str_edge(unknown);
|
||||||
} else if ("Kind" in unknown) {
|
} else if ("Kind" in unknown) {
|
||||||
if ("BlockId" in unknown)
|
if ("BlockId" in unknown)
|
||||||
|
|
|
@ -267,11 +267,5 @@ function addToKeyedList(collection, key, entry)
|
||||||
|
|
||||||
function loadTypeInfo(filename)
|
function loadTypeInfo(filename)
|
||||||
{
|
{
|
||||||
var info = {};
|
return JSON.parse(os.file.readFile(filename));
|
||||||
for (var line of readFileLines_gen(filename)) {
|
|
||||||
line = line.replace(/\n/, "");
|
|
||||||
let [property, name] = line.split("$$");
|
|
||||||
addToKeyedList(info, property, name);
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ EXPORTS += [
|
||||||
'FrameProperties.h',
|
'FrameProperties.h',
|
||||||
'LayoutLogging.h',
|
'LayoutLogging.h',
|
||||||
'MobileViewportManager.h',
|
'MobileViewportManager.h',
|
||||||
|
'nsAutoLayoutPhase.h',
|
||||||
'nsBidi.h',
|
'nsBidi.h',
|
||||||
'nsBidiPresUtils.h',
|
'nsBidiPresUtils.h',
|
||||||
'nsCaret.h',
|
'nsCaret.h',
|
||||||
|
|
|
@ -33,14 +33,27 @@ nsAutoLayoutPhase::Enter()
|
||||||
case eLayoutPhase_Paint:
|
case eLayoutPhase_Paint:
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||||
"recurring into paint");
|
"recurring into paint");
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_DisplayListBuilding] == 0,
|
||||||
|
"recurring into paint from display list building");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||||
"painting in the middle of reflow");
|
"painting in the middle of reflow");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||||
"painting in the middle of frame construction");
|
"painting in the middle of frame construction");
|
||||||
break;
|
break;
|
||||||
|
case eLayoutPhase_DisplayListBuilding:
|
||||||
|
// It's fine and expected to be in a paint here.
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_DisplayListBuilding] == 0,
|
||||||
|
"recurring into display list building");
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||||
|
"display list building in the middle of reflow");
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||||
|
"display list building in the middle of frame construction");
|
||||||
|
break;
|
||||||
case eLayoutPhase_Reflow:
|
case eLayoutPhase_Reflow:
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||||
"reflowing in the middle of a paint");
|
"reflowing in the middle of a paint");
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_DisplayListBuilding] == 0,
|
||||||
|
"reflowing in the middle of a display list building");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||||
"recurring into reflow");
|
"recurring into reflow");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||||
|
@ -49,6 +62,8 @@ nsAutoLayoutPhase::Enter()
|
||||||
case eLayoutPhase_FrameC:
|
case eLayoutPhase_FrameC:
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||||
"constructing frames in the middle of a paint");
|
"constructing frames in the middle of a paint");
|
||||||
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_DisplayListBuilding] == 0,
|
||||||
|
"constructing frames in the middle of a display list building");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||||
"constructing frames in the middle of reflow");
|
"constructing frames in the middle of reflow");
|
||||||
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
MOZ_ASSERT(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||||
|
|
|
@ -2709,22 +2709,46 @@ nsLayoutUtils::PostTranslate(Matrix4x4& aTransform, const nsPoint& aOrigin, floa
|
||||||
aTransform.PostTranslate(gfxOrigin);
|
aTransform.PostTranslate(gfxOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want to this return true for the scroll frame, but not the
|
||||||
|
// scrolled frame (which has the same content).
|
||||||
|
bool
|
||||||
|
nsLayoutUtils::FrameHasDisplayPort(nsIFrame* aFrame, nsIFrame* aScrolledFrame)
|
||||||
|
{
|
||||||
|
if (!aFrame->GetContent() || !HasDisplayPort(aFrame->GetContent())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nsIScrollableFrame* sf = do_QueryFrame(aFrame);
|
||||||
|
if (sf) {
|
||||||
|
if (aScrolledFrame && aScrolledFrame != sf->GetScrolledFrame()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4x4
|
Matrix4x4
|
||||||
nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame,
|
nsLayoutUtils::GetTransformToAncestor(nsIFrame *aFrame,
|
||||||
const nsIFrame *aAncestor,
|
const nsIFrame *aAncestor,
|
||||||
bool aInCSSUnits)
|
uint32_t aFlags,
|
||||||
|
nsIFrame** aOutAncestor)
|
||||||
{
|
{
|
||||||
nsIFrame* parent;
|
nsIFrame* parent;
|
||||||
Matrix4x4 ctm;
|
Matrix4x4 ctm;
|
||||||
if (aFrame == aAncestor) {
|
if (aFrame == aAncestor) {
|
||||||
return ctm;
|
return ctm;
|
||||||
}
|
}
|
||||||
ctm = aFrame->GetTransformMatrix(aAncestor, &parent, aInCSSUnits);
|
ctm = aFrame->GetTransformMatrix(aAncestor, &parent, aFlags);
|
||||||
while (parent && parent != aAncestor) {
|
while (parent && parent != aAncestor &&
|
||||||
|
(!(aFlags & nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
|
||||||
|
(!parent->IsStackingContext() && !FrameHasDisplayPort(parent)))) {
|
||||||
if (!parent->Extend3DContext()) {
|
if (!parent->Extend3DContext()) {
|
||||||
ctm.ProjectTo2D();
|
ctm.ProjectTo2D();
|
||||||
}
|
}
|
||||||
ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent, aInCSSUnits);
|
ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent, aFlags);
|
||||||
|
}
|
||||||
|
if (aOutAncestor) {
|
||||||
|
*aOutAncestor = parent;
|
||||||
}
|
}
|
||||||
return ctm;
|
return ctm;
|
||||||
}
|
}
|
||||||
|
@ -3029,7 +3053,9 @@ TransformGfxRectToAncestor(nsIFrame *aFrame,
|
||||||
const Rect &aRect,
|
const Rect &aRect,
|
||||||
const nsIFrame *aAncestor,
|
const nsIFrame *aAncestor,
|
||||||
bool* aPreservesAxisAlignedRectangles = nullptr,
|
bool* aPreservesAxisAlignedRectangles = nullptr,
|
||||||
Maybe<Matrix4x4>* aMatrixCache = nullptr)
|
Maybe<Matrix4x4>* aMatrixCache = nullptr,
|
||||||
|
bool aStopAtStackingContextAndDisplayPort = false,
|
||||||
|
nsIFrame** aOutAncestor = nullptr)
|
||||||
{
|
{
|
||||||
Matrix4x4 ctm;
|
Matrix4x4 ctm;
|
||||||
if (aMatrixCache && *aMatrixCache) {
|
if (aMatrixCache && *aMatrixCache) {
|
||||||
|
@ -3037,7 +3063,11 @@ TransformGfxRectToAncestor(nsIFrame *aFrame,
|
||||||
ctm = aMatrixCache->value();
|
ctm = aMatrixCache->value();
|
||||||
} else {
|
} else {
|
||||||
// Else, compute it
|
// Else, compute it
|
||||||
ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor);
|
uint32_t flags = 0;
|
||||||
|
if (aStopAtStackingContextAndDisplayPort) {
|
||||||
|
flags |= nsIFrame::STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT;
|
||||||
|
}
|
||||||
|
ctm = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestor, flags, aOutAncestor);
|
||||||
if (aMatrixCache) {
|
if (aMatrixCache) {
|
||||||
// and put it in the cache, if provided
|
// and put it in the cache, if provided
|
||||||
*aMatrixCache = Some(ctm);
|
*aMatrixCache = Some(ctm);
|
||||||
|
@ -3098,7 +3128,9 @@ nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
|
||||||
const nsRect& aRect,
|
const nsRect& aRect,
|
||||||
const nsIFrame* aAncestor,
|
const nsIFrame* aAncestor,
|
||||||
bool* aPreservesAxisAlignedRectangles /* = nullptr */,
|
bool* aPreservesAxisAlignedRectangles /* = nullptr */,
|
||||||
Maybe<Matrix4x4>* aMatrixCache /* = nullptr */)
|
Maybe<Matrix4x4>* aMatrixCache /* = nullptr */,
|
||||||
|
bool aStopAtStackingContextAndDisplayPort /* = false */,
|
||||||
|
nsIFrame** aOutAncestor /* = nullptr */)
|
||||||
{
|
{
|
||||||
SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
|
SVGTextFrame* text = GetContainingSVGTextFrame(aFrame);
|
||||||
|
|
||||||
|
@ -3107,7 +3139,9 @@ nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
|
||||||
|
|
||||||
if (text) {
|
if (text) {
|
||||||
result = ToRect(text->TransformFrameRectFromTextChild(aRect, aFrame));
|
result = ToRect(text->TransformFrameRectFromTextChild(aRect, aFrame));
|
||||||
result = TransformGfxRectToAncestor(text, result, aAncestor, nullptr, aMatrixCache);
|
result = TransformGfxRectToAncestor(text, result, aAncestor,
|
||||||
|
nullptr, aMatrixCache,
|
||||||
|
aStopAtStackingContextAndDisplayPort, aOutAncestor);
|
||||||
// TransformFrameRectFromTextChild could involve any kind of transform, we
|
// TransformFrameRectFromTextChild could involve any kind of transform, we
|
||||||
// could drill down into it to get an answer out of it but we don't yet.
|
// could drill down into it to get an answer out of it but we don't yet.
|
||||||
if (aPreservesAxisAlignedRectangles)
|
if (aPreservesAxisAlignedRectangles)
|
||||||
|
@ -3117,7 +3151,9 @@ nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
|
||||||
NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
|
NSAppUnitsToFloatPixels(aRect.y, srcAppUnitsPerDevPixel),
|
||||||
NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
|
NSAppUnitsToFloatPixels(aRect.width, srcAppUnitsPerDevPixel),
|
||||||
NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
|
NSAppUnitsToFloatPixels(aRect.height, srcAppUnitsPerDevPixel));
|
||||||
result = TransformGfxRectToAncestor(aFrame, result, aAncestor, aPreservesAxisAlignedRectangles, aMatrixCache);
|
result = TransformGfxRectToAncestor(aFrame, result, aAncestor,
|
||||||
|
aPreservesAxisAlignedRectangles, aMatrixCache,
|
||||||
|
aStopAtStackingContextAndDisplayPort, aOutAncestor);
|
||||||
}
|
}
|
||||||
|
|
||||||
float destAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
|
float destAppUnitsPerDevPixel = aAncestor->PresContext()->AppUnitsPerDevPixel();
|
||||||
|
@ -3492,6 +3528,46 @@ nsLayoutUtils::ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsLayoutUtils::AddExtraBackgroundItems(nsDisplayListBuilder& aBuilder,
|
||||||
|
nsDisplayList& aList,
|
||||||
|
nsIFrame* aFrame,
|
||||||
|
const nsRect& aCanvasArea,
|
||||||
|
const nsRegion& aVisibleRegion,
|
||||||
|
nscolor aBackstop)
|
||||||
|
{
|
||||||
|
LayoutFrameType frameType = aFrame->Type();
|
||||||
|
nsPresContext* presContext = aFrame->PresContext();
|
||||||
|
nsIPresShell* presShell = presContext->PresShell();
|
||||||
|
|
||||||
|
// For the viewport frame in print preview/page layout we want to paint
|
||||||
|
// the grey background behind the page, not the canvas color.
|
||||||
|
if (frameType == LayoutFrameType::Viewport &&
|
||||||
|
nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
|
||||||
|
nsRect bounds = nsRect(aBuilder.ToReferenceFrame(aFrame),
|
||||||
|
aFrame->GetSize());
|
||||||
|
nsDisplayListBuilder::AutoBuildingDisplayList
|
||||||
|
buildingDisplayList(&aBuilder, aFrame, bounds, false);
|
||||||
|
presShell->AddPrintPreviewBackgroundItem(aBuilder, aList, aFrame, bounds);
|
||||||
|
} else if (frameType != LayoutFrameType::Page) {
|
||||||
|
// For printing, this function is first called on an nsPageFrame, which
|
||||||
|
// creates a display list with a PageContent item. The PageContent item's
|
||||||
|
// paint function calls this function on the nsPageFrame's child which is
|
||||||
|
// an nsPageContentFrame. We only want to add the canvas background color
|
||||||
|
// item once, for the nsPageContentFrame.
|
||||||
|
|
||||||
|
// Add the canvas background color to the bottom of the list. This
|
||||||
|
// happens after we've built the list so that AddCanvasBackgroundColorItem
|
||||||
|
// can monkey with the contents if necessary.
|
||||||
|
nsRect canvasArea = aVisibleRegion.GetBounds();
|
||||||
|
canvasArea.IntersectRect(aCanvasArea, canvasArea);
|
||||||
|
nsDisplayListBuilder::AutoBuildingDisplayList
|
||||||
|
buildingDisplayList(&aBuilder, aFrame, canvasArea, false);
|
||||||
|
presShell->AddCanvasBackgroundColorItem(
|
||||||
|
aBuilder, aList, aFrame, canvasArea, aBackstop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
||||||
const nsRegion& aDirtyRegion, nscolor aBackstop,
|
const nsRegion& aDirtyRegion, nscolor aBackstop,
|
||||||
|
@ -3650,33 +3726,7 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
|
||||||
aFrame->BuildDisplayListForStackingContext(&builder, &list);
|
aFrame->BuildDisplayListForStackingContext(&builder, &list);
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutFrameType frameType = aFrame->Type();
|
AddExtraBackgroundItems(builder, list, aFrame, canvasArea, visibleRegion, aBackstop);
|
||||||
|
|
||||||
// For the viewport frame in print preview/page layout we want to paint
|
|
||||||
// the grey background behind the page, not the canvas color.
|
|
||||||
if (frameType == LayoutFrameType::Viewport &&
|
|
||||||
nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
|
|
||||||
nsRect bounds = nsRect(builder.ToReferenceFrame(aFrame),
|
|
||||||
aFrame->GetSize());
|
|
||||||
nsDisplayListBuilder::AutoBuildingDisplayList
|
|
||||||
buildingDisplayList(&builder, aFrame, bounds, false);
|
|
||||||
presShell->AddPrintPreviewBackgroundItem(builder, list, aFrame, bounds);
|
|
||||||
} else if (frameType != LayoutFrameType::Page) {
|
|
||||||
// For printing, this function is first called on an nsPageFrame, which
|
|
||||||
// creates a display list with a PageContent item. The PageContent item's
|
|
||||||
// paint function calls this function on the nsPageFrame's child which is
|
|
||||||
// an nsPageContentFrame. We only want to add the canvas background color
|
|
||||||
// item once, for the nsPageContentFrame.
|
|
||||||
|
|
||||||
// Add the canvas background color to the bottom of the list. This
|
|
||||||
// happens after we've built the list so that AddCanvasBackgroundColorItem
|
|
||||||
// can monkey with the contents if necessary.
|
|
||||||
canvasArea.IntersectRect(canvasArea, visibleRegion.GetBounds());
|
|
||||||
nsDisplayListBuilder::AutoBuildingDisplayList
|
|
||||||
buildingDisplayList(&builder, aFrame, canvasArea, false);
|
|
||||||
presShell->AddCanvasBackgroundColorItem(
|
|
||||||
builder, list, aFrame, canvasArea, aBackstop);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.LeavePresShell(aFrame, &list);
|
builder.LeavePresShell(aFrame, &list);
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,14 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool HasDisplayPort(nsIContent* aContent);
|
static bool HasDisplayPort(nsIContent* aContent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given frame has a displayport. It returns false
|
||||||
|
* for scrolled frames and true for the corresponding scroll frame.
|
||||||
|
* Optionally pass the child, and it only returns true if the child is the
|
||||||
|
* scrolled frame for the displayport.
|
||||||
|
*/
|
||||||
|
static bool FrameHasDisplayPort(nsIFrame* aFrame, nsIFrame* aScrolledFrame = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given element has a margins based displayport but is missing a
|
* Check if the given element has a margins based displayport but is missing a
|
||||||
* displayport base rect that it needs to properly compute a displayport rect.
|
* displayport base rect that it needs to properly compute a displayport rect.
|
||||||
|
@ -865,7 +873,9 @@ public:
|
||||||
const nsRect& aRect,
|
const nsRect& aRect,
|
||||||
const nsIFrame* aAncestor,
|
const nsIFrame* aAncestor,
|
||||||
bool* aPreservesAxisAlignedRectangles = nullptr,
|
bool* aPreservesAxisAlignedRectangles = nullptr,
|
||||||
mozilla::Maybe<Matrix4x4>* aMatrixCache = nullptr);
|
mozilla::Maybe<Matrix4x4>* aMatrixCache = nullptr,
|
||||||
|
bool aStopAtStackingContextAndDisplayPort = false,
|
||||||
|
nsIFrame** aOutAncestor = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -875,7 +885,8 @@ public:
|
||||||
*/
|
*/
|
||||||
static Matrix4x4 GetTransformToAncestor(nsIFrame *aFrame,
|
static Matrix4x4 GetTransformToAncestor(nsIFrame *aFrame,
|
||||||
const nsIFrame *aAncestor,
|
const nsIFrame *aAncestor,
|
||||||
bool aInCSSUnits = false);
|
uint32_t aFlags = 0,
|
||||||
|
nsIFrame** aOutAncestor = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the scale factors of the transform for aFrame relative to the root
|
* Gets the scale factors of the transform for aFrame relative to the root
|
||||||
|
@ -2235,6 +2246,13 @@ public:
|
||||||
static nsIContent*
|
static nsIContent*
|
||||||
GetEditableRootContentByContentEditable(nsIDocument* aDocument);
|
GetEditableRootContentByContentEditable(nsIDocument* aDocument);
|
||||||
|
|
||||||
|
static void AddExtraBackgroundItems(nsDisplayListBuilder& aBuilder,
|
||||||
|
nsDisplayList& aList,
|
||||||
|
nsIFrame* aFrame,
|
||||||
|
const nsRect& aCanvasArea,
|
||||||
|
const nsRegion& aVisibleRegion,
|
||||||
|
nscolor aBackstop);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the passed in prescontext needs the dark grey background
|
* Returns true if the passed in prescontext needs the dark grey background
|
||||||
* that goes behind the page of a print preview presentation.
|
* that goes behind the page of a print preview presentation.
|
||||||
|
|
|
@ -108,6 +108,7 @@ struct nsAutoLayoutPhase;
|
||||||
|
|
||||||
enum nsLayoutPhase {
|
enum nsLayoutPhase {
|
||||||
eLayoutPhase_Paint,
|
eLayoutPhase_Paint,
|
||||||
|
eLayoutPhase_DisplayListBuilding, // sometimes a subset of the paint phase
|
||||||
eLayoutPhase_Reflow,
|
eLayoutPhase_Reflow,
|
||||||
eLayoutPhase_FrameC,
|
eLayoutPhase_FrameC,
|
||||||
eLayoutPhase_COUNT
|
eLayoutPhase_COUNT
|
||||||
|
|
|
@ -366,8 +366,6 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
|
||||||
LogicalPoint(mBlockWM,
|
LogicalPoint(mBlockWM,
|
||||||
mScrollableFrame->GetScrollPosition(),
|
mScrollableFrame->GetScrollPosition(),
|
||||||
nullContainerSize));
|
nullContainerSize));
|
||||||
nsIFrame* scrollFrame = do_QueryFrame(mScrollableFrame);
|
|
||||||
scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
|
|
||||||
}
|
}
|
||||||
uint8_t direction = aBlockFrame->StyleVisibility()->mDirection;
|
uint8_t direction = aBlockFrame->StyleVisibility()->mDirection;
|
||||||
const nsStyleTextReset* style = aBlockFrame->StyleTextReset();
|
const nsStyleTextReset* style = aBlockFrame->StyleTextReset();
|
||||||
|
|
|
@ -1326,11 +1326,18 @@ nsIFrame::GetMarginRectRelativeToSelf() const
|
||||||
bool
|
bool
|
||||||
nsIFrame::IsTransformed(const nsStyleDisplay* aStyleDisplay,
|
nsIFrame::IsTransformed(const nsStyleDisplay* aStyleDisplay,
|
||||||
EffectSet* aEffectSet) const
|
EffectSet* aEffectSet) const
|
||||||
|
{
|
||||||
|
return IsCSSTransformed(aStyleDisplay, aEffectSet) ||
|
||||||
|
IsSVGTransformed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsIFrame::IsCSSTransformed(const nsStyleDisplay* aStyleDisplay,
|
||||||
|
EffectSet* aEffectSet) const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||||
return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||||
(aStyleDisplay->HasTransform(this) ||
|
(aStyleDisplay->HasTransform(this) ||
|
||||||
IsSVGTransformed() ||
|
|
||||||
HasAnimationOfTransform(aEffectSet)));
|
HasAnimationOfTransform(aEffectSet)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1402,7 +1409,7 @@ nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay,
|
||||||
if (!parent || !parent->Extend3DContext()) {
|
if (!parent || !parent->Extend3DContext()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return IsTransformed(aStyleDisplay,aEffectSet) ||
|
return IsCSSTransformed(aStyleDisplay, aEffectSet) ||
|
||||||
BackfaceIsHidden(aStyleDisplay);
|
BackfaceIsHidden(aStyleDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3108,21 +3115,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||||
const nsStyleDisplay* disp = child->StyleDisplay();
|
const nsStyleDisplay* disp = child->StyleDisplay();
|
||||||
const nsStyleEffects* effects = child->StyleEffects();
|
const nsStyleEffects* effects = child->StyleEffects();
|
||||||
const nsStylePosition* pos = child->StylePosition();
|
const nsStylePosition* pos = child->StylePosition();
|
||||||
bool isVisuallyAtomic = child->HasOpacity(effectSet)
|
bool isVisuallyAtomic = child->IsVisuallyAtomic(effectSet, disp, effects);
|
||||||
|| child->IsTransformed(disp, effectSet)
|
|
||||||
// strictly speaking, 'perspective' doesn't require visual atomicity,
|
|
||||||
// but the spec says it acts like the rest of these
|
|
||||||
|| disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
|
|
||||||
|| effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
|
|
||||||
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
|
|
||||||
|
|
||||||
bool isPositioned = disp->IsAbsPosContainingBlock(child);
|
bool isPositioned = disp->IsAbsPosContainingBlock(child);
|
||||||
bool isStackingContext =
|
bool isStackingContext = child->IsStackingContext(disp, pos, isPositioned, isVisuallyAtomic) ||
|
||||||
(isPositioned && (disp->IsPositionForcingStackingContext() ||
|
(aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
|
||||||
pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
|
|
||||||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
|
|
||||||
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
|
|
||||||
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
|
|
||||||
|
|
||||||
if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
|
if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
|
||||||
((effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
|
((effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
|
||||||
|
@ -6298,7 +6294,7 @@ nsIFrame::GetFlattenedTreeParentPrimaryFrame() const
|
||||||
Matrix4x4
|
Matrix4x4
|
||||||
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
nsIFrame** aOutAncestor,
|
nsIFrame** aOutAncestor,
|
||||||
bool aInCSSUnits)
|
uint32_t aFlags)
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
|
NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
|
||||||
|
|
||||||
|
@ -6312,7 +6308,7 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
*/
|
*/
|
||||||
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
|
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
|
||||||
"Cannot transform the viewport frame!");
|
"Cannot transform the viewport frame!");
|
||||||
int32_t scaleFactor = (aInCSSUnits ? PresContext()->AppUnitsPerCSSPixel()
|
int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
|
||||||
: PresContext()->AppUnitsPerDevPixel());
|
: PresContext()->AppUnitsPerDevPixel());
|
||||||
|
|
||||||
Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
|
Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
|
||||||
|
@ -6381,14 +6377,18 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
return Matrix4x4();
|
return Matrix4x4();
|
||||||
|
|
||||||
/* Keep iterating while the frame can't possibly be transformed. */
|
/* Keep iterating while the frame can't possibly be transformed. */
|
||||||
|
nsIFrame* current = this;
|
||||||
while (!(*aOutAncestor)->IsTransformed() &&
|
while (!(*aOutAncestor)->IsTransformed() &&
|
||||||
!nsLayoutUtils::IsPopup(*aOutAncestor) &&
|
!nsLayoutUtils::IsPopup(*aOutAncestor) &&
|
||||||
*aOutAncestor != aStopAtAncestor) {
|
*aOutAncestor != aStopAtAncestor &&
|
||||||
|
(!(aFlags & STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
|
||||||
|
(!(*aOutAncestor)->IsStackingContext() && !nsLayoutUtils::FrameHasDisplayPort(*aOutAncestor, current)))) {
|
||||||
/* If no parent, stop iterating. Otherwise, update the ancestor. */
|
/* If no parent, stop iterating. Otherwise, update the ancestor. */
|
||||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
|
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
current = *aOutAncestor;
|
||||||
*aOutAncestor = parent;
|
*aOutAncestor = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6398,7 +6398,7 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
* entire transform, so we're done.
|
* entire transform, so we're done.
|
||||||
*/
|
*/
|
||||||
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
|
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
|
||||||
int32_t scaleFactor = (aInCSSUnits ? PresContext()->AppUnitsPerCSSPixel()
|
int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
|
||||||
: PresContext()->AppUnitsPerDevPixel());
|
: PresContext()->AppUnitsPerDevPixel());
|
||||||
return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
|
return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
|
||||||
NSAppUnitsToFloatPixels(delta.y, scaleFactor),
|
NSAppUnitsToFloatPixels(delta.y, scaleFactor),
|
||||||
|
@ -10506,6 +10506,41 @@ nsIFrame::IsPseudoStackingContextFromStyle() {
|
||||||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
|
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsIFrame::IsVisuallyAtomic(EffectSet* aEffectSet,
|
||||||
|
const nsStyleDisplay* aStyleDisplay,
|
||||||
|
const nsStyleEffects* aStyleEffects) {
|
||||||
|
return HasOpacity(aEffectSet) ||
|
||||||
|
IsTransformed(aStyleDisplay) ||
|
||||||
|
// strictly speaking, 'perspective' doesn't require visual atomicity,
|
||||||
|
// but the spec says it acts like the rest of these
|
||||||
|
aStyleDisplay->mChildPerspective.GetUnit() == eStyleUnit_Coord ||
|
||||||
|
aStyleEffects->mMixBlendMode != NS_STYLE_BLEND_NORMAL ||
|
||||||
|
nsSVGIntegrationUtils::UsingEffectsForFrame(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsIFrame::IsStackingContext(const nsStyleDisplay* aStyleDisplay,
|
||||||
|
const nsStylePosition* aStylePosition,
|
||||||
|
bool aIsPositioned,
|
||||||
|
bool aIsVisuallyAtomic) {
|
||||||
|
return (aIsPositioned && (aStyleDisplay->IsPositionForcingStackingContext() ||
|
||||||
|
aStylePosition->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
|
||||||
|
(aStyleDisplay->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
|
||||||
|
aStyleDisplay->mIsolation != NS_STYLE_ISOLATION_AUTO ||
|
||||||
|
aIsVisuallyAtomic;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsIFrame::IsStackingContext()
|
||||||
|
{
|
||||||
|
const nsStyleDisplay* disp = StyleDisplay();
|
||||||
|
bool isPositioned = disp->IsAbsPosContainingBlock(this);
|
||||||
|
bool isVisuallyAtomic = IsVisuallyAtomic(EffectSet::GetEffectSet(this),
|
||||||
|
disp, StyleEffects());
|
||||||
|
return IsStackingContext(disp, StylePosition(), isPositioned, isVisuallyAtomic);
|
||||||
|
}
|
||||||
|
|
||||||
Element*
|
Element*
|
||||||
nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
|
nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
|
||||||
{
|
{
|
||||||
|
|
|
@ -556,17 +556,6 @@ FRAME_STATE_BIT(Block, 62, BULLET_FRAME_HAS_FONT_INFLATION)
|
||||||
FRAME_STATE_BIT(Block, 63, BULLET_FRAME_IMAGE_LOADING)
|
FRAME_STATE_BIT(Block, 63, BULLET_FRAME_IMAGE_LOADING)
|
||||||
|
|
||||||
|
|
||||||
// == Frame state bits that apply to scroll frames ============================
|
|
||||||
|
|
||||||
FRAME_STATE_GROUP(Scroll, nsIScrollableFrame)
|
|
||||||
|
|
||||||
// When set, the next scroll operation on the scrollframe will invalidate its
|
|
||||||
// entire contents. Useful for text-overflow.
|
|
||||||
// This bit is cleared after each time the scrollframe is scrolled. Whoever
|
|
||||||
// needs to set it should set it again on each paint.
|
|
||||||
FRAME_STATE_BIT(Scroll, 20, NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL)
|
|
||||||
|
|
||||||
|
|
||||||
// == Frame state bits that apply to image frames =============================
|
// == Frame state bits that apply to image frames =============================
|
||||||
|
|
||||||
FRAME_STATE_GROUP(Image, nsImageFrame)
|
FRAME_STATE_GROUP(Image, nsImageFrame)
|
||||||
|
|
|
@ -2421,12 +2421,6 @@ static void AdjustViews(nsIFrame* aFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
NeedToInvalidateOnScroll(nsIFrame* aFrame)
|
|
||||||
{
|
|
||||||
return (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScrollFrameHelper::IsIgnoringViewportClipping() const
|
bool ScrollFrameHelper::IsIgnoringViewportClipping() const
|
||||||
{
|
{
|
||||||
if (!mIsRoot)
|
if (!mIsRoot)
|
||||||
|
@ -2603,16 +2597,9 @@ void ScrollFrameHelper::ScrollVisual()
|
||||||
AdjustViews(mScrolledFrame);
|
AdjustViews(mScrolledFrame);
|
||||||
// We need to call this after fixing up the view positions
|
// We need to call this after fixing up the view positions
|
||||||
// to be consistent with the frame hierarchy.
|
// to be consistent with the frame hierarchy.
|
||||||
bool needToInvalidateOnScroll = NeedToInvalidateOnScroll(mOuter);
|
|
||||||
mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
|
|
||||||
if (needToInvalidateOnScroll) {
|
|
||||||
MarkNotRecentlyScrolled();
|
|
||||||
} else {
|
|
||||||
MarkRecentlyScrolled();
|
MarkRecentlyScrolled();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clamp desired scroll position aDesired and range [aDestLower, aDestUpper]
|
* Clamp desired scroll position aDesired and range [aDestLower, aDestUpper]
|
||||||
* to [aBoundLower, aBoundUpper] and then select the appunit value from among
|
* to [aBoundLower, aBoundUpper] and then select the appunit value from among
|
||||||
|
@ -3279,9 +3266,6 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||||
|
|
||||||
if (aBuilder->IsPaintingToWindow()) {
|
if (aBuilder->IsPaintingToWindow()) {
|
||||||
mScrollPosAtLastPaint = GetScrollPosition();
|
mScrollPosAtLastPaint = GetScrollPosition();
|
||||||
if (IsMaybeScrollingActive() && NeedToInvalidateOnScroll(mOuter)) {
|
|
||||||
MarkNotRecentlyScrolled();
|
|
||||||
}
|
|
||||||
if (IsMaybeScrollingActive()) {
|
if (IsMaybeScrollingActive()) {
|
||||||
if (mScrollPosForLayerPixelAlignment == nsPoint(-1,-1)) {
|
if (mScrollPosForLayerPixelAlignment == nsPoint(-1,-1)) {
|
||||||
mScrollPosForLayerPixelAlignment = mScrollPosAtLastPaint;
|
mScrollPosForLayerPixelAlignment = mScrollPosAtLastPaint;
|
||||||
|
|
|
@ -1724,6 +1724,12 @@ public:
|
||||||
return IsTransformed(StyleDisplay(), aEffectSet);
|
return IsTransformed(StyleDisplay(), aEffectSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as IsTransformed, except that it doesn't take SVG transforms
|
||||||
|
* into account.
|
||||||
|
*/
|
||||||
|
bool IsCSSTransformed(const nsStyleDisplay* aStyleDisplay, mozilla::EffectSet* aEffectSet = nullptr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if this frame has any animation of transform in effect.
|
* True if this frame has any animation of transform in effect.
|
||||||
*
|
*
|
||||||
|
@ -2789,9 +2795,13 @@ public:
|
||||||
* @return A Matrix4x4 that converts points in this frame's coordinate space
|
* @return A Matrix4x4 that converts points in this frame's coordinate space
|
||||||
* into points in aOutAncestor's coordinate space.
|
* into points in aOutAncestor's coordinate space.
|
||||||
*/
|
*/
|
||||||
|
enum {
|
||||||
|
IN_CSS_UNITS = 1 << 0,
|
||||||
|
STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT = 1 << 1
|
||||||
|
};
|
||||||
Matrix4x4 GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
Matrix4x4 GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
nsIFrame **aOutAncestor,
|
nsIFrame **aOutAncestor,
|
||||||
bool aInCSSUnits = false);
|
uint32_t aFlags = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bit-flags to pass to IsFrameOfType()
|
* Bit-flags to pass to IsFrameOfType()
|
||||||
|
@ -3450,6 +3460,27 @@ public:
|
||||||
*/
|
*/
|
||||||
bool IsPseudoStackingContextFromStyle();
|
bool IsPseudoStackingContextFromStyle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this frame has a container effect that requires
|
||||||
|
* it to paint as a visually atomic unit.
|
||||||
|
*/
|
||||||
|
bool IsVisuallyAtomic(mozilla::EffectSet* aEffectSet,
|
||||||
|
const nsStyleDisplay* aStyleDisplay,
|
||||||
|
const nsStyleEffects* aStyleEffects);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this frame is a stacking context.
|
||||||
|
*
|
||||||
|
* @param aIsPositioned The precomputed result of IsAbsPosContainingBlock
|
||||||
|
* on the StyleDisplay().
|
||||||
|
* @param aIsVisuallyAtomic The precomputed result of IsVisuallyAtomic.
|
||||||
|
*/
|
||||||
|
bool IsStackingContext(const nsStyleDisplay* aStyleDisplay,
|
||||||
|
const nsStylePosition* aStylePosition,
|
||||||
|
bool aIsPositioned,
|
||||||
|
bool aIsVisuallyAtomic);
|
||||||
|
bool IsStackingContext();
|
||||||
|
|
||||||
virtual bool HonorPrintBackgroundSettings() { return true; }
|
virtual bool HonorPrintBackgroundSettings() { return true; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1218,6 +1218,10 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
||||||
state->mCaretFrame = nullptr;
|
state->mCaretFrame = nullptr;
|
||||||
state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
|
state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
state->mAutoLayoutPhase.emplace(aReferenceFrame->PresContext(), eLayoutPhase_DisplayListBuilding);
|
||||||
|
#endif
|
||||||
|
|
||||||
state->mPresShell->UpdateCanvasBackground();
|
state->mPresShell->UpdateCanvasBackground();
|
||||||
|
|
||||||
if (mIsPaintingToWindow) {
|
if (mIsPaintingToWindow) {
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "mozilla/gfx/UserData.h"
|
#include "mozilla/gfx/UserData.h"
|
||||||
#include "mozilla/layers/LayerAttributes.h"
|
#include "mozilla/layers/LayerAttributes.h"
|
||||||
#include "nsCSSRenderingBorders.h"
|
#include "nsCSSRenderingBorders.h"
|
||||||
|
#include "nsAutoLayoutPhase.h"
|
||||||
#include "nsDisplayItemTypes.h"
|
#include "nsDisplayItemTypes.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -1474,6 +1475,9 @@ private:
|
||||||
|
|
||||||
struct PresShellState {
|
struct PresShellState {
|
||||||
nsIPresShell* mPresShell;
|
nsIPresShell* mPresShell;
|
||||||
|
#ifdef DEBUG
|
||||||
|
mozilla::Maybe<nsAutoLayoutPhase> mAutoLayoutPhase;
|
||||||
|
#endif
|
||||||
nsIFrame* mCaretFrame;
|
nsIFrame* mCaretFrame;
|
||||||
nsRect mCaretRect;
|
nsRect mCaretRect;
|
||||||
mozilla::Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
|
mozilla::Maybe<OutOfFlowDisplayData> mFixedBackgroundDisplayData;
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body style="width:100px">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="js" viewBox="0 0 200 200" style="transform: rotateX(180deg)">
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" style="fill:rgb(0,0,255)"></rect>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="transform: rotatex(45deg); transform-style: preserve-3d; width: 100px;">
|
||||||
|
<div style="transform: rotatex(45deg); transform-style: preserve-3d; width: 100px;">
|
||||||
|
<div style="transform: rotatex(45deg); transform-style: preserve-3d; width: 100px;">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="js" viewBox="0 0 200 200" style="transform: rotateX(45deg)">
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" style="fill:rgb(0,0,255)"></rect>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -677,6 +677,7 @@ public class BrowserApp extends GeckoApp
|
||||||
});
|
});
|
||||||
|
|
||||||
mProgressView = (AnimatedProgressBar) findViewById(R.id.page_progress);
|
mProgressView = (AnimatedProgressBar) findViewById(R.id.page_progress);
|
||||||
|
mDynamicToolbar.setLayerView(mLayerView);
|
||||||
mProgressView.setDynamicToolbar(mDynamicToolbar);
|
mProgressView.setDynamicToolbar(mDynamicToolbar);
|
||||||
mBrowserToolbar.setProgressBar(mProgressView);
|
mBrowserToolbar.setProgressBar(mProgressView);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@ EXPORTS += [
|
||||||
]
|
]
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'nsHtml5Atom.cpp',
|
|
||||||
'nsHtml5AtomTable.cpp',
|
'nsHtml5AtomTable.cpp',
|
||||||
'nsHtml5AttributeName.cpp',
|
'nsHtml5AttributeName.cpp',
|
||||||
'nsHtml5DependentUTF16Buffer.cpp',
|
'nsHtml5DependentUTF16Buffer.cpp',
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
/* 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 "nsHtml5Atom.h"
|
|
||||||
#include "nsAutoPtr.h"
|
|
||||||
#include "mozilla/Unused.h"
|
|
||||||
|
|
||||||
nsHtml5Atom::nsHtml5Atom(const nsAString& aString)
|
|
||||||
{
|
|
||||||
mLength = aString.Length();
|
|
||||||
SetKind(AtomKind::HTML5Atom);
|
|
||||||
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
|
||||||
if (buf) {
|
|
||||||
mString = static_cast<char16_t*>(buf->Data());
|
|
||||||
} else {
|
|
||||||
const size_t size = (mLength + 1) * sizeof(char16_t);
|
|
||||||
buf = nsStringBuffer::Alloc(size);
|
|
||||||
if (MOZ_UNLIKELY(!buf)) {
|
|
||||||
// We OOM because atom allocations should be small and it's hard to
|
|
||||||
// handle them more gracefully in a constructor.
|
|
||||||
NS_ABORT_OOM(size);
|
|
||||||
}
|
|
||||||
mString = static_cast<char16_t*>(buf->Data());
|
|
||||||
CopyUnicodeTo(aString, 0, mString, mLength);
|
|
||||||
mString[mLength] = char16_t(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
|
|
||||||
NS_ASSERTION(buf && buf->StorageSize() >= (mLength+1) * sizeof(char16_t),
|
|
||||||
"enough storage");
|
|
||||||
NS_ASSERTION(Equals(aString), "correct data");
|
|
||||||
|
|
||||||
// Take ownership of buffer
|
|
||||||
mozilla::Unused << buf.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsHtml5Atom::~nsHtml5Atom()
|
|
||||||
{
|
|
||||||
nsStringBuffer::FromData(mString)->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsHtml5Atom::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
||||||
{
|
|
||||||
NS_NOTREACHED("Attempt to call QueryInterface an nsHtml5Atom.");
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsHtml5Atom::ToUTF8String(nsACString& aReturn)
|
|
||||||
{
|
|
||||||
NS_NOTREACHED("Should not attempt to convert to an UTF-8 string.");
|
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP_(size_t)
|
|
||||||
nsHtml5Atom::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
|
||||||
{
|
|
||||||
NS_NOTREACHED("Should not call SizeOfIncludingThis.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
/* 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 nsHtml5Atom_h
|
|
||||||
#define nsHtml5Atom_h
|
|
||||||
|
|
||||||
#include "nsIAtom.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dynamic atom implementation meant for use within the nsHtml5Tokenizer and
|
|
||||||
* nsHtml5TreeBuilder owned by one nsHtml5Parser or nsHtml5StreamParser
|
|
||||||
* instance.
|
|
||||||
*
|
|
||||||
* Usage is documented in nsHtml5AtomTable and nsIAtom.
|
|
||||||
*/
|
|
||||||
class nsHtml5Atom final : public nsIAtom
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) final;
|
|
||||||
NS_DECL_NSIATOM
|
|
||||||
|
|
||||||
explicit nsHtml5Atom(const nsAString& aString);
|
|
||||||
~nsHtml5Atom();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // nsHtml5Atom_h
|
|
|
@ -3,12 +3,11 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsHtml5AtomTable.h"
|
#include "nsHtml5AtomTable.h"
|
||||||
#include "nsHtml5Atom.h"
|
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
nsHtml5AtomEntry::nsHtml5AtomEntry(KeyTypePointer aStr)
|
nsHtml5AtomEntry::nsHtml5AtomEntry(KeyTypePointer aStr)
|
||||||
: nsStringHashKey(aStr)
|
: nsStringHashKey(aStr)
|
||||||
, mAtom(new nsHtml5Atom(*aStr))
|
, mAtom(new nsAtom(nsAtom::AtomKind::HTML5Atom, *aStr, 0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +20,7 @@ nsHtml5AtomEntry::nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther)
|
||||||
|
|
||||||
nsHtml5AtomEntry::~nsHtml5AtomEntry()
|
nsHtml5AtomEntry::~nsHtml5AtomEntry()
|
||||||
{
|
{
|
||||||
|
delete mAtom;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsHtml5AtomTable::nsHtml5AtomTable()
|
nsHtml5AtomTable::nsHtml5AtomTable()
|
||||||
|
|
|
@ -7,26 +7,20 @@
|
||||||
|
|
||||||
#include "nsHashKeys.h"
|
#include "nsHashKeys.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
#include "nsAutoPtr.h"
|
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsISerialEventTarget.h"
|
#include "nsISerialEventTarget.h"
|
||||||
|
|
||||||
#define RECENTLY_USED_PARSER_ATOMS_SIZE 31
|
#define RECENTLY_USED_PARSER_ATOMS_SIZE 31
|
||||||
|
|
||||||
class nsHtml5Atom;
|
|
||||||
|
|
||||||
class nsHtml5AtomEntry : public nsStringHashKey
|
class nsHtml5AtomEntry : public nsStringHashKey
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsHtml5AtomEntry(KeyTypePointer aStr);
|
explicit nsHtml5AtomEntry(KeyTypePointer aStr);
|
||||||
nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther);
|
nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther);
|
||||||
~nsHtml5AtomEntry();
|
~nsHtml5AtomEntry();
|
||||||
inline nsHtml5Atom* GetAtom()
|
inline nsAtom* GetAtom() { return mAtom; }
|
||||||
{
|
|
||||||
return mAtom;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
nsAutoPtr<nsHtml5Atom> mAtom;
|
nsAtom* mAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "nsHtml5SpeculativeLoad.h"
|
#include "nsHtml5SpeculativeLoad.h"
|
||||||
#include "nsHtml5TreeOpExecutor.h"
|
#include "nsHtml5TreeOpExecutor.h"
|
||||||
|
#include "mozilla/Encoding.h"
|
||||||
|
|
||||||
nsHtml5SpeculativeLoad::nsHtml5SpeculativeLoad()
|
nsHtml5SpeculativeLoad::nsHtml5SpeculativeLoad()
|
||||||
:
|
:
|
||||||
|
|
|
@ -6,20 +6,8 @@
|
||||||
#ifndef nsParserCIID_h__
|
#ifndef nsParserCIID_h__
|
||||||
#define nsParserCIID_h__
|
#define nsParserCIID_h__
|
||||||
|
|
||||||
#include "nsISupports.h"
|
|
||||||
#include "nsIFactory.h"
|
|
||||||
#include "nsIComponentManager.h"
|
|
||||||
|
|
||||||
// {2ce606b0-bee6-11d1-aad9-00805f8a3e14}
|
// {2ce606b0-bee6-11d1-aad9-00805f8a3e14}
|
||||||
#define NS_PARSER_CID \
|
#define NS_PARSER_CID \
|
||||||
{ 0x2ce606b0, 0xbee6, 0x11d1, { 0xaa, 0xd9, 0x0, 0x80, 0x5f, 0x8a, 0x3e, 0x14 } }
|
{ 0x2ce606b0, 0xbee6, 0x11d1, { 0xaa, 0xd9, 0x0, 0x80, 0x5f, 0x8a, 0x3e, 0x14 } }
|
||||||
|
|
||||||
// {a6cf9107-15b3-11d2-932e-00805f8add32}
|
|
||||||
#define NS_CNAVDTD_CID \
|
|
||||||
{ 0xa6cf9107, 0x15b3, 0x11d2, { 0x93, 0x2e, 0x0, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } }
|
|
||||||
|
|
||||||
// {FFF4FBE9-528A-4b37-819D-FC18F3A401A7}
|
|
||||||
#define NS_EXPAT_DRIVER_CID \
|
|
||||||
{ 0xfff4fbe9, 0x528a, 0x4b37, { 0x81, 0x9d, 0xfc, 0x18, 0xf3, 0xa4, 0x1, 0xa7 } }
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,58 +3,27 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsIAtom.h"
|
|
||||||
#include "nsString.h"
|
|
||||||
#include "nspr.h"
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
#include "mozilla/ModuleUtils.h"
|
#include "mozilla/ModuleUtils.h"
|
||||||
#include "nsParserCIID.h"
|
|
||||||
#include "nsParser.h"
|
#include "nsParser.h"
|
||||||
#include "CNavDTD.h"
|
#include "nsParserCIID.h"
|
||||||
#include "nsHTMLTokenizer.h"
|
#include "nsHTMLTags.h"
|
||||||
//#include "nsTextTokenizer.h"
|
|
||||||
#include "nsElementTable.h"
|
|
||||||
#include "nsSAXAttributes.h"
|
|
||||||
#include "nsSAXLocator.h"
|
|
||||||
#include "nsSAXXMLReader.h"
|
#include "nsSAXXMLReader.h"
|
||||||
|
|
||||||
#if defined(DEBUG)
|
|
||||||
#include "nsExpatDriver.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(DEBUG)
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsExpatDriver)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsParser)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsParser)
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CNavDTD)
|
|
||||||
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSAXAttributes)
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSAXXMLReader)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSAXXMLReader)
|
||||||
|
|
||||||
#if defined(DEBUG)
|
|
||||||
NS_DEFINE_NAMED_CID(NS_EXPAT_DRIVER_CID);
|
|
||||||
#endif
|
|
||||||
NS_DEFINE_NAMED_CID(NS_PARSER_CID);
|
NS_DEFINE_NAMED_CID(NS_PARSER_CID);
|
||||||
NS_DEFINE_NAMED_CID(NS_CNAVDTD_CID);
|
|
||||||
NS_DEFINE_NAMED_CID(NS_SAXATTRIBUTES_CID);
|
|
||||||
NS_DEFINE_NAMED_CID(NS_SAXXMLREADER_CID);
|
NS_DEFINE_NAMED_CID(NS_SAXXMLREADER_CID);
|
||||||
|
|
||||||
static const mozilla::Module::CIDEntry kParserCIDs[] = {
|
static const mozilla::Module::CIDEntry kParserCIDs[] = {
|
||||||
#if defined(DEBUG)
|
|
||||||
{ &kNS_EXPAT_DRIVER_CID, false, nullptr, nsExpatDriverConstructor },
|
|
||||||
#endif
|
|
||||||
{ &kNS_PARSER_CID, false, nullptr, nsParserConstructor },
|
{ &kNS_PARSER_CID, false, nullptr, nsParserConstructor },
|
||||||
{ &kNS_CNAVDTD_CID, false, nullptr, CNavDTDConstructor },
|
|
||||||
{ &kNS_SAXATTRIBUTES_CID, false, nullptr, nsSAXAttributesConstructor },
|
|
||||||
{ &kNS_SAXXMLREADER_CID, false, nullptr, nsSAXXMLReaderConstructor },
|
{ &kNS_SAXXMLREADER_CID, false, nullptr, nsSAXXMLReaderConstructor },
|
||||||
{ nullptr }
|
{ nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const mozilla::Module::ContractIDEntry kParserContracts[] = {
|
static const mozilla::Module::ContractIDEntry kParserContracts[] = {
|
||||||
{ NS_SAXATTRIBUTES_CONTRACTID, &kNS_SAXATTRIBUTES_CID },
|
|
||||||
{ NS_SAXXMLREADER_CONTRACTID, &kNS_SAXXMLREADER_CID },
|
{ NS_SAXXMLREADER_CONTRACTID, &kNS_SAXXMLREADER_CID },
|
||||||
{ nullptr }
|
{ nullptr }
|
||||||
};
|
};
|
||||||
|
@ -67,9 +36,6 @@ Initialize()
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
CheckElementTable();
|
CheckElementTable();
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
nsHTMLTags::TestTagTable();
|
nsHTMLTags::TestTagTable();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,6 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
|
||||||
#define NS_SAXATTRIBUTES_CONTRACTID "@mozilla.org/saxparser/attributes;1"
|
|
||||||
#define NS_SAXATTRIBUTES_CID \
|
|
||||||
{/* {7bb40992-77eb-43db-9a4e-39d3bcc483ae}*/ \
|
|
||||||
0x7bb40992, 0x77eb, 0x43db, \
|
|
||||||
{ 0x9a, 0x4e, 0x39, 0xd3, 0xbc, 0xc3, 0x83, 0xae} }
|
|
||||||
|
|
||||||
struct SAXAttr
|
struct SAXAttr
|
||||||
{
|
{
|
||||||
nsString uri;
|
nsString uri;
|
||||||
|
|
|
@ -10,12 +10,6 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
|
|
||||||
#define NS_SAXLOCATOR_CONTRACTID "@mozilla.org/saxparser/locator;1"
|
|
||||||
#define NS_SAXLOCATOR_CID \
|
|
||||||
{/* {c1cd4045-846b-43bb-a95e-745a3d7b40e0}*/ \
|
|
||||||
0xc1cd4045, 0x846b, 0x43bb, \
|
|
||||||
{ 0xa9, 0x5e, 0x74, 0x5a, 0x3d, 0x7b, 0x40, 0xe0} }
|
|
||||||
|
|
||||||
class nsSAXLocator final : public nsISAXLocator
|
class nsSAXLocator final : public nsISAXLocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -106,7 +106,6 @@ config = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
"partials": {
|
"partials": {
|
||||||
"releases-dir": {
|
"releases-dir": {
|
||||||
"product-name": "Firefox-%(version)s-Partial-%(prev_version)s",
|
"product-name": "Firefox-%(version)s-Partial-%(prev_version)s",
|
||||||
|
|
|
@ -697,10 +697,6 @@ nsBaseWidget::SetSizeMode(nsSizeMode aMode)
|
||||||
// Get this component cursor
|
// Get this component cursor
|
||||||
//
|
//
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
nsCursor nsBaseWidget::GetCursor()
|
|
||||||
{
|
|
||||||
return mCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsBaseWidget::SetCursor(nsCursor aCursor)
|
nsBaseWidget::SetCursor(nsCursor aCursor)
|
||||||
|
|
|
@ -174,7 +174,6 @@ public:
|
||||||
return mIsFullyOccluded;
|
return mIsFullyOccluded;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual nsCursor GetCursor() override;
|
|
||||||
virtual void SetCursor(nsCursor aCursor) override;
|
virtual void SetCursor(nsCursor aCursor) override;
|
||||||
virtual nsresult SetCursor(imgIContainer* aCursor,
|
virtual nsresult SetCursor(imgIContainer* aCursor,
|
||||||
uint32_t aHotspotX, uint32_t aHotspotY) override;
|
uint32_t aHotspotX, uint32_t aHotspotY) override;
|
||||||
|
|
|
@ -960,14 +960,6 @@ class nsIWidget : public nsISupports
|
||||||
|
|
||||||
virtual void SetBackgroundColor(const nscolor &aColor) { }
|
virtual void SetBackgroundColor(const nscolor &aColor) { }
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the cursor for this widget.
|
|
||||||
*
|
|
||||||
* @return this widget's cursor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
virtual nsCursor GetCursor(void) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the cursor for this widget
|
* Set the cursor for this widget
|
||||||
*
|
*
|
||||||
|
|
|
@ -28,16 +28,16 @@
|
||||||
|
|
||||||
// There are two kinds of atoms handled by this module.
|
// There are two kinds of atoms handled by this module.
|
||||||
//
|
//
|
||||||
// - Dynamic: the Atom itself is heap allocated, as is the nsStringBuffer it
|
// - Dynamic: the atom itself is heap allocated, as is the nsStringBuffer it
|
||||||
// points to. |gAtomTable| holds weak references to dynamic Atoms. When the
|
// points to. |gAtomTable| holds weak references to dynamic atoms. When the
|
||||||
// refcount of a dynamic Atom drops to zero, we increment a static counter.
|
// refcount of a dynamic atom drops to zero, we increment a static counter.
|
||||||
// When that counter reaches a certain threshold, we iterate over the Atom
|
// When that counter reaches a certain threshold, we iterate over the atom
|
||||||
// table, removing and deleting dynamic Atoms with refcount zero. This allows
|
// table, removing and deleting dynamic atoms with refcount zero. This allows
|
||||||
// us to avoid acquiring the atom table lock during normal refcounting.
|
// us to avoid acquiring the atom table lock during normal refcounting.
|
||||||
//
|
//
|
||||||
// - Static: the Atom itself is heap allocated, but it points to a static
|
// - Static: the atom itself is heap allocated, but it points to a static
|
||||||
// nsStringBuffer. |gAtomTable| effectively owns static Atoms, because such
|
// nsStringBuffer. |gAtomTable| effectively owns static atoms, because such
|
||||||
// Atoms ignore all AddRef/Release calls, which ensures they stay alive until
|
// atoms ignore all AddRef/Release calls, which ensures they stay alive until
|
||||||
// |gAtomTable| itself is destroyed whereupon they are explicitly deleted.
|
// |gAtomTable| itself is destroyed whereupon they are explicitly deleted.
|
||||||
//
|
//
|
||||||
// Note that gAtomTable is used on multiple threads, and callers must acquire
|
// Note that gAtomTable is used on multiple threads, and callers must acquire
|
||||||
|
@ -67,6 +67,32 @@ class CheckStaticAtomSizes
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum class GCKind {
|
||||||
|
RegularOperation,
|
||||||
|
Shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class encapsulates the functions that need access to nsAtom's private
|
||||||
|
// members.
|
||||||
|
class nsAtomFriend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterStaticAtoms(const nsStaticAtom* aAtoms,
|
||||||
|
uint32_t aAtomCount);
|
||||||
|
|
||||||
|
static void AtomTableClearEntry(PLDHashTable* aTable,
|
||||||
|
PLDHashEntryHdr* aEntry);
|
||||||
|
|
||||||
|
static void GCAtomTableLocked(const MutexAutoLock& aProofOfLock,
|
||||||
|
GCKind aKind);
|
||||||
|
|
||||||
|
static already_AddRefed<nsIAtom> Atomize(const nsACString& aUTF8String);
|
||||||
|
static already_AddRefed<nsIAtom> Atomize(const nsAString& aUTF16String);
|
||||||
|
static already_AddRefed<nsIAtom> AtomizeMainThread(const nsAString& aUTF16Str);
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
// gUnusedAtomCount is incremented when an atom loses its last reference
|
// gUnusedAtomCount is incremented when an atom loses its last reference
|
||||||
// (and thus turned into unused state), and decremented when an unused
|
// (and thus turned into unused state), and decremented when an unused
|
||||||
// atom gets a reference again. The atom table relies on this value to
|
// atom gets a reference again. The atom table relies on this value to
|
||||||
|
@ -109,39 +135,13 @@ private:
|
||||||
UniquePtr<nsTArray<FakeBufferRefcountHelper>> gFakeBuffers;
|
UniquePtr<nsTArray<FakeBufferRefcountHelper>> gFakeBuffers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Atom final : public nsIAtom
|
// This constructor is for dynamic atoms and HTML5 atoms.
|
||||||
{
|
nsAtom::nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
|
||||||
public:
|
|
||||||
static already_AddRefed<Atom> CreateDynamic(const nsAString& aString,
|
|
||||||
uint32_t aHash)
|
|
||||||
{
|
|
||||||
// The refcount is appropriately initialized in the constructor.
|
|
||||||
return dont_AddRef(new Atom(aString, aHash));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Atom* CreateStatic(nsStringBuffer* aStringBuffer, uint32_t aLength,
|
|
||||||
uint32_t aHash)
|
|
||||||
{
|
|
||||||
return new Atom(aStringBuffer, aLength, aHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GCAtomTable();
|
|
||||||
|
|
||||||
enum class GCKind {
|
|
||||||
RegularOperation,
|
|
||||||
Shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void GCAtomTableLocked(const MutexAutoLock& aProofOfLock,
|
|
||||||
GCKind aKind);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// This constructor is for dynamic Atoms.
|
|
||||||
Atom(const nsAString& aString, uint32_t aHash)
|
|
||||||
: mRefCnt(1)
|
: mRefCnt(1)
|
||||||
{
|
{
|
||||||
mLength = aString.Length();
|
mLength = aString.Length();
|
||||||
SetKind(AtomKind::DynamicAtom);
|
SetKind(aKind);
|
||||||
|
MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
|
||||||
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
mString = static_cast<char16_t*>(buf->Data());
|
mString = static_cast<char16_t*>(buf->Data());
|
||||||
|
@ -159,7 +159,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
mHash = aHash;
|
mHash = aHash;
|
||||||
MOZ_ASSERT(mHash == HashString(mString, mLength));
|
MOZ_ASSERT_IF(IsDynamicAtom(), mHash == HashString(mString, mLength));
|
||||||
|
|
||||||
NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
|
NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
|
||||||
NS_ASSERTION(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
|
NS_ASSERTION(buf && buf->StorageSize() >= (mLength + 1) * sizeof(char16_t),
|
||||||
|
@ -170,8 +170,8 @@ private:
|
||||||
mozilla::Unused << buf.forget();
|
mozilla::Unused << buf.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This constructor is for static Atoms.
|
// This constructor is for static atoms.
|
||||||
Atom(nsStringBuffer* aStringBuffer, uint32_t aLength, uint32_t aHash)
|
nsAtom::nsAtom(nsStringBuffer* aStringBuffer, uint32_t aLength, uint32_t aHash)
|
||||||
{
|
{
|
||||||
mLength = aLength;
|
mLength = aLength;
|
||||||
SetKind(AtomKind::StaticAtom);
|
SetKind(AtomKind::StaticAtom);
|
||||||
|
@ -198,42 +198,31 @@ private:
|
||||||
"correct storage");
|
"correct storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
// We don't need a virtual destructor because we always delete via an nsAtom*
|
||||||
// We don't need a virtual destructor because we always delete via an Atom*
|
// pointer (in AtomTableClearEntry() for static atoms, and in
|
||||||
// pointer (in AtomTableClearEntry() for static Atoms, and in
|
// GCAtomTableLocked() for dynamic atoms), not an nsIAtom* pointer.
|
||||||
// GCAtomTableLocked() for dynamic Atoms), not an nsIAtom* pointer.
|
nsAtom::~nsAtom()
|
||||||
~Atom() {
|
{
|
||||||
if (IsDynamicAtom()) {
|
if (!IsStaticAtom()) {
|
||||||
|
MOZ_ASSERT(IsDynamicAtom() || IsHTML5Atom());
|
||||||
nsStringBuffer::FromData(mString)->Release();
|
nsStringBuffer::FromData(mString)->Release();
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(IsStaticAtom());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DECL_NSIATOM
|
NS_IMPL_QUERY_INTERFACE(nsAtom, nsIAtom);
|
||||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) final;
|
|
||||||
typedef mozilla::TrueType HasThreadSafeRefCnt;
|
|
||||||
|
|
||||||
MozExternalRefCountType DynamicAddRef();
|
|
||||||
MozExternalRefCountType DynamicRelease();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ThreadSafeAutoRefCnt mRefCnt;
|
|
||||||
NS_DECL_OWNINGTHREAD
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_IMPL_QUERY_INTERFACE(Atom, nsIAtom);
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
Atom::ToUTF8String(nsACString& aBuf)
|
nsAtom::ToUTF8String(nsACString& aBuf)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(!IsHTML5Atom(), "Called ToUTF8String() on an HTML5 atom");
|
||||||
CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
|
CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(size_t)
|
NS_IMETHODIMP_(size_t)
|
||||||
Atom::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
nsAtom::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(!IsHTML5Atom(), "Called SizeOfIncludingThis() on an HTML5 atom");
|
||||||
size_t n = aMallocSizeOf(this);
|
size_t n = aMallocSizeOf(this);
|
||||||
// String buffers pointed to by static atoms are in static memory, and so
|
// String buffers pointed to by static atoms are in static memory, and so
|
||||||
// are not measured here.
|
// are not measured here.
|
||||||
|
@ -251,23 +240,23 @@ Atom::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||||
nsIAtom::AddRef()
|
nsIAtom::AddRef()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to AddRef an nsHtml5Atom");
|
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to AddRef an HTML5 atom");
|
||||||
if (!IsDynamicAtom()) {
|
if (!IsDynamicAtom()) {
|
||||||
MOZ_ASSERT(IsStaticAtom());
|
MOZ_ASSERT(IsStaticAtom());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
return static_cast<Atom*>(this)->DynamicAddRef();
|
return static_cast<nsAtom*>(this)->DynamicAddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP_(MozExternalRefCountType)
|
NS_IMETHODIMP_(MozExternalRefCountType)
|
||||||
nsIAtom::Release()
|
nsIAtom::Release()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to Release an nsHtml5Atom");
|
MOZ_ASSERT(!IsHTML5Atom(), "Attempt to Release an HTML5 atom");
|
||||||
if (!IsDynamicAtom()) {
|
if (!IsDynamicAtom()) {
|
||||||
MOZ_ASSERT(IsStaticAtom());
|
MOZ_ASSERT(IsStaticAtom());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return static_cast<Atom*>(this)->DynamicRelease();
|
return static_cast<nsAtom*>(this)->DynamicRelease();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -334,10 +323,10 @@ struct AtomTableKey
|
||||||
|
|
||||||
struct AtomTableEntry : public PLDHashEntryHdr
|
struct AtomTableEntry : public PLDHashEntryHdr
|
||||||
{
|
{
|
||||||
// These references are either to dynamic Atoms, in which case they are
|
// These references are either to dynamic atoms, in which case they are
|
||||||
// non-owning, or they are to static Atoms, which aren't really refcounted.
|
// non-owning, or they are to static atoms, which aren't really refcounted.
|
||||||
// See the comment at the top of this file for more details.
|
// See the comment at the top of this file for more details.
|
||||||
Atom* MOZ_NON_OWNING_REF mAtom;
|
nsAtom* MOZ_NON_OWNING_REF mAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PLDHashNumber
|
static PLDHashNumber
|
||||||
|
@ -363,14 +352,14 @@ AtomTableMatchKey(const PLDHashEntryHdr* aEntry, const void* aKey)
|
||||||
return he->mAtom->Equals(k->mUTF16String, k->mLength);
|
return he->mAtom->Equals(k->mUTF16String, k->mLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
AtomTableClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
nsAtomFriend::AtomTableClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||||
{
|
{
|
||||||
auto entry = static_cast<AtomTableEntry*>(aEntry);
|
auto entry = static_cast<AtomTableEntry*>(aEntry);
|
||||||
Atom* atom = entry->mAtom;
|
nsAtom* atom = entry->mAtom;
|
||||||
if (atom->IsStaticAtom()) {
|
if (atom->IsStaticAtom()) {
|
||||||
// This case -- when the entry being cleared holds a static Atom -- only
|
// This case -- when the entry being cleared holds a static atom -- only
|
||||||
// occurs when gAtomTable is destroyed, whereupon all static Atoms within it
|
// occurs when gAtomTable is destroyed, whereupon all static atoms within it
|
||||||
// must be explicitly deleted.
|
// must be explicitly deleted.
|
||||||
delete atom;
|
delete atom;
|
||||||
}
|
}
|
||||||
|
@ -386,27 +375,18 @@ static const PLDHashTableOps AtomTableOps = {
|
||||||
AtomTableGetHash,
|
AtomTableGetHash,
|
||||||
AtomTableMatchKey,
|
AtomTableMatchKey,
|
||||||
PLDHashTable::MoveEntryStub,
|
PLDHashTable::MoveEntryStub,
|
||||||
AtomTableClearEntry,
|
nsAtomFriend::AtomTableClearEntry,
|
||||||
AtomTableInitEntry
|
AtomTableInitEntry
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
#define RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE 31
|
#define RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE 31
|
||||||
static Atom*
|
static nsAtom*
|
||||||
sRecentlyUsedMainThreadAtoms[RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE] = {};
|
sRecentlyUsedMainThreadAtoms[RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE] = {};
|
||||||
|
|
||||||
void
|
void
|
||||||
Atom::GCAtomTable()
|
nsAtomFriend::GCAtomTableLocked(const MutexAutoLock& aProofOfLock, GCKind aKind)
|
||||||
{
|
|
||||||
if (NS_IsMainThread()) {
|
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
|
||||||
GCAtomTableLocked(lock, GCKind::RegularOperation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Atom::GCAtomTableLocked(const MutexAutoLock& aProofOfLock, GCKind aKind)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
for (uint32_t i = 0; i < RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE; ++i) {
|
for (uint32_t i = 0; i < RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE; ++i) {
|
||||||
|
@ -422,7 +402,7 @@ Atom::GCAtomTableLocked(const MutexAutoLock& aProofOfLock, GCKind aKind)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom* atom = entry->mAtom;
|
nsAtom* atom = entry->mAtom;
|
||||||
if (atom->mRefCnt == 0) {
|
if (atom->mRefCnt == 0) {
|
||||||
i.Remove();
|
i.Remove();
|
||||||
delete atom;
|
delete atom;
|
||||||
|
@ -473,8 +453,17 @@ Atom::GCAtomTableLocked(const MutexAutoLock& aProofOfLock, GCKind aKind)
|
||||||
gUnusedAtomCount -= removedCount;
|
gUnusedAtomCount -= removedCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GCAtomTable()
|
||||||
|
{
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
|
nsAtomFriend::GCAtomTableLocked(lock, GCKind::RegularOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MozExternalRefCountType
|
MozExternalRefCountType
|
||||||
Atom::DynamicAddRef()
|
nsAtom::DynamicAddRef()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsDynamicAtom());
|
MOZ_ASSERT(IsDynamicAtom());
|
||||||
nsrefcnt count = ++mRefCnt;
|
nsrefcnt count = ++mRefCnt;
|
||||||
|
@ -493,7 +482,7 @@ static const int32_t kAtomGCThreshold = 10000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MozExternalRefCountType
|
MozExternalRefCountType
|
||||||
Atom::DynamicRelease()
|
nsAtom::DynamicRelease()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsDynamicAtom());
|
MOZ_ASSERT(IsDynamicAtom());
|
||||||
MOZ_ASSERT(mRefCnt > 0);
|
MOZ_ASSERT(mRefCnt > 0);
|
||||||
|
@ -536,9 +525,9 @@ public:
|
||||||
|
|
||||||
enum { ALLOW_MEMMOVE = true };
|
enum { ALLOW_MEMMOVE = true };
|
||||||
|
|
||||||
// Static Atoms aren't really refcounted. Because these entries live in a
|
// Static atoms aren't really refcounted. Because these entries live in a
|
||||||
// global hashtable, this reference is essentially owning.
|
// global hashtable, this reference is essentially owning.
|
||||||
Atom* MOZ_OWNING_REF mAtom;
|
nsAtom* MOZ_OWNING_REF mAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -603,7 +592,7 @@ NS_ShutdownAtomTable()
|
||||||
// builds.
|
// builds.
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
Atom::GCAtomTableLocked(lock, Atom::GCKind::Shutdown);
|
nsAtomFriend::GCAtomTableLocked(lock, GCKind::Shutdown);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -650,7 +639,8 @@ GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t* aHashOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
nsAtomFriend::RegisterStaticAtoms(const nsStaticAtom* aAtoms,
|
||||||
|
uint32_t aAtomCount)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
|
|
||||||
|
@ -674,7 +664,7 @@ RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
||||||
GetAtomHashEntry(static_cast<char16_t*>(stringBuffer->Data()),
|
GetAtomHashEntry(static_cast<char16_t*>(stringBuffer->Data()),
|
||||||
stringLen, &hash);
|
stringLen, &hash);
|
||||||
|
|
||||||
Atom* atom = he->mAtom;
|
nsAtom* atom = he->mAtom;
|
||||||
if (atom) {
|
if (atom) {
|
||||||
// Disallow creating a dynamic atom, and then later, while the
|
// Disallow creating a dynamic atom, and then later, while the
|
||||||
// dynamic atom is still alive, registering that same atom as a
|
// dynamic atom is still alive, registering that same atom as a
|
||||||
|
@ -687,7 +677,7 @@ RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
||||||
"Static atom registration for %s should be pushed back", name.get());
|
"Static atom registration for %s should be pushed back", name.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
atom = Atom::CreateStatic(stringBuffer, stringLen, hash);
|
atom = new nsAtom(stringBuffer, stringLen, hash);
|
||||||
he->mAtom = atom;
|
he->mAtom = atom;
|
||||||
}
|
}
|
||||||
*atomp = atom;
|
*atomp = atom;
|
||||||
|
@ -701,14 +691,20 @@ RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIAtom>
|
void
|
||||||
NS_Atomize(const char* aUTF8String)
|
RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
|
||||||
{
|
{
|
||||||
return NS_Atomize(nsDependentCString(aUTF8String));
|
nsAtomFriend::RegisterStaticAtoms(aAtoms, aAtomCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIAtom>
|
already_AddRefed<nsIAtom>
|
||||||
NS_Atomize(const nsACString& aUTF8String)
|
NS_Atomize(const char* aUTF8String)
|
||||||
|
{
|
||||||
|
return nsAtomFriend::Atomize(nsDependentCString(aUTF8String));
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIAtom>
|
||||||
|
nsAtomFriend::Atomize(const nsACString& aUTF8String)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
@ -727,7 +723,8 @@ NS_Atomize(const nsACString& aUTF8String)
|
||||||
// Actually, now there is, sort of: ForgetSharedBuffer.
|
// Actually, now there is, sort of: ForgetSharedBuffer.
|
||||||
nsString str;
|
nsString str;
|
||||||
CopyUTF8toUTF16(aUTF8String, str);
|
CopyUTF8toUTF16(aUTF8String, str);
|
||||||
RefPtr<Atom> atom = Atom::CreateDynamic(str, hash);
|
RefPtr<nsAtom> atom =
|
||||||
|
dont_AddRef(new nsAtom(nsAtom::AtomKind::DynamicAtom, str, hash));
|
||||||
|
|
||||||
he->mAtom = atom;
|
he->mAtom = atom;
|
||||||
|
|
||||||
|
@ -735,13 +732,19 @@ NS_Atomize(const nsACString& aUTF8String)
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIAtom>
|
already_AddRefed<nsIAtom>
|
||||||
NS_Atomize(const char16_t* aUTF16String)
|
NS_Atomize(const nsACString& aUTF8String)
|
||||||
{
|
{
|
||||||
return NS_Atomize(nsDependentString(aUTF16String));
|
return nsAtomFriend::Atomize(aUTF8String);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIAtom>
|
already_AddRefed<nsIAtom>
|
||||||
NS_Atomize(const nsAString& aUTF16String)
|
NS_Atomize(const char16_t* aUTF16String)
|
||||||
|
{
|
||||||
|
return nsAtomFriend::Atomize(nsDependentString(aUTF16String));
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIAtom>
|
||||||
|
nsAtomFriend::Atomize(const nsAString& aUTF16String)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
@ -755,21 +758,28 @@ NS_Atomize(const nsAString& aUTF16String)
|
||||||
return atom.forget();
|
return atom.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<Atom> atom = Atom::CreateDynamic(aUTF16String, hash);
|
RefPtr<nsAtom> atom =
|
||||||
|
dont_AddRef(new nsAtom(nsAtom::AtomKind::DynamicAtom, aUTF16String, hash));
|
||||||
he->mAtom = atom;
|
he->mAtom = atom;
|
||||||
|
|
||||||
return atom.forget();
|
return atom.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIAtom>
|
already_AddRefed<nsIAtom>
|
||||||
NS_AtomizeMainThread(const nsAString& aUTF16String)
|
NS_Atomize(const nsAString& aUTF16String)
|
||||||
|
{
|
||||||
|
return nsAtomFriend::Atomize(aUTF16String);
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIAtom>
|
||||||
|
nsAtomFriend::AtomizeMainThread(const nsAString& aUTF16String)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
nsCOMPtr<nsIAtom> retVal;
|
nsCOMPtr<nsIAtom> retVal;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
AtomTableKey key(aUTF16String.Data(), aUTF16String.Length(), &hash);
|
AtomTableKey key(aUTF16String.Data(), aUTF16String.Length(), &hash);
|
||||||
uint32_t index = hash % RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE;
|
uint32_t index = hash % RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE;
|
||||||
Atom* atom = sRecentlyUsedMainThreadAtoms[index];
|
nsAtom* atom = sRecentlyUsedMainThreadAtoms[index];
|
||||||
if (atom) {
|
if (atom) {
|
||||||
uint32_t length = atom->GetLength();
|
uint32_t length = atom->GetLength();
|
||||||
if (length == key.mLength &&
|
if (length == key.mLength &&
|
||||||
|
@ -786,7 +796,8 @@ NS_AtomizeMainThread(const nsAString& aUTF16String)
|
||||||
if (he->mAtom) {
|
if (he->mAtom) {
|
||||||
retVal = he->mAtom;
|
retVal = he->mAtom;
|
||||||
} else {
|
} else {
|
||||||
RefPtr<Atom> newAtom = Atom::CreateDynamic(aUTF16String, hash);
|
RefPtr<nsAtom> newAtom = dont_AddRef(
|
||||||
|
new nsAtom(nsAtom::AtomKind::DynamicAtom, aUTF16String, hash));
|
||||||
he->mAtom = newAtom;
|
he->mAtom = newAtom;
|
||||||
retVal = newAtom.forget();
|
retVal = newAtom.forget();
|
||||||
}
|
}
|
||||||
|
@ -795,10 +806,16 @@ NS_AtomizeMainThread(const nsAString& aUTF16String)
|
||||||
return retVal.forget();
|
return retVal.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIAtom>
|
||||||
|
NS_AtomizeMainThread(const nsAString& aUTF16String)
|
||||||
|
{
|
||||||
|
return nsAtomFriend::AtomizeMainThread(aUTF16String);
|
||||||
|
}
|
||||||
|
|
||||||
nsrefcnt
|
nsrefcnt
|
||||||
NS_GetNumberOfAtoms(void)
|
NS_GetNumberOfAtoms(void)
|
||||||
{
|
{
|
||||||
Atom::GCAtomTable(); // Trigger a GC so that we return a deterministic result.
|
GCAtomTable(); // Trigger a GC so we return a deterministic result.
|
||||||
MutexAutoLock lock(*gAtomTableLock);
|
MutexAutoLock lock(*gAtomTableLock);
|
||||||
return gAtomTable->EntryCount();
|
return gAtomTable->EntryCount();
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,11 @@ public:
|
||||||
|
|
||||||
// A hashcode that is better distributed than the actual atom pointer, for
|
// A hashcode that is better distributed than the actual atom pointer, for
|
||||||
// use in situations that need a well-distributed hashcode.
|
// use in situations that need a well-distributed hashcode.
|
||||||
uint32_t hash() const { return mHash; }
|
uint32_t hash() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!IsHTML5Atom());
|
||||||
|
return mHash;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t mLength: 30;
|
uint32_t mLength: 30;
|
||||||
|
@ -97,6 +101,30 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIAtom, NS_IATOM_IID)
|
||||||
NS_IMETHOD ToUTF8String(nsACString& _retval) override; \
|
NS_IMETHOD ToUTF8String(nsACString& _retval) override; \
|
||||||
NS_IMETHOD_(size_t) SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) override;
|
NS_IMETHOD_(size_t) SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) override;
|
||||||
|
|
||||||
|
class nsAtom final : public nsIAtom
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_NSIATOM
|
||||||
|
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) final;
|
||||||
|
typedef mozilla::TrueType HasThreadSafeRefCnt;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class nsIAtom;
|
||||||
|
friend class nsAtomFriend;
|
||||||
|
friend class nsHtml5AtomEntry;
|
||||||
|
|
||||||
|
// Construction and destruction is done entirely by |friend|s.
|
||||||
|
nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
|
||||||
|
nsAtom(nsStringBuffer* aStringBuffer, uint32_t aLength, uint32_t aHash);
|
||||||
|
~nsAtom();
|
||||||
|
|
||||||
|
MozExternalRefCountType DynamicAddRef();
|
||||||
|
MozExternalRefCountType DynamicRelease();
|
||||||
|
|
||||||
|
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||||
|
NS_DECL_OWNINGTHREAD
|
||||||
|
};
|
||||||
|
|
||||||
// The four forms of NS_Atomize (for use with |nsCOMPtr<nsIAtom>|) return the
|
// The four forms of NS_Atomize (for use with |nsCOMPtr<nsIAtom>|) return the
|
||||||
// atom for the string given. At any given time there will always be one atom
|
// atom for the string given. At any given time there will always be one atom
|
||||||
// representing a given string. Atoms are intended to make string comparison
|
// representing a given string. Atoms are intended to make string comparison
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub trait NsresultExt {
|
||||||
|
|
||||||
/// Get a printable name for the nsresult error code. This function returns
|
/// Get a printable name for the nsresult error code. This function returns
|
||||||
/// a nsCString<'static>, which implements `Display`.
|
/// a nsCString<'static>, which implements `Display`.
|
||||||
fn error_name(self) -> nsCString<'static>;
|
fn error_name(self) -> nsCString;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NsresultExt for nsresult {
|
impl NsresultExt for nsresult {
|
||||||
|
@ -42,7 +42,7 @@ impl NsresultExt for nsresult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_name(self) -> nsCString<'static> {
|
fn error_name(self) -> nsCString {
|
||||||
let mut cstr = nsCString::new();
|
let mut cstr = nsCString::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_GetErrorName(self, &mut *cstr);
|
Gecko_GetErrorName(self, &mut *cstr);
|
||||||
|
|
|
@ -5,12 +5,18 @@
|
||||||
//! Use `&{mut,} nsA[C]String` for functions in rust which wish to take or
|
//! Use `&{mut,} nsA[C]String` for functions in rust which wish to take or
|
||||||
//! mutate XPCOM strings. The other string types `Deref` to this type.
|
//! mutate XPCOM strings. The other string types `Deref` to this type.
|
||||||
//!
|
//!
|
||||||
//! Use `ns[C]String<'a>` (`ns[C]String` in C++) for string struct members, and
|
//! Use `ns[C]String` (`ns[C]String` in C++) for string struct members, and as
|
||||||
//! as an intermediate between rust string data structures (such as `String`,
|
//! an intermediate between rust string data structures (such as `String` or
|
||||||
//! `Vec<u16>`, `&str`, and `&[u16]`) and `&{mut,} nsA[C]String` (using
|
//! `Vec<u16>`) and `&{mut,} nsA[C]String` (using `ns[C]String::from(value)`).
|
||||||
//! `ns[C]String::from(value)`). These conversions, when possible, will not
|
//! These conversions will attempt to re-use the passed-in buffer, appending a
|
||||||
//! perform any allocations. When using this type in structs shared with C++,
|
//! null.
|
||||||
//! the correct lifetime argument is usually `'static`.
|
//!
|
||||||
|
//! Use `ns[C]Str` (`nsDependent[C]String` in C++) as an intermediate between
|
||||||
|
//! borrowed rust data structures (such as `&str` and `&[u16]`) and `&{mut,}
|
||||||
|
//! nsA[C]String` (using `ns[C]Str::from(value)`). These conversions should not
|
||||||
|
//! perform any allocations. This type is not safe to share with `C++` as a
|
||||||
|
//! struct field, but passing the borrowed `&{mut,} nsA[C]String` over FFI is
|
||||||
|
//! safe.
|
||||||
//!
|
//!
|
||||||
//! Use `nsFixed[C]String` or `ns_auto_[c]string!` for dynamic stack allocated
|
//! Use `nsFixed[C]String` or `ns_auto_[c]string!` for dynamic stack allocated
|
||||||
//! strings which are expected to hold short string values.
|
//! strings which are expected to hold short string values.
|
||||||
|
@ -48,7 +54,7 @@
|
||||||
//! with the methods `.append`, `.append_utf{8,16}`, and with the `write!`
|
//! with the methods `.append`, `.append_utf{8,16}`, and with the `write!`
|
||||||
//! macro, and can be assigned to with `.assign`.
|
//! macro, and can be assigned to with `.assign`.
|
||||||
//!
|
//!
|
||||||
//! ## `ns[C]String<'a>`
|
//! ## `ns[C]Str<'a>`
|
||||||
//!
|
//!
|
||||||
//! This type is an maybe-owned string type. It acts similarially to a
|
//! This type is an maybe-owned string type. It acts similarially to a
|
||||||
//! `Cow<[{u8,u16}]>`. This type provides `Deref` and `DerefMut` implementations
|
//! `Cow<[{u8,u16}]>`. This type provides `Deref` and `DerefMut` implementations
|
||||||
|
@ -57,20 +63,36 @@
|
||||||
//! storage. When modified this type may re-allocate in order to ensure that it
|
//! storage. When modified this type may re-allocate in order to ensure that it
|
||||||
//! does not mutate its backing storage.
|
//! does not mutate its backing storage.
|
||||||
//!
|
//!
|
||||||
//! `ns[C]String`s can be constructed either with `ns[C]String::new()`, which
|
//! `ns[C]Str`s can be constructed either with `ns[C]Str::new()`, which creates
|
||||||
//! creates an empty `ns[C]String<'static>`, or through one of the provided
|
//! an empty `ns[C]Str<'static>`, or through one of the provided `From`
|
||||||
//! `From` implementations. Both string types may be constructed `From<&'a
|
//! implementations. Only `nsCStr` can be constructed `From<'a str>`, as
|
||||||
//! str>`, with `nsCString` having a `'a` lifetime, as the storage is shared
|
//! constructing a `nsStr` would require transcoding. Use `ns[C]String` instead.
|
||||||
//! with the `str`, while `nsString` has a `'static` lifetime, as its storage
|
|
||||||
//! has to be transcoded.
|
|
||||||
//!
|
//!
|
||||||
//! When passing this type by reference, prefer passing a `&nsA[C]String` or
|
//! When passing this type by reference, prefer passing a `&nsA[C]String` or
|
||||||
//! `&mut nsA[C]String`. to passing this type.
|
//! `&mut nsA[C]String`. to passing this type.
|
||||||
//!
|
//!
|
||||||
//! When passing this type across the language boundary, pass it as `*const
|
//! When passing this type across the language boundary, pass it as `*const
|
||||||
//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
|
//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
|
||||||
//! mutable reference. This struct may also be included in `#[repr(C)]`
|
//! mutable reference.
|
||||||
//! structs shared with C++.
|
//!
|
||||||
|
//! ## `ns[C]String`
|
||||||
|
//!
|
||||||
|
//! This type is an owned, null-terminated string type. This type provides
|
||||||
|
//! `Deref` and `DerefMut` implementations to `nsA[C]String`, which provides the
|
||||||
|
//! methods for manipulating this type.
|
||||||
|
//!
|
||||||
|
//! `ns[C]String`s can be constructed either with `ns[C]String::new()`, which
|
||||||
|
//! creates an empty `ns[C]String`, or through one of the provided `From`
|
||||||
|
//! implementations, which will try to avoid reallocating when possible,
|
||||||
|
//! although a terminating `null` will be added.
|
||||||
|
//!
|
||||||
|
//! When passing this type by reference, prefer passing a `&nsA[C]String` or
|
||||||
|
//! `&mut nsA[C]String`. to passing this type.
|
||||||
|
//!
|
||||||
|
//! When passing this type across the language boundary, pass it as `*const
|
||||||
|
//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
|
||||||
|
//! mutable reference. This struct may also be included in `#[repr(C)]` structs
|
||||||
|
//! shared with C++.
|
||||||
//!
|
//!
|
||||||
//! ## `nsFixed[C]String<'a>`
|
//! ## `nsFixed[C]String<'a>`
|
||||||
//!
|
//!
|
||||||
|
@ -105,7 +127,7 @@
|
||||||
//! ## `ns[C]StringRepr`
|
//! ## `ns[C]StringRepr`
|
||||||
//!
|
//!
|
||||||
//! This crate also provides the type `ns[C]StringRepr` which acts conceptually
|
//! This crate also provides the type `ns[C]StringRepr` which acts conceptually
|
||||||
//! similar to an `ns[C]String<'static>`, however, it does not have a `Drop`
|
//! similar to an `ns[C]String`, however, it does not have a `Drop`
|
||||||
//! implementation.
|
//! implementation.
|
||||||
//!
|
//!
|
||||||
//! If this type is dropped in rust, it will not free its backing storage. This
|
//! If this type is dropped in rust, it will not free its backing storage. This
|
||||||
|
@ -122,7 +144,6 @@ use std::ops::{Deref, DerefMut};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::borrow;
|
use std::borrow;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::ptr;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -175,6 +196,7 @@ macro_rules! define_string_types {
|
||||||
|
|
||||||
AString = $AString: ident;
|
AString = $AString: ident;
|
||||||
String = $String: ident;
|
String = $String: ident;
|
||||||
|
Str = $Str: ident;
|
||||||
FixedString = $FixedString: ident;
|
FixedString = $FixedString: ident;
|
||||||
|
|
||||||
StringLike = $StringLike: ident;
|
StringLike = $StringLike: ident;
|
||||||
|
@ -207,6 +229,18 @@ macro_rules! define_string_types {
|
||||||
classflags: ClassFlags,
|
classflags: ClassFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl $StringRepr {
|
||||||
|
fn new(classflags: ClassFlags) -> $StringRepr {
|
||||||
|
static NUL: $char_t = 0;
|
||||||
|
$StringRepr {
|
||||||
|
data: &NUL,
|
||||||
|
length: 0,
|
||||||
|
dataflags: data_flags::TERMINATED | data_flags::LITERAL,
|
||||||
|
classflags: classflags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for $StringRepr {
|
impl Deref for $StringRepr {
|
||||||
type Target = $AString;
|
type Target = $AString;
|
||||||
fn deref(&self) -> &$AString {
|
fn deref(&self) -> &$AString {
|
||||||
|
@ -385,8 +419,14 @@ macro_rules! define_string_types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> cmp::PartialEq<$String<'a>> for $AString {
|
impl cmp::PartialEq<$String> for $AString {
|
||||||
fn eq(&self, other: &$String<'a>) -> bool {
|
fn eq(&self, other: &$String) -> bool {
|
||||||
|
self.eq(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> cmp::PartialEq<$Str<'a>> for $AString {
|
||||||
|
fn eq(&self, other: &$Str<'a>) -> bool {
|
||||||
self.eq(&**other)
|
self.eq(&**other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,26 +438,21 @@ macro_rules! define_string_types {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct $String<'a> {
|
pub struct $Str<'a> {
|
||||||
hdr: $StringRepr,
|
hdr: $StringRepr,
|
||||||
_marker: PhantomData<&'a [$char_t]>,
|
_marker: PhantomData<&'a [$char_t]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $String<'static> {
|
impl $Str<'static> {
|
||||||
pub fn new() -> $String<'static> {
|
pub fn new() -> $Str<'static> {
|
||||||
$String {
|
$Str {
|
||||||
hdr: $StringRepr {
|
hdr: $StringRepr::new(ClassFlags::empty()),
|
||||||
data: ptr::null(),
|
|
||||||
length: 0,
|
|
||||||
dataflags: DataFlags::empty(),
|
|
||||||
classflags: class_flags::NULL_TERMINATED,
|
|
||||||
},
|
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for $String<'a> {
|
impl<'a> Drop for $Str<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
$drop(&mut **self);
|
$drop(&mut **self);
|
||||||
|
@ -425,65 +460,184 @@ macro_rules! define_string_types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for $String<'a> {
|
impl<'a> Deref for $Str<'a> {
|
||||||
type Target = $AString;
|
type Target = $AString;
|
||||||
fn deref(&self) -> &$AString {
|
fn deref(&self) -> &$AString {
|
||||||
&self.hdr
|
&self.hdr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DerefMut for $String<'a> {
|
impl<'a> DerefMut for $Str<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut $AString {
|
fn deref_mut(&mut self) -> &mut $AString {
|
||||||
&mut self.hdr
|
&mut self.hdr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AsRef<[$char_t]> for $String<'a> {
|
impl<'a> AsRef<[$char_t]> for $Str<'a> {
|
||||||
fn as_ref(&self) -> &[$char_t] {
|
fn as_ref(&self) -> &[$char_t] {
|
||||||
&self
|
&self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a String> for $String<'a> {
|
impl<'a> From<&'a [$char_t]> for $Str<'a> {
|
||||||
fn from(s: &'a String) -> $String<'a> {
|
fn from(s: &'a [$char_t]) -> $Str<'a> {
|
||||||
$String::from(&s[..])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Vec<$char_t>> for $String<'a> {
|
|
||||||
fn from(s: &'a Vec<$char_t>) -> $String<'a> {
|
|
||||||
$String::from(&s[..])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a [$char_t]> for $String<'a> {
|
|
||||||
fn from(s: &'a [$char_t]) -> $String<'a> {
|
|
||||||
assert!(s.len() < (u32::MAX as usize));
|
assert!(s.len() < (u32::MAX as usize));
|
||||||
$String {
|
if s.is_empty() {
|
||||||
|
return $Str::new();
|
||||||
|
}
|
||||||
|
$Str {
|
||||||
hdr: $StringRepr {
|
hdr: $StringRepr {
|
||||||
data: if s.is_empty() { ptr::null() } else { s.as_ptr() },
|
data: s.as_ptr(),
|
||||||
length: s.len() as u32,
|
length: s.len() as u32,
|
||||||
dataflags: DataFlags::empty(),
|
dataflags: DataFlags::empty(),
|
||||||
classflags: class_flags::NULL_TERMINATED,
|
classflags: ClassFlags::empty(),
|
||||||
},
|
},
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<[$char_t]>> for $String<'static> {
|
impl<'a> From<&'a Vec<$char_t>> for $Str<'a> {
|
||||||
fn from(s: Box<[$char_t]>) -> $String<'static> {
|
fn from(s: &'a Vec<$char_t>) -> $Str<'a> {
|
||||||
|
$Str::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a $AString> for $Str<'a> {
|
||||||
|
fn from(s: &'a $AString) -> $Str<'a> {
|
||||||
|
$Str::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Write for $Str<'a> {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
|
$AString::write_str(self, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for $Str<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
<$AString as fmt::Display>::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for $Str<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
<$AString as fmt::Debug>::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> cmp::PartialEq for $Str<'a> {
|
||||||
|
fn eq(&self, other: &$Str<'a>) -> bool {
|
||||||
|
$AString::eq(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> cmp::PartialEq<[$char_t]> for $Str<'a> {
|
||||||
|
fn eq(&self, other: &[$char_t]) -> bool {
|
||||||
|
$AString::eq(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $Str<'a> {
|
||||||
|
fn eq(&self, other: &&'b [$char_t]) -> bool {
|
||||||
|
$AString::eq(self, *other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> cmp::PartialEq<str> for $Str<'a> {
|
||||||
|
fn eq(&self, other: &str) -> bool {
|
||||||
|
$AString::eq(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> cmp::PartialEq<&'b str> for $Str<'a> {
|
||||||
|
fn eq(&self, other: &&'b str) -> bool {
|
||||||
|
$AString::eq(self, *other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct $String {
|
||||||
|
hdr: $StringRepr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $String {
|
||||||
|
pub fn new() -> $String {
|
||||||
|
$String {
|
||||||
|
hdr: $StringRepr::new(class_flags::NULL_TERMINATED),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for $String {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
$drop(&mut **self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for $String {
|
||||||
|
type Target = $AString;
|
||||||
|
fn deref(&self) -> &$AString {
|
||||||
|
&self.hdr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for $String {
|
||||||
|
fn deref_mut(&mut self) -> &mut $AString {
|
||||||
|
&mut self.hdr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[$char_t]> for $String {
|
||||||
|
fn as_ref(&self) -> &[$char_t] {
|
||||||
|
&self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [$char_t]> for $String {
|
||||||
|
fn from(s: &'a [$char_t]) -> $String {
|
||||||
|
let mut res = $String::new();
|
||||||
|
res.assign(&$Str::from(&s[..]));
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Vec<$char_t>> for $String {
|
||||||
|
fn from(s: &'a Vec<$char_t>) -> $String {
|
||||||
|
$String::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a $AString> for $String {
|
||||||
|
fn from(s: &'a $AString) -> $String {
|
||||||
|
$String::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<[$char_t]>> for $String {
|
||||||
|
fn from(s: Box<[$char_t]>) -> $String {
|
||||||
|
s.to_vec().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<$char_t>> for $String {
|
||||||
|
fn from(mut s: Vec<$char_t>) -> $String {
|
||||||
assert!(s.len() < (u32::MAX as usize));
|
assert!(s.len() < (u32::MAX as usize));
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return $String::new();
|
return $String::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let length = s.len() as u32;
|
||||||
|
s.push(0); // null terminator
|
||||||
|
|
||||||
// SAFETY NOTE: This method produces an data_flags::OWNED
|
// SAFETY NOTE: This method produces an data_flags::OWNED
|
||||||
// ns[C]String from a Box<[$char_t]>. this is only safe
|
// ns[C]String from a Box<[$char_t]>. this is only safe
|
||||||
// because in the Gecko tree, we use the same allocator for
|
// because in the Gecko tree, we use the same allocator for
|
||||||
// Rust code as for C++ code, meaning that our box can be
|
// Rust code as for C++ code, meaning that our box can be
|
||||||
// legally freed with libc::free().
|
// legally freed with libc::free().
|
||||||
let length = s.len() as u32;
|
|
||||||
let ptr = s.as_ptr();
|
let ptr = s.as_ptr();
|
||||||
mem::forget(s);
|
mem::forget(s);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -493,72 +647,57 @@ macro_rules! define_string_types {
|
||||||
hdr: $StringRepr {
|
hdr: $StringRepr {
|
||||||
data: ptr,
|
data: ptr,
|
||||||
length: length,
|
length: length,
|
||||||
dataflags: data_flags::OWNED,
|
dataflags: data_flags::OWNED | data_flags::TERMINATED,
|
||||||
classflags: class_flags::NULL_TERMINATED,
|
classflags: class_flags::NULL_TERMINATED,
|
||||||
},
|
}
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<$char_t>> for $String<'static> {
|
impl fmt::Write for $String {
|
||||||
fn from(s: Vec<$char_t>) -> $String<'static> {
|
|
||||||
s.into_boxed_slice().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a $AString> for $String<'static> {
|
|
||||||
fn from(s: &'a $AString) -> $String<'static> {
|
|
||||||
let mut string = $String::new();
|
|
||||||
string.assign(s);
|
|
||||||
string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::Write for $String<'a> {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
$AString::write_str(self, s)
|
$AString::write_str(self, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for $String<'a> {
|
impl fmt::Display for $String {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
<$AString as fmt::Display>::fmt(self, f)
|
<$AString as fmt::Display>::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for $String<'a> {
|
impl fmt::Debug for $String {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
<$AString as fmt::Debug>::fmt(self, f)
|
<$AString as fmt::Debug>::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> cmp::PartialEq for $String<'a> {
|
impl cmp::PartialEq for $String {
|
||||||
fn eq(&self, other: &$String<'a>) -> bool {
|
fn eq(&self, other: &$String) -> bool {
|
||||||
$AString::eq(self, other)
|
$AString::eq(self, other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> cmp::PartialEq<[$char_t]> for $String<'a> {
|
impl cmp::PartialEq<[$char_t]> for $String {
|
||||||
fn eq(&self, other: &[$char_t]) -> bool {
|
fn eq(&self, other: &[$char_t]) -> bool {
|
||||||
$AString::eq(self, other)
|
$AString::eq(self, other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $String<'a> {
|
impl<'a> cmp::PartialEq<&'a [$char_t]> for $String {
|
||||||
fn eq(&self, other: &&'b [$char_t]) -> bool {
|
fn eq(&self, other: &&'a [$char_t]) -> bool {
|
||||||
$AString::eq(self, *other)
|
$AString::eq(self, *other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> cmp::PartialEq<str> for $String<'a> {
|
impl cmp::PartialEq<str> for $String {
|
||||||
fn eq(&self, other: &str) -> bool {
|
fn eq(&self, other: &str) -> bool {
|
||||||
$AString::eq(self, other)
|
$AString::eq(self, other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> cmp::PartialEq<&'b str> for $String<'a> {
|
impl<'a> cmp::PartialEq<&'a str> for $String {
|
||||||
fn eq(&self, other: &&'b str) -> bool {
|
fn eq(&self, other: &&'a str) -> bool {
|
||||||
$AString::eq(self, *other)
|
$AString::eq(self, *other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,7 +707,7 @@ macro_rules! define_string_types {
|
||||||
/// buffer, rather than using heap allocations.
|
/// buffer, rather than using heap allocations.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct $FixedString<'a> {
|
pub struct $FixedString<'a> {
|
||||||
base: $String<'a>,
|
base: $String,
|
||||||
capacity: u32,
|
capacity: u32,
|
||||||
buffer: *mut $char_t,
|
buffer: *mut $char_t,
|
||||||
_marker: PhantomData<&'a mut [$char_t]>,
|
_marker: PhantomData<&'a mut [$char_t]>,
|
||||||
|
@ -581,13 +720,7 @@ macro_rules! define_string_types {
|
||||||
let buf_ptr = buf.as_mut_ptr();
|
let buf_ptr = buf.as_mut_ptr();
|
||||||
$FixedString {
|
$FixedString {
|
||||||
base: $String {
|
base: $String {
|
||||||
hdr: $StringRepr {
|
hdr: $StringRepr::new(class_flags::FIXED | class_flags::NULL_TERMINATED),
|
||||||
data: ptr::null(),
|
|
||||||
length: 0,
|
|
||||||
dataflags: DataFlags::empty(),
|
|
||||||
classflags: class_flags::FIXED | class_flags::NULL_TERMINATED,
|
|
||||||
},
|
|
||||||
_marker: PhantomData,
|
|
||||||
},
|
},
|
||||||
capacity: len as u32,
|
capacity: len as u32,
|
||||||
buffer: buf_ptr,
|
buffer: buf_ptr,
|
||||||
|
@ -667,7 +800,7 @@ macro_rules! define_string_types {
|
||||||
/// &[$char_type], and &$AString to a function, while still performing
|
/// &[$char_type], and &$AString to a function, while still performing
|
||||||
/// optimized operations when passed the $AString.
|
/// optimized operations when passed the $AString.
|
||||||
pub enum $StringAdapter<'a> {
|
pub enum $StringAdapter<'a> {
|
||||||
Borrowed($String<'a>),
|
Borrowed($Str<'a>),
|
||||||
Abstract(&'a $AString),
|
Abstract(&'a $AString),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,7 +853,13 @@ macro_rules! define_string_types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $StringLike for $String<'a> {
|
impl<'a> $StringLike for $Str<'a> {
|
||||||
|
fn adapt(&self) -> $StringAdapter {
|
||||||
|
$StringAdapter::Abstract(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $StringLike for $String {
|
||||||
fn adapt(&self) -> $StringAdapter {
|
fn adapt(&self) -> $StringAdapter {
|
||||||
$StringAdapter::Abstract(self)
|
$StringAdapter::Abstract(self)
|
||||||
}
|
}
|
||||||
|
@ -734,19 +873,19 @@ macro_rules! define_string_types {
|
||||||
|
|
||||||
impl $StringLike for [$char_t] {
|
impl $StringLike for [$char_t] {
|
||||||
fn adapt(&self) -> $StringAdapter {
|
fn adapt(&self) -> $StringAdapter {
|
||||||
$StringAdapter::Borrowed($String::from(self))
|
$StringAdapter::Borrowed($Str::from(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $StringLike for Vec<$char_t> {
|
impl $StringLike for Vec<$char_t> {
|
||||||
fn adapt(&self) -> $StringAdapter {
|
fn adapt(&self) -> $StringAdapter {
|
||||||
$StringAdapter::Borrowed($String::from(&self[..]))
|
$StringAdapter::Borrowed($Str::from(&self[..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $StringLike for Box<[$char_t]> {
|
impl $StringLike for Box<[$char_t]> {
|
||||||
fn adapt(&self) -> $StringAdapter {
|
fn adapt(&self) -> $StringAdapter {
|
||||||
$StringAdapter::Borrowed($String::from(&self[..]))
|
$StringAdapter::Borrowed($Str::from(&self[..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -761,6 +900,7 @@ define_string_types! {
|
||||||
|
|
||||||
AString = nsACString;
|
AString = nsACString;
|
||||||
String = nsCString;
|
String = nsCString;
|
||||||
|
Str = nsCStr;
|
||||||
FixedString = nsFixedCString;
|
FixedString = nsFixedCString;
|
||||||
|
|
||||||
StringLike = nsCStringLike;
|
StringLike = nsCStringLike;
|
||||||
|
@ -805,20 +945,38 @@ impl nsACString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for nsCString<'a> {
|
impl<'a> From<&'a str> for nsCStr<'a> {
|
||||||
fn from(s: &'a str) -> nsCString<'a> {
|
fn from(s: &'a str) -> nsCStr<'a> {
|
||||||
s.as_bytes().into()
|
s.as_bytes().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<str>> for nsCString<'static> {
|
impl<'a> From<&'a String> for nsCStr<'a> {
|
||||||
fn from(s: Box<str>) -> nsCString<'static> {
|
fn from(s: &'a String) -> nsCStr<'a> {
|
||||||
|
nsCStr::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for nsCString {
|
||||||
|
fn from(s: &'a str) -> nsCString {
|
||||||
|
s.as_bytes().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a String> for nsCString {
|
||||||
|
fn from(s: &'a String) -> nsCString {
|
||||||
|
nsCString::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<str>> for nsCString {
|
||||||
|
fn from(s: Box<str>) -> nsCString {
|
||||||
s.into_string().into()
|
s.into_string().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for nsCString<'static> {
|
impl From<String> for nsCString {
|
||||||
fn from(s: String) -> nsCString<'static> {
|
fn from(s: String) -> nsCString {
|
||||||
s.into_bytes().into()
|
s.into_bytes().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -851,19 +1009,19 @@ impl cmp::PartialEq<str> for nsACString {
|
||||||
|
|
||||||
impl nsCStringLike for str {
|
impl nsCStringLike for str {
|
||||||
fn adapt(&self) -> nsCStringAdapter {
|
fn adapt(&self) -> nsCStringAdapter {
|
||||||
nsCStringAdapter::Borrowed(nsCString::from(self))
|
nsCStringAdapter::Borrowed(nsCStr::from(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl nsCStringLike for String {
|
impl nsCStringLike for String {
|
||||||
fn adapt(&self) -> nsCStringAdapter {
|
fn adapt(&self) -> nsCStringAdapter {
|
||||||
nsCStringAdapter::Borrowed(nsCString::from(&self[..]))
|
nsCStringAdapter::Borrowed(nsCStr::from(&self[..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl nsCStringLike for Box<str> {
|
impl nsCStringLike for Box<str> {
|
||||||
fn adapt(&self) -> nsCStringAdapter {
|
fn adapt(&self) -> nsCStringAdapter {
|
||||||
nsCStringAdapter::Borrowed(nsCString::from(&self[..]))
|
nsCStringAdapter::Borrowed(nsCStr::from(&self[..]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,6 +1042,7 @@ define_string_types! {
|
||||||
|
|
||||||
AString = nsAString;
|
AString = nsAString;
|
||||||
String = nsString;
|
String = nsString;
|
||||||
|
Str = nsStr;
|
||||||
FixedString = nsFixedString;
|
FixedString = nsFixedString;
|
||||||
|
|
||||||
StringLike = nsStringLike;
|
StringLike = nsStringLike;
|
||||||
|
@ -926,12 +1085,18 @@ impl nsAString {
|
||||||
|
|
||||||
// NOTE: The From impl for a string slice for nsString produces a <'static>
|
// NOTE: The From impl for a string slice for nsString produces a <'static>
|
||||||
// lifetime, as it allocates.
|
// lifetime, as it allocates.
|
||||||
impl<'a> From<&'a str> for nsString<'static> {
|
impl<'a> From<&'a str> for nsString {
|
||||||
fn from(s: &'a str) -> nsString<'static> {
|
fn from(s: &'a str) -> nsString {
|
||||||
s.encode_utf16().collect::<Vec<u16>>().into()
|
s.encode_utf16().collect::<Vec<u16>>().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a String> for nsString {
|
||||||
|
fn from(s: &'a String) -> nsString {
|
||||||
|
nsString::from(&s[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Support for the write!() macro for writing to nsStrings
|
// Support for the write!() macro for writing to nsStrings
|
||||||
impl fmt::Write for nsAString {
|
impl fmt::Write for nsAString {
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
|
@ -1022,6 +1187,8 @@ pub mod test_helpers {
|
||||||
nsFixedString,
|
nsFixedString,
|
||||||
nsCString,
|
nsCString,
|
||||||
nsString,
|
nsString,
|
||||||
|
nsCStr,
|
||||||
|
nsStr,
|
||||||
nsCStringRepr,
|
nsCStringRepr,
|
||||||
nsStringRepr,
|
nsStringRepr,
|
||||||
data_flags,
|
data_flags,
|
||||||
|
@ -1042,7 +1209,7 @@ pub mod test_helpers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($T:ty, $U:ty, $fname:ident) => {
|
($T:ty, $U:ty, $V:ty, $fname:ident) => {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub extern fn $fname(size: *mut usize, align: *mut usize) {
|
pub extern fn $fname(size: *mut usize, align: *mut usize) {
|
||||||
|
@ -1052,13 +1219,17 @@ pub mod test_helpers {
|
||||||
|
|
||||||
assert_eq!(*size, mem::size_of::<$U>());
|
assert_eq!(*size, mem::size_of::<$U>());
|
||||||
assert_eq!(*align, mem::align_of::<$U>());
|
assert_eq!(*align, mem::align_of::<$U>());
|
||||||
|
assert_eq!(*size, mem::size_of::<$V>());
|
||||||
|
assert_eq!(*align, mem::align_of::<$V>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_align_check!(nsStringRepr, nsString<'static>, Rust_Test_ReprSizeAlign_nsString);
|
size_align_check!(nsStringRepr, nsString, nsStr<'static>,
|
||||||
size_align_check!(nsCStringRepr, nsCString<'static>, Rust_Test_ReprSizeAlign_nsCString);
|
Rust_Test_ReprSizeAlign_nsString);
|
||||||
|
size_align_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||||
|
Rust_Test_ReprSizeAlign_nsCString);
|
||||||
size_align_check!(nsFixedString<'static>, Rust_Test_ReprSizeAlign_nsFixedString);
|
size_align_check!(nsFixedString<'static>, Rust_Test_ReprSizeAlign_nsFixedString);
|
||||||
size_align_check!(nsFixedCString<'static>, Rust_Test_ReprSizeAlign_nsFixedCString);
|
size_align_check!(nsFixedCString<'static>, Rust_Test_ReprSizeAlign_nsFixedCString);
|
||||||
|
|
||||||
|
@ -1088,7 +1259,7 @@ pub mod test_helpers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($T:ty, $U:ty, $member:ident, $method:ident) => {
|
($T:ty, $U:ty, $V:ty, $member:ident, $method:ident) => {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub extern fn $method(size: *mut usize,
|
pub extern fn $method(size: *mut usize,
|
||||||
|
@ -1112,19 +1283,35 @@ pub mod test_helpers {
|
||||||
(&tmp.hdr.$member as *const _ as usize) -
|
(&tmp.hdr.$member as *const _ as usize) -
|
||||||
(&tmp as *const _ as usize));
|
(&tmp as *const _ as usize));
|
||||||
mem::forget(tmp);
|
mem::forget(tmp);
|
||||||
|
|
||||||
|
let tmp: $V = mem::zeroed();
|
||||||
|
assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member));
|
||||||
|
assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member));
|
||||||
|
assert_eq!(*offset,
|
||||||
|
(&tmp.hdr.$member as *const _ as usize) -
|
||||||
|
(&tmp as *const _ as usize));
|
||||||
|
mem::forget(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
member_check!(nsStringRepr, nsString<'static>, data, Rust_Test_Member_nsString_mData);
|
member_check!(nsStringRepr, nsString, nsStr<'static>,
|
||||||
member_check!(nsStringRepr, nsString<'static>, length, Rust_Test_Member_nsString_mLength);
|
data, Rust_Test_Member_nsString_mData);
|
||||||
member_check!(nsStringRepr, nsString<'static>, dataflags, Rust_Test_Member_nsString_mDataFlags);
|
member_check!(nsStringRepr, nsString, nsStr<'static>,
|
||||||
member_check!(nsStringRepr, nsString<'static>, classflags, Rust_Test_Member_nsString_mClassFlags);
|
length, Rust_Test_Member_nsString_mLength);
|
||||||
member_check!(nsCStringRepr, nsCString<'static>, data, Rust_Test_Member_nsCString_mData);
|
member_check!(nsStringRepr, nsString, nsStr<'static>,
|
||||||
member_check!(nsCStringRepr, nsCString<'static>, length, Rust_Test_Member_nsCString_mLength);
|
dataflags, Rust_Test_Member_nsString_mDataFlags);
|
||||||
member_check!(nsCStringRepr, nsCString<'static>, dataflags, Rust_Test_Member_nsCString_mDataFlags);
|
member_check!(nsStringRepr, nsString, nsStr<'static>,
|
||||||
member_check!(nsCStringRepr, nsCString<'static>, classflags, Rust_Test_Member_nsCString_mClassFlags);
|
classflags, Rust_Test_Member_nsString_mClassFlags);
|
||||||
|
member_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||||
|
data, Rust_Test_Member_nsCString_mData);
|
||||||
|
member_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||||
|
length, Rust_Test_Member_nsCString_mLength);
|
||||||
|
member_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||||
|
dataflags, Rust_Test_Member_nsCString_mDataFlags);
|
||||||
|
member_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||||
|
classflags, Rust_Test_Member_nsCString_mClassFlags);
|
||||||
member_check!(nsFixedString<'static>, capacity, Rust_Test_Member_nsFixedString_mFixedCapacity);
|
member_check!(nsFixedString<'static>, capacity, Rust_Test_Member_nsFixedString_mFixedCapacity);
|
||||||
member_check!(nsFixedString<'static>, buffer, Rust_Test_Member_nsFixedString_mFixedBuf);
|
member_check!(nsFixedString<'static>, buffer, Rust_Test_Member_nsFixedString_mFixedBuf);
|
||||||
member_check!(nsFixedCString<'static>, capacity, Rust_Test_Member_nsFixedCString_mFixedCapacity);
|
member_check!(nsFixedCString<'static>, capacity, Rust_Test_Member_nsFixedCString_mFixedCapacity);
|
||||||
|
|