Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2020-04-18 07:25:50 +08:00
commit 924da4a2cc
559 changed files with 9029 additions and 12082 deletions

36
SECURITY.md Normal file
View file

@ -0,0 +1,36 @@
# Security Policy
## What is or is not a vulnerability?
In general, vulnerabilities are those bugs that can actually be exploited to perform malicious tasks.
Most _crashes_ are not security vulnerabilities. Although important to fix, they don't inherently cause a problem for the
browser's security.
What should be considered vulnerabilities or security hazards by default:
- Use-after-free crashes, since those can potentially be used for remote code execution;
- Spoofing issues in the UI;
- File security issues, like out-of-bounds access to arbitrary files or locations;
- Type confusion issues;
- Bypass of security measures like CSP or the various mechanisms around HTTPS.
Generally not security vulnerabilities:
- Null dereferencing crashes;
- Malware extensions (but please do report those on the forum in the extensions board!);
- Denial-of-service (AKA "evil trap sites")
- Browser hangs
- Issues with non-standard manual configuration (either at build time or by manipulating about:config directly)
## Reporting a Vulnerability
If you find an issue in UXP or the applications it builds on that could impact the security or safety of users please **do not**
make an issue on GitHub about it. GitHub does not support restricted viewability for security sensitive bugs.
If you want to report a security-sensitive issue then please go to the [forum](https://forum.palemoon.org) and report the issue
via a **private message** to **Moonchild** (the founder and prime responsible for security issues).
The forum's private message system is fully secure since your visits are encrypted and private messages are not available to anyone
except the recipient (not even moderators!).
You will be informed via private message if the vulnerability report is accepted or declined, with reasoning.
Security updates occur regularly and are given priority over most other development tasks. In general, they can be solved
relatively quickly and will be included in the next point release (third digit if not rolled into a more major one).

View file

@ -205,7 +205,7 @@ toolbar[customizing] > .overflow-button {
display: none;
}
%ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#main-window:not([chromemargin]) > #titlebar,
#main-window[inFullscreen] > #titlebar,
#main-window[inFullscreen] .titlebar-placeholder,

View file

@ -45,7 +45,7 @@
titlemodifier_normal="&mainWindow.titlemodifier;"
titlemodifier_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
#endif
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#ifdef XP_WIN
chromemargin="0,2,2,2"
#else
@ -388,7 +388,7 @@
onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/>
</popupset>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<vbox id="titlebar">
<hbox id="titlebar-content">
<spacer id="titlebar-spacer" flex="1"/>
@ -437,7 +437,7 @@
#include browser-menubar.inc
</toolbaritem>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#ifndef XP_MACOSX
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"
id="titlebar-placeholder-on-menubar-for-caption-buttons" persist="width"
@ -507,7 +507,7 @@
#if !defined(MOZ_WIDGET_GTK)
<hbox class="private-browsing-indicator" skipintoolbarset="true"/>
#endif
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<hbox class="titlebar-placeholder" type="caption-buttons"
id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
#ifndef XP_MACOSX

View file

@ -79,7 +79,7 @@ browser.jar:
#endif
content/browser/browser-sidebar.js (content/browser-sidebar.js)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar.js)
#else
content/browser/browser-tabsintitlebar.js (content/browser-tabsintitlebar-stub.js)

View file

@ -13,9 +13,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
DEFINES['HAVE_SHELL_SERVICE'] = 1
DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1

View file

@ -19,7 +19,7 @@
<vbox id="customization-palette" class="customization-palette"/>
<spacer id="customization-spacer"/>
<hbox id="customization-footer">
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<button id="customization-titlebar-visibility-button" class="customizationmode-button"
label="&customizeMode.titlebar;" type="checkbox"
#NB: because oncommand fires after click, by the time we've fired, the checkbox binding

View file

@ -19,6 +19,3 @@ EXTRA_JS_MODULES += [
EXTRA_PP_JS_MODULES += [
'CustomizableUI.jsm',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1

View file

@ -58,6 +58,13 @@ MOZ_SERVICES_SYNC=1
MOZ_SERVICES_HEALTHREPORT=
MOZ_SAFE_BROWSING=
MOZ_GAMEPAD=1
MOZ_AV1=1
if test "$OS_ARCH" = "WINNT" -o \
"$OS_ARCH" = "Darwin"; then
MOZ_CAN_DRAW_IN_TITLEBAR=1
fi
# Disable checking that add-ons are signed by the trusted root
MOZ_ADDON_SIGNING=0
MOZ_REQUIRE_SIGNING=0

View file

@ -4,4 +4,7 @@
# 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/.
# Specific options go here
# Example: imply_option('MOZ_AV1', True)
include('../../toolkit/moz.configure')

View file

@ -8,6 +8,4 @@ DIRS += ['communicator']
JAR_MANIFESTS += ['jar.mn']
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
include('../tab-svgs.mozbuild')

View file

@ -182,7 +182,7 @@
height: 24px;
}
%ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#customization-titlebar-visibility-button > .button-box > .button-text,
%endif
#customization-lwtheme-button > .box-inherit > .box-inherit > .button-text {
@ -198,7 +198,7 @@
background-size: contain;
}
%ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#customization-titlebar-visibility-button {
list-style-image: url("chrome://browser/skin/customizableui/customize-titleBar-toggle.png");
-moz-image-region: rect(0, 24px, 24px, 0);
@ -222,7 +222,7 @@
-moz-image-region: rect(0, 96px, 48px, 48px);
}
}
%endif /* CAN_DRAW_IN_TITLEBAR */
%endif /* MOZ_CAN_DRAW_IN_TITLEBAR */
#main-window[customize-entered] #customization-panel-container {
background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),

View file

@ -8,6 +8,4 @@ DIRS += ['communicator']
JAR_MANIFESTS += ['jar.mn']
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
include('../tab-svgs.mozbuild')

View file

@ -875,7 +875,7 @@ pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
// 0 = standard behavior: pull fully from cache
// 1 = perform a soft refresh when restoring a tab (check network)
// 2 = perform a hard refresh when restoring a tab (bypass cache completely)
pref("browser.sessionstore.cache_behavior", 1);
pref("browser.sessionstore.cache_behavior", 0);
// Pale Moon: Allow exact positioning of windows to previous locations, even
// if they would be outside of the screen bounds
pref("browser.sessionstore.exactPos", false);

View file

@ -106,7 +106,7 @@ toolbar[printpreview="true"] {
-moz-box-ordinal-group: 10;
}
%ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#main-window[inFullscreen] > #titlebar,
#main-window[inFullscreen] .titlebar-placeholder,
#main-window:not([tabsintitlebar]) .titlebar-placeholder {
@ -222,7 +222,7 @@ splitmenu {
}
%ifdef MENUBAR_CAN_AUTOHIDE
%ifndef CAN_DRAW_IN_TITLEBAR
%ifndef MOZ_CAN_DRAW_IN_TITLEBAR
#appmenu-toolbar-button > .toolbarbutton-text {
display: -moz-box;
}

View file

@ -4706,7 +4706,7 @@ var TabsOnTop = {
var TabsInTitlebar = {
init: function() {
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
this._readPref();
Services.prefs.addObserver(this._prefName, this, false);
@ -4719,7 +4719,7 @@ var TabsInTitlebar = {
},
allowedBy: function(condition, allow) {
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
if (allow) {
if (condition in this._disallowed) {
delete this._disallowed[condition];
@ -4738,7 +4738,7 @@ var TabsInTitlebar = {
return document.documentElement.getAttribute("tabsintitlebar") == "true";
},
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
observe: function(subject, topic, data) {
if (topic == "nsPref:changed")
this._readPref();
@ -4812,7 +4812,7 @@ var TabsInTitlebar = {
#endif
uninit: function() {
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
this._initialized = false;
Services.prefs.removeObserver(this._prefName, this);
#endif
@ -4826,7 +4826,7 @@ function updateAppButtonDisplay() {
window.menubar.visible &&
document.getElementById("toolbar-menubar").getAttribute("autohide") == "true";
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
document.getElementById("titlebar").hidden = !displayAppButton;
if (displayAppButton)
@ -4842,7 +4842,7 @@ function updateAppButtonDisplay() {
}
#endif
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
function onTitlebarMaxClick() {
if (window.windowState == window.STATE_MAXIMIZED)
window.restore();
@ -6955,7 +6955,7 @@ var gPrivateBrowsingUI = {
document.getElementById("Tools:Sanitize").setAttribute("disabled", "true");
if (window.location.href == getBrowserURL()) {
#ifdef XP_MACOSX
#if defined(XP_MACOSX) && defined(MOZ_CAN_DRAW_IN_TITLEBAR)
if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
document.documentElement.setAttribute("drawintitlebar", true);
}

View file

@ -324,7 +324,7 @@
</popupset>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<vbox id="titlebar">
<hbox id="titlebar-content">
#ifdef MENUBAR_CAN_AUTOHIDE
@ -374,7 +374,7 @@
#include browser-menubar.inc
</toolbaritem>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
#endif
@ -771,7 +771,7 @@
</toolbar>
#ifdef MENUBAR_CAN_AUTOHIDE
#ifndef CAN_DRAW_IN_TITLEBAR
#ifndef MOZ_CAN_DRAW_IN_TITLEBAR
#define APPMENU_ON_TABBAR
#endif
#endif
@ -838,7 +838,7 @@
label="&closeTab.label;"
tooltiptext="&closeTab.label;"/>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MOZ_CAN_DRAW_IN_TITLEBAR
<hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
#endif

View file

@ -11,9 +11,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
DEFINES['HAVE_SHELL_SERVICE'] = 1
DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1

View file

@ -3236,19 +3236,24 @@ var SessionStoreInternal = {
// instead of gotoIndex. See bug 597315.
browser.webNavigation.sessionHistory.getEntryAtIndex(activeIndex, true);
browser.webNavigation.sessionHistory.reloadCurrentEntry();
// If the user prefers it, bypass cache and always load from the network.
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
switch (this._cacheBehavior) {
case 2: // hard refresh
flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
browser.webNavigation.reload(flags);
break;
case 1: // soft refresh
browser.webNavigation.reload(flags);
break;
default: // 0 or other: use cache, so do nothing.
break;
// If the user prefers it, bypass cache and always load from the network,
// but only if restoring on demand, to prevent request flooding (since
// reloading will override the max tabs to restore concurrently mechanism).
// See Issue #1772
if (restoreOnDemand) {
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
switch (this._cacheBehavior) {
case 2: // hard refresh
flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
browser.webNavigation.reload(flags);
break;
case 1: // soft refresh
browser.webNavigation.reload(flags);
break;
default: // 0 or other: use cache, so do nothing.
break;
}
}
}
catch (ex) {

View file

@ -79,6 +79,11 @@ MOZ_JSDOWNLOADS=1
# conformant implementations.
MOZ_WEBGL_CONFORMANT=1
# Platform Feature: Enable drawing in the titlebar on Windows
if test "$OS_ARCH" = "WINNT"; then
MOZ_CAN_DRAW_IN_TITLEBAR=1
fi
# Set the chrome packing format
# Possible values are omni, jar, and flat
# Currently, only omni and flat are supported

View file

@ -93,6 +93,7 @@
}
/* Blend the topmost toolbar with the titlebar */
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#main-window[tabsontop=false]:not([privatebrowsingmode=temporary]) #nav-bar:not(:-moz-lwtheme),
#main-window[tabsontop=false]:not([privatebrowsingmode=temporary]) #PersonalToolbar[collapsed=true]
~ #TabsToolbar:not(:-moz-lwtheme),
@ -110,6 +111,14 @@
#main-window[tabsontop=false][privatebrowsingmode=temporary] #nav-bar:not(:-moz-lwtheme) {
border-bottom: 1px solid rgba(26,26,26,0.2);
}
%else
#main-window[tabsontop=false] #nav-bar:not(:-moz-lwtheme),
#main-window[tabsontop=false] #PersonalToolbar[collapsed=true]
~ #TabsToolbar:not(:-moz-lwtheme),
#main-window[tabsontop=true] #TabsToolbar:not(:-moz-lwtheme) {
-moz-appearance: toolbar;
}
%endif
#personal-bookmarks {
min-height: 24px;
@ -124,7 +133,7 @@
}
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
/* ::::: titlebar ::::: */
#main-window[sizemode="normal"]:not([privatebrowsingmode=temporary]) > #titlebar {
@ -180,7 +189,7 @@
margin-left: 7px;
margin-top: 3px;
}
%endif
/* ::::: bookmark toolbar ::::: */
#personal-bookmarks {
@ -218,13 +227,21 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
/* ::::: bookmark buttons ::::: */
toolbarbutton.bookmark-item {
color: #222;
border: 0;
border-radius: 10000px;
padding: 1px 8px;
margin: 0 0 1px;
}
toolbarbutton.bookmark-item:not(:-moz-lwtheme) {
color: #222;
}
toolbarbutton.bookmark-item:-moz-lwtheme {
color: inherit;
text-shadow: inherit;
}
.bookmark-item > .toolbarbutton-menu-dropmarker {
list-style-image: url("chrome://browser/skin/places/folderDropArrow.png");
-moz-image-region: rect(0, 7px, 5px, 0);
@ -254,18 +271,25 @@ toolbarbutton.bookmark-item[open="true"] {
background-color: rgba(0, 0, 0, .205);
}
toolbarbutton.bookmark-item:hover,
toolbarbutton.bookmark-item[open="true"] {
color: #FFF !important;
text-shadow: 0 1px rgba(0, 0, 0, .4) !important;
toolbarbutton.bookmark-item:-moz-lwtheme-brighttext:hover,
toolbarbutton.bookmark-item[open="true"]:-moz-lwtheme-brighttext {
background-color: rgba(255, 255, 255, .3);
}
toolbarbutton.bookmark-item:not(:-moz-lwtheme):hover,
toolbarbutton.bookmark-item[open="true"]:not(:-moz-lwtheme) {
color: #FFF;
text-shadow: 0 1px rgba(0, 0, 0, .4);
}
.bookmark-item:-moz-lwtheme-brighttext > .toolbarbutton-menu-dropmarker,
.bookmark-item:hover > .toolbarbutton-menu-dropmarker,
.bookmark-item[open="true"] > .toolbarbutton-menu-dropmarker {
-moz-image-region: rect(5px, 7px, 10px, 0);
}
@media (min-resolution: 2dppx) {
.bookmark-item:-moz-lwtheme-brighttext > .toolbarbutton-menu-dropmarker,
.bookmark-item:hover > .toolbarbutton-menu-dropmarker,
.bookmark-item[open="true"] > .toolbarbutton-menu-dropmarker {
-moz-image-region: rect(10px, 14px, 20px, 0);
@ -278,6 +302,11 @@ toolbarbutton.bookmark-item[open="true"] {
background-color: rgba(0, 0, 0, .5);
}
toolbarbutton.bookmark-item:-moz-lwtheme-brighttext:hover,
toolbarbutton.bookmark-item[open="true"]:-moz-lwtheme-brighttext {
background-color: rgba(255,255,255, .3);
}
toolbarbutton.bookmark-item > menupopup {
margin-top: 2px;
margin-inline-start: 3px;
@ -1738,14 +1767,6 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
margin-top: 0px;
}
/* make the tab text colors match those of the Windows client */
@media (-moz-mac-lion-theme) {
tab {
text-shadow: none;
color: black !important;
}
}
.tabbrowser-tab:hover,
.tabs-newtab-button:hover {
background-image: @toolbarShadowOnTab@, var(--tab-background-hover),
@ -2787,6 +2808,7 @@ toolbar[brighttext] #addonbar-closebutton {
right: auto;
}
%ifdef MOZ_CAN_DRAW_IN_TITLEBAR
#main-window[privatebrowsingmode=temporary] {
background-image: url("chrome://browser/skin/privatebrowsing-mask.png");
background-position: top right;
@ -2840,3 +2862,4 @@ toolbar[brighttext] #addonbar-closebutton {
padding-inline-end: 50px;
}
}
%endif

View file

@ -157,6 +157,7 @@ def old_configure_options(*options):
'--enable-accessibility',
'--enable-address-sanitizer',
'--enable-alsa',
'--enable-av1',
'--enable-b2g-bt',
'--enable-b2g-camera',
'--enable-b2g-ril',

View file

@ -436,23 +436,22 @@ nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
NS_ENSURE_SUCCESS(rv, rv);
}
int32_t count = document->GetNumberOfStyleSheets();
size_t count = document->SheetCount();
// Build an array of style sheets we need to reload.
nsTArray<RefPtr<StyleSheet>> oldSheets(count);
nsTArray<RefPtr<StyleSheet>> newSheets(count);
// Iterate over the style sheets.
for (int32_t i = 0; i < count; i++) {
for (size_t i = 0; i < count; i++) {
// Get the style sheet
StyleSheet* styleSheet = document->GetStyleSheetAt(i);
oldSheets.AppendElement(styleSheet);
oldSheets.AppendElement(document->SheetAt(i));
}
// Iterate over our old sheets and kick off a sync load of the new
// sheet if and only if it's a non-inline sheet with a chrome URL.
for (StyleSheet* sheet : oldSheets) {
MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
MOZ_ASSERT(sheet, "SheetAt shouldn't return nullptr for "
"in-range sheet indexes");
nsIURI* uri = sheet->GetSheetURI();

View file

@ -33,7 +33,7 @@ function* testTopLeft(inspector, view) {
let afterElement = children.nodes[children.nodes.length - 1];
yield selectNode(afterElement, inspector);
top = getComputedViewPropertyValue(view, "top");
is(top, "50%", "The computed view shows the correct top");
is(top, "96px", "The computed view shows the correct top");
left = getComputedViewPropertyValue(view, "left");
is(left, "50%", "The computed view shows the correct left");
is(left, "96px", "The computed view shows the correct left");
}

View file

@ -356,24 +356,16 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement,
return aElement;
}
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (!primaryFrame) {
return nullptr;
}
nsIFrame* pseudoFrame;
if (aPseudoType == CSSPseudoElementType::before) {
pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
} else if (aPseudoType == CSSPseudoElementType::after) {
pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
} else {
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
"other that :before or :after");
return nullptr;
return nsLayoutUtils::GetBeforePseudo(aElement);
}
if (!pseudoFrame) {
return nullptr;
if (aPseudoType == CSSPseudoElementType::after) {
return nsLayoutUtils::GetAfterPseudo(aElement);
}
return pseudoFrame->GetContent()->AsElement();
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
"other that :before or :after");
return nullptr;
}
bool

View file

@ -1105,19 +1105,17 @@ KeyframeEffectReadOnly::GetAnimationFrame() const
return nullptr;
}
nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
if (!frame) {
return nullptr;
}
nsIFrame* frame;
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
frame = nsLayoutUtils::GetBeforeFrame(frame);
frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
frame = nsLayoutUtils::GetAfterFrame(frame);
frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
} else {
frame = mTarget->mElement->GetPrimaryFrame();
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
"unknown mTarget->mPseudoType");
}
if (!frame) {
return nullptr;
}

View file

@ -69,10 +69,10 @@ ArchiveRequest::~ArchiveRequest()
}
nsresult
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.mParentTarget = nullptr;
aVisitor.SetParentTarget(nullptr, false);
return NS_OK;
}

View file

@ -38,7 +38,8 @@ public:
ArchiveReader* aReader);
// nsIDOMEventTarget
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
virtual nsresult GetEventTargetParent(
EventChainPreVisitor& aVisitor) override;
public:
// This is called by the DOMArchiveRequestEvent

View file

@ -7,6 +7,7 @@
#include "AnonymousContent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/AnonymousContentBinding.h"
#include "nsComputedDOMStyle.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h"
#include "nsIDOMHTMLCollection.h"
@ -208,5 +209,31 @@ AnonymousContent::WrapObject(JSContext* aCx,
return AnonymousContentBinding::Wrap(aCx, this, aGivenProto, aReflector);
}
void
AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
const nsAString& aPropertyName,
DOMString& aResult,
ErrorResult& aRv)
{
Element* element = GetElementById(aElementId);
if (!element) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
nsIPresShell* shell = element->OwnerDoc()->GetShell();
if (!shell) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
RefPtr<nsComputedDOMStyle> cs =
new nsComputedDOMStyle(element,
NS_LITERAL_STRING(""),
element->OwnerDoc(),
nsComputedDOMStyle::eAll);
aRv = cs->GetPropertyValue(aPropertyName, aResult);
}
} // namespace dom
} // namespace mozilla

View file

@ -68,6 +68,11 @@ public:
const Sequence<OwningNonNull<DOMRect>>& aRects,
ErrorResult& aError);
void GetComputedStylePropertyValue(const nsAString& aElementId,
const nsAString& aPropertyName,
DOMString& aResult,
ErrorResult& aRv);
private:
~AnonymousContent();
nsCOMPtr<Element> mContentNode;

View file

@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
}
nsresult
Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
return NS_OK;

View file

@ -54,7 +54,7 @@ public:
// nsIDOMAttr interface
NS_DECL_NSIDOMATTR
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsIAttribute interface
void SetMap(nsDOMAttributeMap *aMap) override;

View file

@ -8,6 +8,9 @@
#define mozilla_dom_BlobSet_h
#include "mozilla/RefPtr.h"
#include "jsfriendapi.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {

View file

@ -4,6 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#ifndef CORSMode_h_
#define CORSMode_h_

View file

@ -6,61 +6,27 @@
#include "ChildIterator.h"
#include "nsContentUtils.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/XBLChildrenElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIFrame.h"
#include "nsCSSAnonBoxes.h"
#include "nsDocument.h"
namespace mozilla {
namespace dom {
class MatchedNodes {
public:
explicit MatchedNodes(HTMLContentElement* aInsertionPoint)
: mIsContentElement(true), mContentElement(aInsertionPoint) {}
explicit MatchedNodes(XBLChildrenElement* aInsertionPoint)
: mIsContentElement(false), mChildrenElement(aInsertionPoint) {}
uint32_t Length() const
{
return mIsContentElement ? mContentElement->MatchedNodes().Length()
: mChildrenElement->InsertedChildrenLength();
}
nsIContent* operator[](int32_t aIndex) const
{
return mIsContentElement ? mContentElement->MatchedNodes()[aIndex]
: mChildrenElement->InsertedChild(aIndex);
}
bool IsEmpty() const
{
return mIsContentElement ? mContentElement->MatchedNodes().IsEmpty()
: !mChildrenElement->HasInsertedChildren();
}
protected:
bool mIsContentElement;
union {
HTMLContentElement* mContentElement;
XBLChildrenElement* mChildrenElement;
};
};
static inline MatchedNodes
GetMatchedNodesForPoint(nsIContent* aContent)
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
bool aStartAtBeginning)
: mParent(aParent),
mChild(nullptr),
mDefaultChild(nullptr),
mIsFirst(aStartAtBeginning),
mIndexInInserted(0)
{
if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
// XBL case
return MatchedNodes(static_cast<XBLChildrenElement*>(aContent));
}
// Web components case
MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::content));
return MatchedNodes(HTMLContentElement::FromContent(aContent));
mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
HTMLSlotElement::FromContent(mParent) : nullptr;
}
nsIContent*
@ -69,30 +35,29 @@ ExplicitChildIterator::GetNextChild()
// If we're already in the inserted-children array, look there first
if (mIndexInInserted) {
MOZ_ASSERT(mChild);
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
MOZ_ASSERT(!mDefaultChild);
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (mIndexInInserted < assignedChildren.Length()) {
return assignedChildren[mIndexInInserted++];
}
mIndexInInserted = 0;
mChild = mChild->GetNextSibling();
} else if (mShadowIterator) {
// If we're inside of a <shadow> element, look through the
// explicit children of the projected ShadowRoot via
// the mShadowIterator.
nsIContent* nextChild = mShadowIterator->GetNextChild();
if (nextChild) {
return nextChild;
if (mParentAsSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes =
mParentAsSlot->AssignedNodes();
mChild = (mIndexInInserted < assignedNodes.Length()) ?
assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
return mChild;
}
mShadowIterator = nullptr;
MOZ_ASSERT(mChild->IsActiveChildrenElement());
auto* childrenElement =
static_cast<XBLChildrenElement*>(mChild);
if (mIndexInInserted < childrenElement->InsertedChildrenLength()) {
return childrenElement->InsertedChild(mIndexInInserted++);
}
mIndexInInserted = 0;
mChild = mChild->GetNextSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
MOZ_ASSERT(mChild);
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
MOZ_ASSERT(mChild->IsActiveChildrenElement());
mDefaultChild = mDefaultChild->GetNextSibling();
if (mDefaultChild) {
@ -101,6 +66,19 @@ ExplicitChildIterator::GetNextChild()
mChild = mChild->GetNextSibling();
} else if (mIsFirst) { // at the beginning of the child list
// For slot parent, iterate over assigned nodes if not empty, otherwise
// fall through and iterate over direct children (fallback content).
if (mParentAsSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes =
mParentAsSlot->AssignedNodes();
if (!assignedNodes.IsEmpty()) {
mIndexInInserted = 1;
mChild = assignedNodes[0]->AsContent();
mIsFirst = false;
return mChild;
}
}
mChild = mParent->GetFirstChild();
mIsFirst = false;
} else if (mChild) { // in the middle of the child list
@ -110,31 +88,16 @@ ExplicitChildIterator::GetNextChild()
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
// If the current child being iterated is a shadow insertion point then
// the iterator needs to go into the projected ShadowRoot.
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
// Look for the next child in the projected ShadowRoot for the <shadow>
// element.
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
if (projectedShadow) {
mShadowIterator = new ExplicitChildIterator(projectedShadow);
nsIContent* nextChild = mShadowIterator->GetNextChild();
if (nextChild) {
return nextChild;
}
mShadowIterator = nullptr;
}
mChild = mChild->GetNextSibling();
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
if (mChild->IsActiveChildrenElement()) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (!assignedChildren.IsEmpty()) {
auto* childrenElement =
static_cast<XBLChildrenElement*>(mChild);
if (childrenElement->HasInsertedChildren()) {
// Iterate through elements projected on insertion point.
mIndexInInserted = 1;
return assignedChildren[0];
return childrenElement->InsertedChild(0);
}
// Insertion points inside fallback/default content
@ -192,19 +155,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
}
bool
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
{
if (aChildToFind->GetParent() == mParent &&
!aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours.
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
mChild = aChildToFind;
mChild = const_cast<nsIContent*>(aChildToFind);
mIndexInInserted = 0;
mShadowIterator = nullptr;
mDefaultChild = nullptr;
mIsFirst = false;
MOZ_ASSERT(!mChild->IsActiveChildrenElement());
return true;
}
@ -220,12 +181,18 @@ ExplicitChildIterator::Get() const
{
MOZ_ASSERT(!mIsFirst);
if (mIndexInInserted) {
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
return assignedChildren[mIndexInInserted - 1];
} else if (mShadowIterator) {
return mShadowIterator->Get();
// When mParentAsSlot is set, mChild is always set to the current child. It
// does not matter whether mChild is an assigned node or a fallback content.
if (mParentAsSlot) {
return mChild;
}
if (mIndexInInserted) {
MOZ_ASSERT(mChild->IsActiveChildrenElement());
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
return childrenElement->InsertedChild(mIndexInInserted - 1);
}
return mDefaultChild ? mDefaultChild : mChild;
}
@ -234,20 +201,28 @@ ExplicitChildIterator::GetPreviousChild()
{
// If we're already in the inserted-children array, look there first
if (mIndexInInserted) {
if (mParentAsSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes =
mParentAsSlot->AssignedNodes();
mChild = (--mIndexInInserted) ?
assignedNodes[mIndexInInserted - 1]->AsContent() : nullptr;
if (!mChild) {
mIsFirst = true;
}
return mChild;
}
// NB: mIndexInInserted points one past the last returned child so we need
// to look *two* indices back in order to return the previous child.
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
MOZ_ASSERT(mChild->IsActiveChildrenElement());
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
if (--mIndexInInserted) {
return assignedChildren[mIndexInInserted - 1];
return childrenElement->InsertedChild(mIndexInInserted - 1);
}
mChild = mChild->GetPreviousSibling();
} else if (mShadowIterator) {
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
if (previousChild) {
return previousChild;
}
mShadowIterator = nullptr;
mChild = mChild->GetPreviousSibling();
} else if (mDefaultChild) {
// If we're already in default content, check if there are more nodes there
mDefaultChild = mDefaultChild->GetPreviousSibling();
@ -261,35 +236,32 @@ ExplicitChildIterator::GetPreviousChild()
} else if (mChild) { // in the middle of the child list
mChild = mChild->GetPreviousSibling();
} else { // at the end of the child list
// For slot parent, iterate over assigned nodes if not empty, otherwise
// fall through and iterate over direct children (fallback content).
if (mParentAsSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes =
mParentAsSlot->AssignedNodes();
if (!assignedNodes.IsEmpty()) {
mIndexInInserted = assignedNodes.Length();
mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
return mChild;
}
}
mChild = mParent->GetLastChild();
}
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
// If the current child being iterated is a shadow insertion point then
// the iterator needs to go into the projected ShadowRoot.
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
if (projectedShadow) {
// Create a ExplicitChildIterator that begins iterating from the end.
mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
if (previousChild) {
return previousChild;
}
mShadowIterator = nullptr;
}
mChild = mChild->GetPreviousSibling();
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
if (mChild->IsActiveChildrenElement()) {
// If the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (!assignedChildren.IsEmpty()) {
mIndexInInserted = assignedChildren.Length();
return assignedChildren[mIndexInInserted - 1];
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
if (childrenElement->HasInsertedChildren()) {
mIndexInInserted = childrenElement->InsertedChildrenLength();
return childrenElement->InsertedChild(mIndexInInserted - 1);
}
mDefaultChild = mChild->GetLastChild();
@ -317,11 +289,9 @@ AllChildrenIterator::Get() const
{
switch (mPhase) {
case eAtBeforeKid: {
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
return beforeFrame->GetContent();
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
return before;
}
case eAtExplicitKids:
@ -331,11 +301,9 @@ AllChildrenIterator::Get() const
return mAnonKids[mAnonKidsIdx];
case eAtAfterKid: {
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
return afterFrame->GetContent();
Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
return after;
}
default:
@ -345,19 +313,14 @@ AllChildrenIterator::Get() const
bool
AllChildrenIterator::Seek(nsIContent* aChildToFind)
AllChildrenIterator::Seek(const nsIContent* aChildToFind)
{
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
if (beforeFrame->GetContent() == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
}
}
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforePseudo && beforePseudo == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
}
}
@ -383,12 +346,10 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
if (scrollFrame) {
AppendNativeAnonymousChildrenFromFrame(scrollFrame);
}
if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
mOriginalContent->OwnerDoc(), mAnonKids);
}
}
@ -406,13 +367,10 @@ AllChildrenIterator::GetNextChild()
{
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforeContent) {
mPhase = eAtBeforeKid;
return beforeContent;
}
}
@ -448,13 +406,10 @@ AllChildrenIterator::GetNextChild()
return mAnonKids[mAnonKidsIdx];
}
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
if (afterContent) {
mPhase = eAtAfterKid;
return afterContent;
}
}
@ -468,13 +423,10 @@ AllChildrenIterator::GetPreviousChild()
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
if (afterContent) {
mPhase = eAtAfterKid;
return afterContent;
}
}
@ -503,13 +455,10 @@ AllChildrenIterator::GetPreviousChild()
return kid;
}
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforeContent) {
mPhase = eAtBeforeKid;
return beforeContent;
}
}
@ -585,12 +534,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
return true;
}
// The root element has a scroll frame that is not the primary frame, so we
// need to do special checking for that case.
if (aElement == aElement->OwnerDoc()->GetRootElement()) {
return true;
}
return false;
}

View file

@ -36,27 +36,20 @@ class ExplicitChildIterator
{
public:
explicit ExplicitChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true)
: mParent(aParent),
mChild(nullptr),
mDefaultChild(nullptr),
mIndexInInserted(0),
mIsFirst(aStartAtBeginning)
{
}
bool aStartAtBeginning = true);
ExplicitChildIterator(const ExplicitChildIterator& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
: mParent(aOther.mParent),
mParentAsSlot(aOther.mParentAsSlot),
mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(aOther.mShadowIterator ?
new ExplicitChildIterator(*aOther.mShadowIterator) :
nullptr),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
ExplicitChildIterator(ExplicitChildIterator&& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
: mParent(aOther.mParent),
mParentAsSlot(aOther.mParentAsSlot),
mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(Move(aOther.mShadowIterator)),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
nsIContent* GetNextChild();
@ -65,13 +58,13 @@ public:
// found. This version can take shortcuts that the two-argument version
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
// cases).
bool Seek(nsIContent* aChildToFind);
bool Seek(const nsIContent* aChildToFind);
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
// whether aChildToFind was found as an explicit child prior to encountering
// aBound.
bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
{
// It would be nice to assert that we find aChildToFind, but bz thinks that
// we might not find aChildToFind when called from ContentInserted
@ -102,6 +95,10 @@ protected:
// the <xbl:content> element for the binding.
const nsIContent* mParent;
// If parent is a slot element, this points to the parent as HTMLSlotElement,
// otherwise, it's null.
const HTMLSlotElement* mParentAsSlot;
// The current child. When we encounter an insertion point,
// mChild remains as the insertion point whose content we're iterating (and
// our state is controled by mDefaultChild or mIndexInInserted depending on
@ -114,11 +111,6 @@ protected:
// to null, we continue iterating at mChild's next sibling.
nsIContent* mDefaultChild;
// If non-null, this points to an iterator of the explicit children of
// the ShadowRoot projected by the current shadow element that we're
// iterating.
nsAutoPtr<ExplicitChildIterator> mShadowIterator;
// If not zero, we're iterating inserted children for an insertion point. This
// is an index into mChild's inserted children array (mChild must be an
// nsXBLChildrenElement). The index is one past the "current" child (as
@ -139,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
public:
explicit FlattenedChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{
Init(false);
}
FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
: ExplicitChildIterator(Move(aOther))
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
: ExplicitChildIterator(aOther)
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
bool XBLInvolved() { return mXBLInvolved; }
const nsIContent* Parent() const { return mOriginalContent; }
protected:
/**
* This constructor is a hack to help AllChildrenIterator which sometimes
@ -159,7 +161,9 @@ protected:
*/
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
Init(ignoreXBL);
@ -170,6 +174,8 @@ protected:
// For certain optimizations, nsCSSFrameConstructor needs to know if the
// child list of the element that we're iterating matches its .childNodes.
bool mXBLInvolved;
const nsIContent* mOriginalContent;
};
/**
@ -187,12 +193,11 @@ public:
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
#ifdef DEBUG
@ -211,11 +216,10 @@ public:
// Seeks the given node in children of a parent element, starting from
// the current iterator's position, and sets the iterator at the given child
// node if it was found.
bool Seek(nsIContent* aChildToFind);
bool Seek(const nsIContent* aChildToFind);
nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
const nsIContent* Parent() const { return mOriginalContent; }
enum IteratorPhase
{
@ -233,8 +237,6 @@ private:
void AppendNativeAnonymousChildren();
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
const nsIContent* mOriginalContent;
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
@ -256,10 +258,11 @@ private:
/**
* StyleChildrenIterator traverses the children of the element from the
* perspective of the style system, particularly the children we need to traverse
* during restyle. This is identical to AllChildrenIterator with eAllChildren,
* _except_ that we detect and skip any native anonymous children that are used
* to implement pseudo-elements (since the style system needs to cascade those
* using different algorithms).
* during restyle. This is identical to AllChildrenIterator with
* (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
* detect and skip any native anonymous children that are used to implement
* pseudo-elements (since the style system needs to cascade those using
* different algorithms).
*
* Note: it assumes that no mutation of the DOM or frame tree takes place during
* iteration, and will break horribly if that is not true.
@ -267,7 +270,9 @@ private:
class StyleChildrenIterator : private AllChildrenIterator {
public:
explicit StyleChildrenIterator(const nsIContent* aContent)
: AllChildrenIterator(aContent, nsIContent::eAllChildren)
: AllChildrenIterator(aContent,
nsIContent::eAllChildren |
nsIContent::eSkipDocumentLevelNativeAnonymousContent)
{
MOZ_COUNT_CTOR(StyleChildrenIterator);
}

View file

@ -7,6 +7,7 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
#include "jsfriendapi.h"
namespace mozilla {
namespace dom {

View file

@ -10,6 +10,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ChromeUtilsBinding.h"
#include "mozilla/dom/ThreadSafeChromeUtilsBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {

View file

@ -11,7 +11,9 @@
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/DocGroup.h"
#include "nsIParserService.h"
#include "mozilla/dom/Promise.h"
#include "nsContentUtils.h"
#include "nsHTMLTags.h"
#include "jsapi.h"
namespace mozilla {
@ -291,7 +293,6 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
nsWeakPtr* elem = unresolved->AppendElement();
*elem = do_GetWeakReference(aElement);
aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
return;
}
@ -414,19 +415,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback));
}
void
CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype)
{
mozilla::dom::CustomElementDefinition* definition =
mCustomDefinitions.GetWeak(aAtom);
if (definition) {
aPrototype.set(definition->mPrototype);
} else {
aPrototype.set(nullptr);
}
}
void
CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey,
CustomElementDefinition* aDefinition,
@ -466,6 +454,12 @@ nsISupports* CustomElementRegistry::GetParentObject() const
return mWindow;
}
DocGroup*
CustomElementRegistry::GetDocGroup() const
{
return mWindow ? mWindow->GetDocGroup() : nullptr;
}
static const char* kLifeCycleCallbackNames[] = {
"connectedCallback",
"disconnectedCallback",
@ -588,14 +582,8 @@ CustomElementRegistry::Define(const nsAString& aName,
return;
}
nsIParserService* ps = nsContentUtils::GetParserService();
if (!ps) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
// bgsound and multicol are unknown html element.
int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
tag == eHTMLTag_multicol) {
@ -630,9 +618,9 @@ CustomElementRegistry::Define(const nsAString& aName,
*/
JSAutoCompartment ac(cx, constructor);
JS::Rooted<JS::Value> prototypev(cx);
// The .prototype on the constructor passed from document.registerElement
// is the "expando" of a wrapper. So we should get it from wrapper instead
// instead of underlying object.
// The .prototype on the constructor passed could be an "expando" of a
// wrapper. So we should get it from wrapper instead of the underlying
// object.
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
aRv.StealExceptionFromJSContext(cx);
return;
@ -878,8 +866,6 @@ CustomElementRegistry::Upgrade(Element* aElement,
CustomElementDefinition* aDefinition,
ErrorResult& aRv)
{
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
MOZ_ASSERT(data, "CustomElementData should exist");

View file

@ -27,6 +27,7 @@ struct CustomElementData;
struct ElementDefinitionOptions;
class CallbackFunction;
class CustomElementReaction;
class DocGroup;
class Function;
class Promise;
@ -423,9 +424,6 @@ public:
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
CustomElementDefinition* aDefinition);
void GetCustomPrototype(nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype);
/**
* Upgrade an element.
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
@ -434,8 +432,7 @@ public:
/**
* Registers an unresolved custom element that is a candidate for
* upgrade when the definition is registered via registerElement.
* |aTypeName| is the name of the custom element type, if it is not
* upgrade. |aTypeName| is the name of the custom element type, if it is not
* provided, then element name is used. |aTypeName| should be provided
* when registering a custom element that extends an existing
* element. e.g. <button is="x-button">.
@ -472,8 +469,8 @@ private:
js::SystemAllocPolicy> ConstructorMap;
// Hashtable for custom element definitions in web components.
// Custom prototypes are stored in the compartment where
// registerElement was called.
// Custom prototypes are stored in the compartment where definition was
// defined.
DefinitionMap mCustomDefinitions;
// Hashtable for looking up definitions by using constructor as key.
@ -517,6 +514,8 @@ private:
public:
nsISupports* GetParentObject() const;
DocGroup* GetDocGroup() const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void Define(const nsAString& aName, Function& aFunctionConstructor,

View file

@ -728,7 +728,7 @@ WalkDescendantsResetAutoDirection(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
if (child->HasDirAuto()) {
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
@ -791,7 +791,7 @@ WalkDescendantsClearAncestorDirAuto(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
if (child->HasDirAuto()) {
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}

View file

@ -1,3 +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/. */
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/TabGroup.h"
#include "mozilla/Telemetry.h"
@ -6,10 +10,14 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIDocShell.h"
#include "nsDOMMutationObserver.h"
#include "nsNetCID.h"
namespace mozilla {
namespace dom {
AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
/* static */ void
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
{
@ -54,5 +62,23 @@ DocGroup::~DocGroup()
NS_IMPL_ISUPPORTS(DocGroup, nsISupports)
void
DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
{
if (mSignalSlotList.Contains(aSlot)) {
return;
}
mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
if (!sPendingDocGroups) {
// Queue a mutation observer compound microtask.
nsDOMMutationObserver::QueueMutationObserverMicroTask();
sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
}
sPendingDocGroups->AppendElement(this);
}
}
}

View file

@ -15,6 +15,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/HTMLSlotElement.h"
namespace mozilla {
namespace dom {
@ -73,6 +74,23 @@ public:
return mDocuments.end();
}
// Append aSlot to the list of signal slot list, if it's not in it already
// list, and queue a mutation observer microtask.
void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
{
return mSignalSlotList;
}
void ClearSignalSlotList()
{
mSignalSlotList.Clear();
}
// List of DocGroups that has non-empty signal slot list.
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
private:
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
~DocGroup();
@ -81,6 +99,7 @@ private:
RefPtr<TabGroup> mTabGroup;
nsTArray<nsIDocument*> mDocuments;
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
};
} // namespace dom

View file

@ -125,6 +125,8 @@ DocumentFragment::Constructor(const GlobalObject& aGlobal,
return window->GetDoc()->CreateDocumentFragment();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
// QueryInterface implementation for DocumentFragment
NS_INTERFACE_MAP_BEGIN(DocumentFragment)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY

View file

@ -43,6 +43,7 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
// interface nsIDOMNode
NS_FORWARD_NSIDOMNODE_TO_NSINODE
@ -121,15 +122,9 @@ public:
return nullptr;
}
nsIContent* GetHost() const
{
return mHost;
}
Element* GetHost() const { return mHost; }
void SetHost(nsIContent* aHost)
{
mHost = aHost;
}
void SetHost(Element* aHost) { mHost = aHost; }
static already_AddRefed<DocumentFragment>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
@ -145,7 +140,7 @@ protected:
}
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
nsIContent* mHost; // Weak
nsCOMPtr<Element> mHost;
};
} // namespace dom

View file

@ -166,8 +166,7 @@ nsIContent::DoGetID() const
const nsAttrValue*
Element::DoGetClasses() const
{
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
MOZ_ASSERT(MayHaveClass(), "Unexpected call");
if (IsSVGElement()) {
const nsAttrValue* animClass =
static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
@ -470,50 +469,11 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
JSObject*
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
JS::Rooted<JSObject*> customProto(aCx);
if (!givenProto) {
// Custom element prototype swizzling.
CustomElementData* data = GetCustomElementData();
if (data) {
// If this is a registered custom element then fix the prototype.
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
data->GetCustomElementType(), &customProto);
if (customProto &&
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
// The custom element prototype could be in different compartment.
if (!JS_WrapObject(aCx, &customProto)) {
return nullptr;
}
// Just go ahead and create with the right proto up front. Set
// customProto to null to flag that we don't need to do any post-facto
// proto fixups here.
givenProto = customProto;
customProto = nullptr;
}
}
}
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
if (!obj) {
return nullptr;
}
if (customProto) {
// We want to set the custom prototype in the compartment where it was
// registered. In the case that |obj| and |prototype| are in different
// compartments, this will set the prototype on the |obj|'s wrapper and
// thus only visible in the wrapper's compartment, since we know obj's
// principal does not subsume customProto's in this case.
JSAutoCompartment ac(aCx, customProto);
JS::Rooted<JSObject*> wrappedObj(aCx, obj);
if (!JS_WrapObject(aCx, &wrappedObj) ||
!JS_SetPrototype(aCx, wrappedObj, customProto)) {
return nullptr;
}
}
nsIDocument* doc;
if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
doc = OwnerDoc();
@ -1093,9 +1053,102 @@ Element::RemoveFromIdTable()
}
}
void
Element::SetSlot(const nsAString& aName, ErrorResult& aError)
{
aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
}
void
Element::GetSlot(nsAString& aName)
{
GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
}
// https://dom.spec.whatwg.org/#dom-element-shadowroot
ShadowRoot*
Element::GetShadowRootByMode() const
{
/**
* 1. Let shadow be context objects shadow root.
* 2. If shadow is null or its mode is "closed", then return null.
*/
ShadowRoot* shadowRoot = GetShadowRoot();
if (!shadowRoot || shadowRoot->IsClosed()) {
return nullptr;
}
/**
* 3. Return shadow.
*/
return shadowRoot;
}
// https://dom.spec.whatwg.org/#dom-element-attachshadow
already_AddRefed<ShadowRoot>
Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
{
/**
* 1. If context objects namespace is not the HTML namespace,
* then throw a "NotSupportedError" DOMException.
*/
if (!IsHTMLElement()) {
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
/**
* 2. If context objects local name is not
* a valid custom element name, "article", "aside", "blockquote",
* "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
* "header", "main" "nav", "p", "section", or "span",
* then throw a "NotSupportedError" DOMException.
*/
nsIAtom* nameAtom = NodeInfo()->NameAtom();
if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
nameAtom == nsGkAtoms::article ||
nameAtom == nsGkAtoms::aside ||
nameAtom == nsGkAtoms::blockquote ||
nameAtom == nsGkAtoms::body ||
nameAtom == nsGkAtoms::div ||
nameAtom == nsGkAtoms::footer ||
nameAtom == nsGkAtoms::h1 ||
nameAtom == nsGkAtoms::h2 ||
nameAtom == nsGkAtoms::h3 ||
nameAtom == nsGkAtoms::h4 ||
nameAtom == nsGkAtoms::h5 ||
nameAtom == nsGkAtoms::h6 ||
nameAtom == nsGkAtoms::header ||
nameAtom == nsGkAtoms::main ||
nameAtom == nsGkAtoms::nav ||
nameAtom == nsGkAtoms::p ||
nameAtom == nsGkAtoms::section ||
nameAtom == nsGkAtoms::span)) {
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
return AttachShadowInternal(aInit.mMode == ShadowRootMode::Closed, aError);
}
already_AddRefed<ShadowRoot>
Element::CreateShadowRoot(ErrorResult& aError)
{
return AttachShadowInternal(false, aError);
}
already_AddRefed<ShadowRoot>
Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
{
/**
* 3. If context object is a shadow host, then throw
* an "InvalidStateError" DOMException.
*/
if (GetShadowRoot()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
nsAutoScriptBlocker scriptBlocker;
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
@ -1113,12 +1166,9 @@ Element::CreateShadowRoot(ErrorResult& aError)
return nullptr;
}
nsIDocument* doc = GetComposedDoc();
nsIContent* destroyedFramesFor = nullptr;
if (doc) {
nsIPresShell* shell = doc->GetShell();
if (shell) {
shell->DestroyFramesFor(this, &destroyedFramesFor);
if (nsIDocument* doc = GetComposedDoc()) {
if (nsIPresShell* shell = doc->GetShell()) {
shell->DestroyFramesForAndRestyle(this);
MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
}
}
@ -1130,29 +1180,20 @@ Element::CreateShadowRoot(ErrorResult& aError)
// Calling SetPrototypeBinding takes ownership of protoBinding.
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
protoBinding);
/**
* 4. Let shadow be a new shadow root whose node document is
* context objects node document, host is context object,
* and mode is inits mode.
*/
RefPtr<ShadowRoot> shadowRoot =
new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
// Replace the old ShadowRoot with the new one and let the old
// ShadowRoot know about the younger ShadowRoot because the old
// ShadowRoot is projected into the younger ShadowRoot's shadow
// insertion point (if it exists).
ShadowRoot* olderShadow = GetShadowRoot();
/**
* 5. Set context objects shadow root to shadow.
*/
SetShadowRoot(shadowRoot);
if (olderShadow) {
olderShadow->SetYoungerShadow(shadowRoot);
// Unbind children of older shadow root because they
// are no longer in the composed tree.
for (nsIContent* child = olderShadow->GetFirstChild(); child;
child = child->GetNextSibling()) {
child->UnbindFromTree(true, false);
}
olderShadow->SetIsComposedDocParticipant(false);
}
// xblBinding takes ownership of docInfo.
RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
@ -1161,96 +1202,12 @@ Element::CreateShadowRoot(ErrorResult& aError)
SetXBLBinding(xblBinding);
// Recreate the frame for the bound content because binding a ShadowRoot
// changes how things are rendered.
if (doc) {
MOZ_ASSERT(doc == GetComposedDoc());
nsIPresShell* shell = doc->GetShell();
if (shell) {
shell->CreateFramesFor(destroyedFramesFor);
}
}
/**
* 6. Return shadow.
*/
return shadowRoot.forget();
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DestinationInsertionPointList, mParent,
mDestinationPoints)
NS_INTERFACE_TABLE_HEAD(DestinationInsertionPointList)
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(DestinationInsertionPointList, nsINodeList, nsIDOMNodeList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DestinationInsertionPointList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DestinationInsertionPointList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DestinationInsertionPointList)
DestinationInsertionPointList::DestinationInsertionPointList(Element* aElement)
: mParent(aElement)
{
nsTArray<nsIContent*>* destPoints = aElement->GetExistingDestInsertionPoints();
if (destPoints) {
for (uint32_t i = 0; i < destPoints->Length(); i++) {
mDestinationPoints.AppendElement(destPoints->ElementAt(i));
}
}
}
DestinationInsertionPointList::~DestinationInsertionPointList()
{
}
nsIContent*
DestinationInsertionPointList::Item(uint32_t aIndex)
{
return mDestinationPoints.SafeElementAt(aIndex);
}
NS_IMETHODIMP
DestinationInsertionPointList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
{
nsIContent* item = Item(aIndex);
if (!item) {
return NS_ERROR_FAILURE;
}
return CallQueryInterface(item, aReturn);
}
uint32_t
DestinationInsertionPointList::Length() const
{
return mDestinationPoints.Length();
}
NS_IMETHODIMP
DestinationInsertionPointList::GetLength(uint32_t* aLength)
{
*aLength = Length();
return NS_OK;
}
int32_t
DestinationInsertionPointList::IndexOf(nsIContent* aContent)
{
return mDestinationPoints.IndexOf(aContent);
}
JSObject*
DestinationInsertionPointList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return NodeListBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<DestinationInsertionPointList>
Element::GetDestinationInsertionPoints()
{
RefPtr<DestinationInsertionPointList> list =
new DestinationInsertionPointList(this);
return list.forget();
}
void
Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
{
@ -2383,7 +2340,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
bool aNotify,
nsAttrValue& aOldValue,
uint8_t* aModType,
bool* aHasListeners)
bool* aHasListeners,
bool* aOldValueSet)
{
bool modification = false;
*aHasListeners = aNotify &&
@ -2391,6 +2349,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
*aOldValueSet = false;
// If we have no listeners and aNotify is false, we are almost certainly
// coming from the content sink and will almost certainly have no previous
// value. Even if we do, setting the value is cheap when we have no
@ -2414,6 +2374,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
// We have to serialize the value anyway in order to create the
// mutation event so there's no cost in doing it now.
aOldValue.SetToSerialized(*info.mValue);
*aOldValueSet = true;
}
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
@ -2433,10 +2394,12 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
uint8_t* aModType, bool* aHasListeners)
uint8_t* aModType, bool* aHasListeners,
bool* aOldValueSet)
{
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
aOldValue, aModType, aHasListeners)) {
aOldValue, aModType, aHasListeners,
aOldValueSet)) {
return false;
}
@ -2445,12 +2408,45 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
return true;
}
nsresult
Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
{
// Keep this in sync with SetAttr and SetParsedAttr below.
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
return NS_ERROR_FAILURE;
}
nsAttrValue value(aSingleClassName);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
// In principle, BeforeSetAttr should be called here if a node type
// existed that wanted to do something special for class, but there
// is no such node type, so calling SetMayHaveClass() directly.
SetMayHaveClass();
return SetAttrAndNotify(kNameSpaceID_None,
nsGkAtoms::_class,
nullptr, // prefix
nullptr, // old value
value,
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
false, // hasListeners
false, // notify
kCallAfterSetAttr,
document,
updateBatch);
}
nsresult
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
{
// Keep this in sync with SetParsedAttr below
// Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
// above.
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@ -2462,17 +2458,27 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
uint8_t modType;
bool hasListeners;
// We don't want to spend time preparsing class attributes if the value is not
// changing, so just init our nsAttrValueOrString with aValue for the
// OnlyNotifySameValueSet call.
nsAttrValueOrString value(aValue);
nsAttrValue oldValue;
bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
return NS_OK;
oldValue, &modType, &hasListeners, &oldValueSet)) {
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
nsAttrValue attrValue;
nsAttrValue* preparsedAttrValue;
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
attrValue.ParseAtomArray(aValue);
value.ResetToAttrValue(attrValue);
preparsedAttrValue = &attrValue;
} else {
preparsedAttrValue = nullptr;
}
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
@ -2481,21 +2487,23 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
// Hold a script blocker while calling ParseAttribute since that can call
// out to id-observers
nsAutoScriptBlocker scriptBlocker;
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
nsAttrValue attrValue;
if (preparsedAttrValue) {
attrValue.SwapValueWith(*preparsedAttrValue);
}
// Even the value was pre-parsed in BeforeSetAttr, we still need to call
// ParseAttribute because it can have side effects.
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (!preparsedAttrValue &&
!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
attrValue.SetTo(aValue);
}
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
PreIdMaybeChange(aNamespaceID, aName, &value);
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
oldValueSet ? &oldValue : nullptr,
attrValue, modType, hasListeners, aNotify,
kCallAfterSetAttr);
kCallAfterSetAttr, document, updateBatch);
}
nsresult
@ -2503,7 +2511,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
bool aNotify)
{
// Keep this in sync with SetAttr above
// Keep this in sync with SetAttr and SetSingleClassFromParser above
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@ -2518,41 +2526,46 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
bool hasListeners;
nsAttrValueOrString value(aParsedValue);
nsAttrValue oldValue;
bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
return NS_OK;
oldValue, &modType, &hasListeners, &oldValueSet)) {
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
&aParsedValue);
}
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
PreIdMaybeChange(aNamespaceID, aName, &value);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
oldValueSet ? &oldValue : nullptr,
aParsedValue, modType, hasListeners, aNotify,
kCallAfterSetAttr);
kCallAfterSetAttr, document, updateBatch);
}
nsresult
Element::SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValue& aOldValue,
const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
bool aCallAfterSetAttr)
bool aCallAfterSetAttr,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate&)
{
nsresult rv;
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
nsMutationGuard::DidMutate();
// Copy aParsedValue for later use since it will be lost when we call
@ -2564,6 +2577,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
bool hadValidDir = false;
bool hadDirAuto = false;
bool oldValueSet;
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::dir) {
@ -2574,8 +2588,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
// XXXbz Perhaps we should push up the attribute mapping function
// stuff to Element?
if (!IsAttributeMapped(aName) ||
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
!SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) {
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
}
}
else {
@ -2584,24 +2598,34 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
aNamespaceID,
nsIDOMNode::ATTRIBUTE_NODE);
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
}
// If the old value owns its own data, we know it is OK to keep using it.
const nsAttrValue* oldValue =
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
NS_ENSURE_SUCCESS(rv, rv);
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
// If the old value owns its own data, we know it is OK to keep using it.
// oldValue will be null if there was no previously set value
const nsAttrValue* oldValue;
if (aParsedValue.StoresOwnData()) {
if (oldValueSet) {
oldValue = &aParsedValue;
} else {
oldValue = nullptr;
}
} else {
// No need to conditionally assign null here. If there was no previously
// set value for the attribute, aOldValue will already be null.
oldValue = aOldValue;
}
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
RefPtr<nsXBLBinding> binding = GetXBLBinding();
if (binding) {
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
}
}
UpdateState(aNotify);
if (CustomElementRegistry::IsCustomElementEnabled()) {
if (CustomElementData* data = GetCustomElementData()) {
if (CustomElementDefinition* definition =
@ -2611,7 +2635,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
"AttributeChanged callback should fire only if "
"custom element state is custom");
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
nsCOMPtr<nsIAtom> oldValueAtom;
if (oldValue) {
oldValueAtom = oldValue->GetAsAtom();
} else {
// If there is no old value, get the value of the uninitialized attribute
// that was swapped with aParsedValue.
oldValueAtom = aParsedValue.GetAsAtom();
}
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
@ -2631,7 +2662,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
}
if (aCallAfterSetAttr) {
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
@ -2640,12 +2672,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
}
}
UpdateState(aNotify);
if (aNotify) {
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
// Callers only compute aOldValue under certain conditions which may not
// be triggered by all nsIMutationObservers.
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
oldValue == &aParsedValue ? &aParsedValue : nullptr);
aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
}
if (aFireMutation) {
@ -2663,7 +2697,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = NS_Atomize(newValue);
}
if (!oldValue->IsEmptyString()) {
if (oldValue && !oldValue->IsEmptyString()) {
mutation.mPrevAttrValue = oldValue->GetAsAtom();
}
mutation.mAttrChange = aModType;
@ -2675,25 +2709,6 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
return NS_OK;
}
nsresult
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsAttrValueOrString* aValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::_class) {
// aValue->GetAttrValue will only be non-null here when this is called
// via Element::SetParsedAttr. This shouldn't happen for "class", but
// this will handle it.
if (aValue && !aValue->GetAttrValue()) {
nsAttrValue attr;
attr.ParseAtomArray(aValue->String());
aValue->TakeParsedValue(attr);
}
}
}
return NS_OK;
}
bool
Element::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
@ -2701,22 +2716,16 @@ Element::ParseAttribute(int32_t aNamespaceID,
nsAttrValue& aResult)
{
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::_class) {
SetFlags(NODE_MAY_HAVE_CLASS);
// Result should have been preparsed above.
return true;
}
MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
"The class attribute should be preparsed and therefore should "
"never be passed to Element::ParseAttribute");
if (aAttribute == nsGkAtoms::id) {
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.
RemoveFromIdTable();
if (aValue.IsEmpty()) {
ClearHasID();
return false;
}
aResult.ParseAtom(aValue);
SetHasID();
AddToIdTable(aResult.GetAtomValue());
return true;
}
}
@ -2725,15 +2734,71 @@ Element::ParseAttribute(int32_t aNamespaceID,
}
bool
Element::SetMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
nsresult* aRetval)
Element::SetAndSwapMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
bool* aValueWasSet,
nsresult* aRetval)
{
*aRetval = NS_OK;
return false;
}
nsresult
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::_class) {
if (aValue) {
// Note: This flag is asymmetrical. It is never unset and isn't exact.
// If it is ever made to be exact, we probably need to handle this
// similarly to how ids are handled in PreIdMaybeChange and
// PostIdMaybeChange.
// Note that SetSingleClassFromParser inlines BeforeSetAttr and
// calls SetMayHaveClass directly. Making a subclass take action
// on the class attribute in a BeforeSetAttr override would
// require revising SetSingleClassFromParser.
SetMayHaveClass();
}
}
}
return NS_OK;
}
void
Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue)
{
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
return;
}
RemoveFromIdTable();
return;
}
void
Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue)
{
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
return;
}
// id="" means that the element has no id, not that it has an empty
// string as the id.
if (aValue && !aValue->IsEmptyString()) {
SetHasID();
AddToIdTable(aValue->GetAtomValue());
} else {
ClearHasID();
}
return;
}
EventListenerManager*
Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer)
@ -2810,9 +2875,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
return NS_OK;
}
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
nsIDocument *document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
@ -2822,11 +2884,16 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nullptr);
}
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
bool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
PreIdMaybeChange(aNameSpaceID, aName, nullptr);
// Grab the attr node if needed before we remove it from the attr map
RefPtr<Attr> attrNode;
if (hasMutationListeners) {
@ -2845,12 +2912,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
// react to unexpected attribute changes.
nsMutationGuard::DidMutate();
if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
// Have to do this before clearing flag. See RemoveFromIdTable
RemoveFromIdTable();
ClearHasID();
}
bool hadValidDir = false;
bool hadDirAuto = false;
@ -2863,6 +2924,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
NS_ENSURE_SUCCESS(rv, rv);
PostIdMaybeChange(aNameSpaceID, aName, nullptr);
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
RefPtr<nsXBLBinding> binding = GetXBLBinding();
if (binding) {
@ -2870,8 +2933,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
UpdateState(aNotify);
if (CustomElementRegistry::IsCustomElementEnabled()) {
if (CustomElementData* data = GetCustomElementData()) {
if (CustomElementDefinition* definition =
@ -2898,6 +2959,11 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
UpdateState(aNotify);
if (aNotify) {
// We can always pass oldValue here since there is no new value which could
// have corrupted it.
@ -2905,9 +2971,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIDOMMutationEvent::REMOVAL, &oldValue);
}
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
}
@ -3129,7 +3192,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
}
nsresult
Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
{
// Optimisation: return early if this event doesn't interest us.
// IMPORTANT: this switch and the switch below it must be kept in sync!
@ -3151,8 +3214,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
nsresult rv = NS_OK;
// We do the status bar updates in PreHandleEvent so that the status bar gets
// updated even if the event is consumed before we have a chance to set it.
// We do the status bar updates in GetEventTargetParent so that the status bar
// gets updated even if the event is consumed before we have a chance to set
// it.
switch (aVisitor.mEvent->mMessage) {
// Set the status bar similarly for mouseover and focus
case eMouseOver:

View file

@ -41,6 +41,7 @@
#include "Units.h"
#include "DOMIntersectionObserver.h"
class mozAutoDocUpdate;
class nsIFrame;
class nsIDOMMozNamedAttrMap;
class nsIURI;
@ -143,7 +144,6 @@ class CustomElementRegistry;
class Link;
class DOMRect;
class DOMRectList;
class DestinationInsertionPointList;
class Grid;
// IID for the dom::Element interface
@ -254,6 +254,23 @@ public:
*/
void ClearStyleStateLocks();
/**
* Accessors for the state of our dir attribute.
*/
bool HasDirAuto() const
{
return State().HasState(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
}
/**
* Elements with dir="rtl" or dir="ltr".
*/
bool HasFixedDir() const
{
return State().HasAtLeastOneOfStates(NS_EVENT_STATE_DIR_ATTR_LTR |
NS_EVENT_STATE_DIR_ATTR_RTL);
}
/**
* Get the inline style declaration, if any, for this element.
*/
@ -379,17 +396,10 @@ public:
bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
// The bdi element defaults to dir=auto if it has no dir attribute set.
// Other elements will only have dir=auto if they have an explicit dir=auto,
// which will mean that HasValidDir() returns true but HasFixedDir() returns
// false
inline bool HasDirAuto() const {
return (!HasFixedDir() &&
(HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
}
Directionality GetComputedDirectionality() const;
inline Element* GetFlattenedTreeParentElementForStyle() const;
/**
* Gets the custom element data used by web components custom element.
* Custom element data is created at the first attempt to enqueue a callback.
@ -460,6 +470,9 @@ protected:
mState &= ~aStates;
}
already_AddRefed<ShadowRoot> AttachShadowInternal(bool aClosed,
ErrorResult& aError);
private:
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
// set our state
@ -498,6 +511,16 @@ protected:
RemoveStatesSilently(aStates);
NotifyStateChange(aStates);
}
virtual void ToggleStates(EventStates aStates, bool aNotify)
{
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
"Should only be removing externally-managed states here");
mState ^= aStates;
if (aNotify) {
NotifyStateChange(aStates);
}
}
public:
virtual void UpdateEditableState(bool aNotify) override;
@ -520,6 +543,7 @@ public:
already_AddRefed<mozilla::dom::NodeInfo>
GetExistingAttrNameFromQName(const nsAString& aStr) const;
MOZ_ALWAYS_INLINE // Avoid a crashy hook from Avast 10 Beta (Bug 1058131)
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, bool aNotify)
{
@ -534,25 +558,57 @@ public:
* values will not actually be compared if we aren't notifying and we don't
* have mutation listeners (in which case it's cheap to just return false
* and let the caller go ahead and set the value).
* @param aOldValue Set to the old value of the attribute, but only if there
* are event listeners. If set, the type of aOldValue will be either
* @param aOldValue [out] Set to the old value of the attribute, but only if
* there are event listeners. If set, the type of aOldValue will be either
* nsAttrValue::eString or nsAttrValue::eAtom.
* @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
* @param aHasListeners Set to true if there are mutation event listeners
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
* @param aHasListeners [out] Set to true if there are mutation event
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
* @param aOldValueSet [out] Indicates whether an old attribute value has been
* stored in aOldValue. The bool will be set to true if a value was stored.
*/
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
uint8_t* aModType, bool* aHasListeners);
uint8_t* aModType, bool* aHasListeners,
bool* aOldValueSet);
/**
* Notifies mutation listeners if aNotify is true, there are mutation
* listeners, and the attribute value is changing.
*
* @param aNamespaceID The namespace of the attribute
* @param aName The local name of the attribute
* @param aPrefix The prefix of the attribute
* @param aValue The value that the attribute is being changed to
* @param aNotify If true, mutation listeners will be notified if they exist
* and the attribute value is changing
* @param aOldValue [out] Set to the old value of the attribute, but only if
* there are event listeners. If set, the type of aOldValue will be either
* nsAttrValue::eString or nsAttrValue::eAtom.
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
* @param aHasListeners [out] Set to true if there are mutation event
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
* @param aOldValueSet [out] Indicates whether an old attribute value has been
* stored in aOldValue. The bool will be set to true if a value was stored.
*/
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
uint8_t* aModType, bool* aHasListeners);
uint8_t* aModType, bool* aHasListeners,
bool* aOldValueSet);
/**
* Sets the class attribute to a value that contains no whitespace.
* Assumes that we are not notifying and that the attribute hasn't been
* set previously.
*/
nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify) override;
@ -589,7 +645,7 @@ public:
* guaranteed (e.g. we could have class="").
*/
const nsAttrValue* GetClasses() const {
if (HasFlag(NODE_MAY_HAVE_CLASS)) {
if (MayHaveClass()) {
return DoGetClasses();
}
return nullptr;
@ -761,6 +817,25 @@ public:
already_AddRefed<nsIHTMLCollection>
GetElementsByClassName(const nsAString& aClassNames);
CSSPseudoElementType GetPseudoElementType() const {
if (!HasProperties()) {
return CSSPseudoElementType::NotPseudo;
}
nsresult rv = NS_OK;
auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
return CSSPseudoElementType::NotPseudo;
}
return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
}
void SetPseudoElementType(CSSPseudoElementType aPseudo) {
static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
"Need to be able to store this in a void*");
MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
}
private:
/**
* Implement the algorithm specified at
@ -848,8 +923,15 @@ public:
already_AddRefed<DOMRectList> GetClientRects();
already_AddRefed<DOMRect> GetBoundingClientRect();
// Shadow DOM v1
already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
ErrorResult& aError);
ShadowRoot* GetShadowRootByMode() const;
void SetSlot(const nsAString& aName, ErrorResult& aError);
void GetSlot(nsAString& aName);
// [deprecated] Shadow DOM v0
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
ShadowRoot *FastGetShadowRoot() const
{
@ -1239,7 +1321,10 @@ protected:
* its current value) is !StoresOwnData() --- in which
* case the current value is probably already useless.
* If the current value is StoresOwnData() (or absent),
* aOldValue will not be used.
* aOldValue will not be used. aOldValue will only be set
* in certain circumstances (there are mutation
* listeners, element is a custom element, attribute was
* not previously unset). Otherwise it will be null.
* @param aParsedValue parsed new value of attribute. Replaced by the
* old value of the attribute. This old value is only
* useful if either it or the new value is StoresOwnData.
@ -1248,16 +1333,19 @@ protected:
* @param aFireMutation should mutation-events be fired?
* @param aNotify should we notify document-observers?
* @param aCallAfterSetAttr should we call AfterSetAttr?
* @param aComposedDocument The current composed document of the element.
*/
nsresult SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValue& aOldValue,
const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
bool aCallAfterSetAttr);
bool aCallAfterSetAttr,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate& aGuard);
/**
* Scroll to a new position using behavior evaluated from CSS and
@ -1295,14 +1383,21 @@ protected:
*
* @param aDocument the current document of this node (an optimization)
* @param aName the name of the attribute
* @param aValue the nsAttrValue to set
* @param aValue the nsAttrValue to set. Will be swapped with the existing
* value of the attribute if the attribute already exists.
* @param [out] aValueWasSet If the attribute was not set previously,
* aValue will be swapped with an empty attribute
* and aValueWasSet will be set to false. Otherwise,
* aValueWasSet will be set to true and aValue will
* contain the previous value set.
* @param [out] aRetval the nsresult status of the operation, if any.
* @return true if the setting was attempted, false otherwise.
*/
virtual bool SetMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
nsresult* aRetval);
virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
bool* aValueWasSet,
nsresult* aRetval);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
@ -1315,33 +1410,92 @@ protected:
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to represented as either a string or
* a parsed nsAttrValue. Alternatively, if the attr is being removed it
* will be null. BeforeSetAttr is allowed to modify aValue by parsing
* the string to an nsAttrValue (to avoid having to reparse it in
* ParseAttribute).
* will be null.
* @param aNotify Whether we plan to notify document observers.
*/
// Note that this is inlined so that when subclasses call it it gets
// inlined. Those calls don't go through a vtable.
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsAttrValueOrString* aValue,
const nsAttrValueOrString* aValue,
bool aNotify);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
* deal with attribute sets. This will only be called after we have called
* SetAndTakeAttr and AttributeChanged (that is, after we have actually set
* the attr). It will always be called under a scriptblocker.
* SetAndSwapAttr (that is, after we have actually set the attr). It will
* always be called under a scriptblocker.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to. If null, the attr is being
* removed.
* @param aOldValue the value that the attribute had previously. If null,
* the attr was not previously set. This argument may not have the
* correct value for SVG elements, or other cases in which the
* attribute value doesn't store its own data
* @param aNotify Whether we plan to notify document observers.
*/
// Note that this is inlined so that when subclasses call it it gets
// inlined. Those calls don't go through a vtable.
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
const nsAttrValue* aValue,
const nsAttrValue* aOldValue, bool aNotify)
{
return NS_OK;
}
/**
* This function shall be called just before the id attribute changes. It will
* be called after BeforeSetAttr. If the attribute being changed is not the id
* attribute, this function does nothing. Otherwise, it will remove the old id
* from the document's id cache.
*
* This must happen after BeforeSetAttr (rather than during) because the
* the subclasses' calls to BeforeSetAttr may notify on state changes. If they
* incorrectly determine whether the element had an id, the element may not be
* restyled properly.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the new id value. Will be null if the id is being unset.
*/
void PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue);
/**
* This function shall be called just after the id attribute changes. It will
* be called before AfterSetAttr. If the attribute being changed is not the id
* attribute, this function does nothing. Otherwise, it will add the new id to
* the document's id cache and properly set the ElementHasID flag.
*
* This must happen before AfterSetAttr (rather than during) because the
* the subclasses' calls to AfterSetAttr may notify on state changes. If they
* incorrectly determine whether the element now has an id, the element may
* not be restyled properly.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the new id value. Will be null if the id is being unset.
*/
void PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValue* aValue);
/**
* Usually, setting an attribute to the value that it already has results in
* no action. However, in some cases, setting an attribute to its current
* value should have the effect of, for example, forcing a reload of
* network data. To address that, this function will be called in this
* situation to allow the handling of such a case.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to represented as either a string or
* a parsed nsAttrValue.
* @param aNotify Whether we plan to notify document observers.
*/
// Note that this is inlined so that when subclasses call it it gets
// inlined. Those calls don't go through a vtable.
virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString& aValue,
bool aNotify)
{
return NS_OK;
}
@ -1400,7 +1554,7 @@ protected:
/**
* Handle status bar updates before they can be cancelled.
*/
nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
/**
* Handle default actions for link event if the event isn't consumed yet.
@ -1460,30 +1614,6 @@ private:
nsCOMPtr<nsIDocument> mDoc;
};
class DestinationInsertionPointList : public nsINodeList
{
public:
explicit DestinationInsertionPointList(Element* aElement);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DestinationInsertionPointList)
// nsIDOMNodeList
NS_DECL_NSIDOMNODELIST
// nsINodeList
virtual nsIContent* Item(uint32_t aIndex) override;
virtual int32_t IndexOf(nsIContent* aContent) override;
virtual nsINode* GetParentObject() override { return mParent; }
virtual uint32_t Length() const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual ~DestinationInsertionPointList();
RefPtr<Element> mParent;
nsCOMArray<nsIContent> mDestinationPoints;
};
NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
inline bool

View file

@ -25,6 +25,17 @@ Element::UnregisterActivityObserver()
OwnerDoc()->UnregisterActivityObserver(this);
}
inline Element*
Element::GetFlattenedTreeParentElementForStyle() const
{
nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
return parentNode->AsElement();
}
return nullptr;
}
} // namespace dom
} // namespace mozilla

View file

@ -123,6 +123,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "nsStyledElement.h"
@ -151,8 +152,56 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
return nullptr;
}
// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
HTMLSlotElement*
nsIContent::GetAssignedSlotByMode() const
{
/**
* Get slotable's assigned slot for the result of
* find a slot with open flag UNSET [1].
*
* [1] https://dom.spec.whatwg.org/#assign-a-slot
*/
HTMLSlotElement* slot = GetAssignedSlot();
if (!slot) {
return nullptr;
}
MOZ_ASSERT(GetParent());
MOZ_ASSERT(GetParent()->GetShadowRoot());
/**
* Additional check for open flag SET:
* If slotables parents shadow root's mode is not "open",
* then return null.
*/
if (GetParent()->GetShadowRoot()->IsClosed()) {
return nullptr;
}
return slot;
}
nsINode*
nsIContent::GetFlattenedTreeParentNodeInternal() const
nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const
{
if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) {
return assignedSlot;
}
HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent());
if (!parentSlot) {
return nullptr;
}
// If this is not an unassigned node, then it must be a fallback content.
MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty());
return parentSlot;
}
nsINode*
nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
@ -161,18 +210,51 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const
}
nsIContent* parent = parentNode->AsContent();
if (aType == eForStyle &&
IsRootOfNativeAnonymousSubtree() &&
OwnerDoc()->GetRootElement() == parent) {
// When getting the flattened tree parent for style, we return null
// for any "document level" native anonymous content subtree root.
// This is NAC generated by an ancestor frame of the document element's
// primary frame, and includes scrollbar elements created by the root
// scroll frame, and the "custom content container" and accessible caret
// generated by the nsCanvasFrame. We distinguish document level NAC
// from NAC generated by the root element's primary frame below.
nsIFrame* parentFrame = parent->GetPrimaryFrame();
if (!parentFrame) {
// If the root element has no primary frame, it means it can't have
// generated any NAC itself. Thus any NAC we have here must have
// been generated by an ancestor frame.
//
// If we are in here, then either the root element is display:none, or
// we are in the middle of constructing the root of the frame tree and
// we are trying to eagerly restyle document level NAC in
// nsCSSFrameConstructor::GetAnonymousContent before the root
// element's frame has been constructed.
return nullptr;
}
nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
if (!creator) {
// If the root element does have a frame, but does not implement
// nsIAnonymousContentCreator, then this must be document level NAC.
return nullptr;
}
AutoTArray<nsIContent*, 8> elements;
creator->AppendAnonymousContentTo(elements, 0);
if (!elements.Contains(this)) {
// If the root element does have a frame, and also does implement
// nsIAnonymousContentCreator, but didn't create this node, then
// it must be document level NAC.
return nullptr;
}
}
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
// This node is distributed to insertion points, thus we
// need to consult the destination insertion points list to
// figure out where this node was inserted in the flattened tree.
// It may be the case that |parent| distributes its children
// but the child does not match any insertion points, thus
// the flattened tree parent is nullptr.
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
destInsertionPoints->LastElement()->GetParent() : nullptr;
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
return GetFlattenedTreeParentForMaybeAssignedNode();
}
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
nsIContent* insertionParent = GetXBLInsertionParent();
if (insertionParent) {
parent = insertionParent;
@ -575,6 +657,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get()));
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding");
cb.NoteNativeChild(mExtendedSlots->mXBLBinding,
NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
@ -618,6 +703,7 @@ FragmentOrElement::nsDOMSlots::Unlink()
mExtendedSlots->mLabelsList = nullptr;
mExtendedSlots->mShadowRoot = nullptr;
mExtendedSlots->mContainingShadow = nullptr;
mExtendedSlots->mAssignedSlot = nullptr;
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
mExtendedSlots->mXBLInsertionParent = nullptr;
if (mExtendedSlots->mCustomElementData) {
@ -718,7 +804,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
}
nsresult
nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
//FIXME! Document how this event retargeting works, Bug 329124.
aVisitor.mCanHandle = true;
@ -727,6 +813,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Don't propagate mouseover and mouseout events when mouse is moving
// inside chrome access only content.
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
aVisitor.mRootOfClosedTree = isAnonForEvents;
if ((aVisitor.mEvent->mMessage == eMouseOver ||
aVisitor.mEvent->mMessage == eMouseOut ||
aVisitor.mEvent->mMessage == ePointerOver ||
@ -738,7 +825,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
((this == aVisitor.mEvent->mOriginalTarget &&
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
nsCOMPtr<nsIContent> relatedTarget =
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
if (relatedTarget &&
relatedTarget->OwnerDoc() == OwnerDoc()) {
@ -748,7 +835,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsIContent* adjustedTarget =
Event::GetShadowRelatedTarget(this, relatedTarget);
if (this == adjustedTarget) {
aVisitor.mParentTarget = nullptr;
aVisitor.SetParentTarget(nullptr, false);
aVisitor.mCanHandle = false;
return NS_OK;
}
@ -805,7 +892,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
originalTarget->FindFirstNonChromeOnlyAccessContent())
? "" : "Wrong event propagation!?!\n");
#endif
aVisitor.mParentTarget = nullptr;
aVisitor.SetParentTarget(nullptr, false);
// Event should not propagate to non-anon content.
aVisitor.mCanHandle = isAnonForEvents;
return NS_OK;
@ -816,58 +903,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
nsIContent* parent = GetParent();
// Web components have a special event chain that need to account
// for destination insertion points where nodes have been distributed.
nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
if (destPoints && !destPoints->IsEmpty()) {
// Push destination insertion points to aVisitor.mDestInsertionPoints
// excluding shadow insertion points.
bool didPushNonShadowInsertionPoint = false;
for (uint32_t i = 0; i < destPoints->Length(); i++) {
nsIContent* point = destPoints->ElementAt(i);
if (!ShadowRoot::IsShadowInsertionPoint(point)) {
aVisitor.mDestInsertionPoints.AppendElement(point);
didPushNonShadowInsertionPoint = true;
}
}
// Next node in the event path is the final destination
// (non-shadow) insertion point that was pushed.
if (didPushNonShadowInsertionPoint) {
parent = aVisitor.mDestInsertionPoints.LastElement();
aVisitor.mDestInsertionPoints.SetLength(
aVisitor.mDestInsertionPoints.Length() - 1);
}
}
ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
if (thisShadowRoot) {
if (!aVisitor.mEvent->mFlags.mComposed) {
// If we do stop propagation, we still want to propagate
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
// The load event is special in that we don't ever propagate it
// to chrome.
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
? win->GetParentTarget() : nullptr;
aVisitor.mParentTarget = parentTarget;
return NS_OK;
}
if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
parent = aVisitor.mDestInsertionPoints.LastElement();
aVisitor.mDestInsertionPoints.SetLength(
aVisitor.mDestInsertionPoints.Length() - 1);
} else {
// The pool host for the youngest shadow root is shadow DOM host,
// for older shadow roots, it is the shadow insertion point
// where the shadow root is projected, nullptr if none exists.
parent = thisShadowRoot->GetPoolHost();
}
}
// Event parent is the assigned slot, if node is assigned, or node's parent
// otherwise.
HTMLSlotElement* slot = GetAssignedSlot();
nsIContent* parent = slot ? slot : GetParent();
// Event may need to be retargeted if this is the root of a native
// anonymous content subtree or event is dispatched somewhere inside XBL.
@ -905,11 +944,17 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
OwnerDoc()->GetWindow()) {
aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
} else if (parent) {
aVisitor.mParentTarget = parent;
aVisitor.SetParentTarget(parent, false);
if (slot) {
ShadowRoot* root = slot->GetContainingShadow();
if (root && root->IsClosed()) {
aVisitor.mParentIsSlotInClosedTree = true;
}
}
} else {
aVisitor.mParentTarget = GetComposedDoc();
aVisitor.SetParentTarget(GetComposedDoc(), false);
}
return NS_OK;
}
@ -1086,21 +1131,18 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
slots->mShadowRoot = aShadowRoot;
}
nsTArray<nsIContent*>&
FragmentOrElement::DestInsertionPoints()
{
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
return slots->mDestInsertionPoints;
}
nsTArray<nsIContent*>*
FragmentOrElement::GetExistingDestInsertionPoints() const
HTMLSlotElement*
FragmentOrElement::GetAssignedSlot() const
{
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
if (slots) {
return &slots->mDestInsertionPoints;
}
return nullptr;
return slots ? slots->mAssignedSlot.get() : nullptr;
}
void
FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
{
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
slots->mAssignedSlot = aSlot;
}
void
@ -2368,9 +2410,8 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
"on a non-Element is useless");
ShadowRoot* shadowRoot = GetShadowRoot();
while (shadowRoot) {
if (shadowRoot) {
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
shadowRoot = shadowRoot->GetOlderShadowRoot();
}
}

View file

@ -62,6 +62,7 @@ public:
// nsIWeakReference
NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
virtual bool IsAlive() const override { return mNode != nullptr; }
void NoticeNodeDestruction()
{
@ -154,9 +155,9 @@ public:
virtual void SetXBLBinding(nsXBLBinding* aBinding,
nsBindingManager* aOldBindingManager = nullptr) override;
virtual ShadowRoot *GetContainingShadow() const override;
virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
virtual void SetShadowRoot(ShadowRoot* aBinding) override;
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
virtual nsIContent *GetXBLInsertionParent() const override;
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
virtual bool IsLink(nsIURI** aURI) const override;
@ -294,10 +295,9 @@ public:
RefPtr<ShadowRoot> mContainingShadow;
/**
* An array of web component insertion points to which this element
* is distributed.
* The assigned slot associated with this element.
*/
nsTArray<nsIContent*> mDestInsertionPoints;
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
/**
* XBL binding installed on the element.

View file

@ -7,6 +7,8 @@
#ifndef GroupedSHistory_h
#define GroupedSHistory_h
#include "nsCOMArray.h"
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsIFrameLoader.h"
#include "nsIGroupedSHistory.h"
#include "nsIPartialSHistory.h"

View file

@ -8,6 +8,8 @@
* animating */
#include "ImageTracker.h"
#include "mozilla/Preferences.h"
#include "nsAppRunner.h" // for XRE_IsContentProcess
namespace mozilla {
namespace dom {

View file

@ -10,6 +10,7 @@
#ifndef mozilla_dom_ImageTracker
#define mozilla_dom_ImageTracker
#include "imgIRequest.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"

View file

@ -7,6 +7,9 @@
#ifndef mozilla_dom_MutableBlobStorage_h
#define mozilla_dom_MutableBlobStorage_h
#include "nsCycleCollectionParticipant.h"
#include "nsThreadUtils.h"
#include "nsProxyRelease.h"
#include "mozilla/RefPtr.h"
#include "prio.h"

View file

@ -5,6 +5,7 @@
#include "MutableBlobStreamListener.h"
#include "MutableBlobStorage.h"
#include "nsIInputStream.h"
namespace mozilla {
namespace dom {

View file

@ -15,6 +15,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Likely.h"
#include "mozilla/Unused.h"
#include "nsNodeInfoManager.h"
#include "nsCOMPtr.h"

View file

@ -8,6 +8,7 @@
#define mozilla_dom_Pose_h
#include "nsWrapperCache.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {

View file

@ -14,9 +14,9 @@
#include "nsIDOMHTMLElement.h"
#include "nsIStyleSheetLinkingElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@ -27,10 +27,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@ -38,18 +35,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
if (tmp->mPoolHost) {
tmp->mPoolHost->RemoveMutationObserver(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
if (tmp->GetHost()) {
tmp->GetHost()->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
@ -59,14 +52,16 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(nsIContent* aContent,
ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
: DocumentFragment(aNodeInfo)
, mProtoBinding(aProtoBinding)
, mInsertionPointChanged(false)
, mIsComposedDocParticipant(false)
{
SetHost(aContent);
SetHost(aElement);
mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
// Nodes in a shadow tree should never store a value
// in the subtree root pointer, nodes in the shadow tree
@ -75,29 +70,27 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
SetFlags(NODE_IS_IN_SHADOW_TREE);
ExtendedDOMSlots()->mBindingParent = aContent;
ExtendedDOMSlots()->mBindingParent = aElement;
ExtendedDOMSlots()->mContainingShadow = this;
// Add the ShadowRoot as a mutation observer on the host to watch
// for mutations because the insertion points in this ShadowRoot
// may need to be updated when the host children are modified.
mPoolHost->AddMutationObserver(this);
GetHost()->AddMutationObserver(this);
}
ShadowRoot::~ShadowRoot()
{
if (mPoolHost) {
// mPoolHost may have been unlinked or a new ShadowRoot may have been
// creating, making this one obsolete.
mPoolHost->RemoveMutationObserver(this);
if (auto* host = GetHost()) {
// mHost may have been unlinked or a new ShadowRoot may have been
// created, making this one obsolete.
host->RemoveMutationObserver(this);
}
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
SetSubtreeRootPointer(this);
SetHost(nullptr);
}
JSObject*
@ -118,13 +111,116 @@ ShadowRoot::FromNode(nsINode* aNode)
return nullptr;
}
void
ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
{
MOZ_ASSERT(aSlot);
// Note that if name attribute missing, the slot is a default slot.
nsAutoString name;
aSlot->GetName(name);
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
MOZ_ASSERT(currentSlots);
HTMLSlotElement* oldSlot = currentSlots->IsEmpty() ?
nullptr : currentSlots->ElementAt(0);
TreeOrderComparator comparator;
currentSlots->InsertElementSorted(aSlot, comparator);
HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
if (currentSlot != aSlot) {
return;
}
bool doEnqueueSlotChange = false;
if (oldSlot && oldSlot != currentSlot) {
// Move assigned nodes from old slot to new slot.
const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
while (assignedNodes.Length() > 0) {
nsINode* assignedNode = assignedNodes[0];
oldSlot->RemoveAssignedNode(assignedNode);
currentSlot->AppendAssignedNode(assignedNode);
doEnqueueSlotChange = true;
}
if (doEnqueueSlotChange) {
oldSlot->EnqueueSlotChangeEvent();
currentSlot->EnqueueSlotChangeEvent();
}
} else {
// Otherwise add appropriate nodes to this slot from the host.
for (nsIContent* child = GetHost()->GetFirstChild();
child;
child = child->GetNextSibling()) {
nsAutoString slotName;
child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
if (child->IsSlotable() && slotName.Equals(name)) {
currentSlot->AppendAssignedNode(child);
doEnqueueSlotChange = true;
}
}
if (doEnqueueSlotChange) {
currentSlot->EnqueueSlotChangeEvent();
}
}
}
void
ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
{
MOZ_ASSERT(aSlot);
nsAutoString name;
aSlot->GetName(name);
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.Get(name);
if (currentSlots) {
if (currentSlots->Length() == 1) {
MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
mSlotMap.Remove(name);
if (aSlot->AssignedNodes().Length() > 0) {
aSlot->ClearAssignedNodes();
aSlot->EnqueueSlotChangeEvent();
}
} else {
bool doEnqueueSlotChange = false;
bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
currentSlots->RemoveElement(aSlot);
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
// Move assigned nodes from removed slot to the next slot in
// tree order with the same name.
if (doReplaceSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
while (assignedNodes.Length() > 0) {
nsINode* assignedNode = assignedNodes[0];
aSlot->RemoveAssignedNode(assignedNode);
replacementSlot->AppendAssignedNode(assignedNode);
doEnqueueSlotChange = true;
}
if (doEnqueueSlotChange) {
aSlot->EnqueueSlotChangeEvent();
replacementSlot->EnqueueSlotChangeEvent();
}
}
}
}
}
void
ShadowRoot::StyleSheetChanged()
{
mProtoBinding->FlushSkinSheets();
nsIPresShell* shell = OwnerDoc()->GetShell();
if (shell) {
if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
shell->RecordShadowStyleChange(this);
OwnerDoc()->EndUpdate(UPDATE_STYLE);
@ -142,16 +238,30 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == StyleScope::SheetCount());
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
// FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
// binding will disappear soon (tm).
{
size_t i = 0;
for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
}
}
#endif
// Find the correct position to insert into the style sheet list (must
// be in tree order).
for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
if (i == mProtoBinding->SheetCount()) {
for (size_t i = 0; i <= SheetCount(); i++) {
if (i == SheetCount()) {
AppendStyleSheet(*aSheet);
mProtoBinding->AppendStyleSheet(aSheet);
break;
}
nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
InsertSheetAt(i, *aSheet);
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
@ -166,6 +276,7 @@ void
ShadowRoot::RemoveSheet(StyleSheet* aSheet)
{
mProtoBinding->RemoveStyleSheet(aSheet);
StyleScope::RemoveSheet(*aSheet);
if (aSheet->IsApplicable()) {
StyleSheetChanged();
@ -232,238 +343,158 @@ ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
return nsContentUtils::GetElementsByClassName(this, aClasses);
}
void
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
nsresult
ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
TreeOrderComparator comparator;
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
}
aVisitor.mCanHandle = true;
aVisitor.mRootOfClosedTree = IsClosed();
void
ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
{
mInsertionPoints.RemoveElement(aInsertionPoint);
}
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
if (!aVisitor.mEvent->mFlags.mComposed) {
nsCOMPtr<nsIContent> originalTarget =
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
if (originalTarget->GetContainingShadow() == this) {
// If we do stop propagation, we still want to propagate
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
// The load event is special in that we don't ever propagate it
// to chrome.
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
? win->GetParentTarget() : nullptr;
void
ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
{
mYoungerShadow = aYoungerShadow;
mYoungerShadow->mOlderShadow = this;
ChangePoolHost(mYoungerShadow->GetShadowElement());
}
void
ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints)
{
// Remove the insertion point from the destination insertion points.
// Also remove all succeeding insertion points because it is no longer
// possible for the content to be distributed into deeper node trees.
int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
// It's possible that we already removed the insertion point while processing
// other insertion point removals.
if (index >= 0) {
aDestInsertionPoints.SetLength(index);
aVisitor.SetParentTarget(parentTarget, true);
return NS_OK;
}
}
nsIContent* shadowHost = GetHost();
aVisitor.SetParentTarget(shadowHost, false);
if (aVisitor.mOriginalTargetIsInAnon) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
if (content && content->GetBindingParent() == shadowHost) {
aVisitor.mEventTargetAtParent = shadowHost;
}
}
return NS_OK;
}
void
ShadowRoot::DistributeSingleNode(nsIContent* aContent)
const HTMLSlotElement*
ShadowRoot::AssignSlotFor(nsIContent* aContent)
{
// Find the insertion point to which the content belongs.
HTMLContentElement* insertionPoint = nullptr;
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
if (mInsertionPoints[i]->Match(aContent)) {
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
// Node is already matched into the insertion point. We are done.
return;
nsAutoString slotName;
// Note that if slot attribute is missing, assign it to the first default
// slot, if exists.
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
if (!slots) {
return nullptr;
}
HTMLSlotElement* slot = slots->ElementAt(0);
MOZ_ASSERT(slot);
// Find the appropriate position in the assigned node list for the
// newly assigned content.
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
nsIContent* currentContent = GetHost()->GetFirstChild();
bool indexFound = false;
uint32_t insertionIndex;
for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
// Seek through the host's explicit children until the
// assigned content is found.
while (currentContent && currentContent != assignedNodes[i]) {
if (currentContent == aContent) {
indexFound = true;
insertionIndex = i;
}
// Matching may cause the insertion point to drop fallback content.
if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
// This match will cause the insertion point to drop all fallback
// content and used matched nodes instead. Give up on the optimization
// and just distribute all nodes.
DistributeAllNodes();
return;
}
insertionPoint = mInsertionPoints[i];
currentContent = currentContent->GetNextSibling();
}
if (indexFound) {
break;
}
}
// Find the index into the insertion point.
if (insertionPoint) {
nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
// Find the appropriate position in the matched node list for the
// newly distributed content.
bool isIndexFound = false;
MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
ExplicitChildIterator childIterator(mPoolHost);
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
// Seek through the host's explicit children until the inserted content
// is found or when the current matched node is reached.
if (childIterator.Seek(aContent, matchedNodes[i])) {
// aContent was found before the current matched node.
insertionPoint->InsertMatchedNode(i, aContent);
isIndexFound = true;
break;
if (indexFound) {
slot->InsertAssignedNode(insertionIndex, aContent);
} else {
slot->AppendAssignedNode(aContent);
}
return slot;
}
const HTMLSlotElement*
ShadowRoot::UnassignSlotFor(nsIContent* aNode, const nsAString& aSlotName)
{
// Find the insertion point to which the content belongs. Note that if slot
// attribute is missing, unassign it from the first default slot, if exists.
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
if (!slots) {
return nullptr;
}
HTMLSlotElement* slot = slots->ElementAt(0);
MOZ_ASSERT(slot);
if (!slot->AssignedNodes().Contains(aNode)) {
return nullptr;
}
slot->RemoveAssignedNode(aNode);
return slot;
}
bool
ShadowRoot::MaybeReassignElement(Element* aElement,
const nsAttrValue* aOldValue)
{
nsIContent* parent = aElement->GetParent();
if (parent && parent == GetHost()) {
const HTMLSlotElement* oldSlot = UnassignSlotFor(aElement,
aOldValue ? aOldValue->GetStringValue() : EmptyString());
const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
if (oldSlot != newSlot) {
if (oldSlot) {
oldSlot->EnqueueSlotChangeEvent();
}
}
if (!isIndexFound) {
// We have still not found an index in the insertion point,
// thus it must be at the end.
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
"Trying to match a node that is not a candidate to be matched");
insertionPoint->AppendMatchedNode(aContent);
}
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The node distributed into the insertion point must be reprojected
// to the shadow insertion point.
if (insertionPoint->GetParent() == this &&
mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The node distributed into the insertion point must be reprojected to the
// insertion points of the parent's ShadowRoot.
ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
if (parentShadow) {
parentShadow->DistributeSingleNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The node distributed into the insertion point must be reprojected
// into the older ShadowRoot's insertion points.
if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->DistributeSingleNode(aContent);
if (newSlot) {
newSlot->EnqueueSlotChangeEvent();
}
return true;
}
}
return false;
}
void
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
ShadowRoot::DistributionChanged()
{
// Find insertion point containing the content and remove the node.
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
// Removing the matched node may cause the insertion point to use
// fallback content.
if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
// Removing the matched node will cause fallback content to be
// used instead. Give up optimization and distribute all nodes.
DistributeAllNodes();
return;
}
mInsertionPoints[i]->RemoveMatchedNode(aContent);
// Handle the case where the parent of the insertion point is a ShadowRoot
// that is projected into the younger ShadowRoot's shadow insertion point.
// The removed node needs to be removed from the shadow insertion point.
if (mInsertionPoints[i]->GetParent() == this) {
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
}
}
// Handle the case where the parent of the insertion point has a ShadowRoot.
// The removed node needs to be removed from the insertion points of the
// parent's ShadowRoot.
ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
if (parentShadow) {
parentShadow->RemoveDistributedNode(aContent);
}
// Handle the case where the parent of the insertion point is the <shadow>
// element. The removed node must be removed from the older ShadowRoot's
// insertion points.
if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
if (olderShadow) {
olderShadow->RemoveDistributedNode(aContent);
}
}
break;
}
// FIXME(emilio): We could be more granular in a bunch of cases.
auto* host = GetHost();
if (!host || !host->IsInComposedDoc()) {
return;
}
auto* shell = OwnerDoc()->GetShell();
if (!shell) {
return;
}
shell->DestroyFramesForAndRestyle(host);
}
void
ShadowRoot::DistributeAllNodes()
{
// Create node pool.
nsTArray<nsIContent*> nodePool;
//XXX Handle <slot>.
// Make sure there is a pool host, an older shadow may not have
// one if the younger shadow does not have a <shadow> element.
if (mPoolHost) {
ExplicitChildIterator childIterator(mPoolHost);
for (nsIContent* content = childIterator.GetNextChild();
content;
content = childIterator.GetNextChild()) {
nodePool.AppendElement(content);
}
}
nsTArray<ShadowRoot*> shadowsToUpdate;
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
mInsertionPoints[i]->ClearMatchedNodes();
// Assign matching nodes from node pool.
for (uint32_t j = 0; j < nodePool.Length(); j++) {
if (mInsertionPoints[i]->Match(nodePool[j])) {
mInsertionPoints[i]->AppendMatchedNode(nodePool[j]);
nodePool.RemoveElementAt(j--);
}
}
// Keep track of instances where the content insertion point is distributed
// (parent of insertion point has a ShadowRoot).
nsIContent* insertionParent = mInsertionPoints[i]->GetParent();
MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
"mInsertionPoints array is to be a descendant of a"
"ShadowRoot, in which case, it should have a parent");
// If the parent of the insertion point has a ShadowRoot, the nodes distributed
// to the insertion point must be reprojected to the insertion points of the
// parent's ShadowRoot.
ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
shadowsToUpdate.AppendElement(parentShadow);
}
}
// If there is a shadow insertion point in this ShadowRoot, the children
// of the shadow insertion point needs to be distributed into the insertion
// points of the older ShadowRoot.
if (mShadowElement && mOlderShadow) {
mOlderShadow->DistributeAllNodes();
}
// If there is a younger ShadowRoot with a shadow insertion point,
// then the children of this ShadowRoot needs to be distributed to
// the younger ShadowRoot's shadow insertion point.
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
mYoungerShadow->GetShadowElement()->DistributeAllNodes();
}
for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
shadowsToUpdate[i]->DistributeAllNodes();
}
DistributionChanged();
}
void
@ -507,105 +538,6 @@ ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
}
}
StyleSheetList*
ShadowRoot::StyleSheets()
{
if (!mStyleSheetList) {
mStyleSheetList = new ShadowRootStyleSheetList(this);
}
return mStyleSheetList;
}
void
ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
{
// If there is already a shadow element point, remove
// the projected shadow because it is no longer an insertion
// point.
if (mShadowElement) {
mShadowElement->SetProjectedShadow(nullptr);
}
if (mOlderShadow) {
// Nodes for distribution will come from the new shadow element.
mOlderShadow->ChangePoolHost(aShadowElement);
}
// Set the new shadow element to project the older ShadowRoot because
// it is the current shadow insertion point.
mShadowElement = aShadowElement;
if (mShadowElement) {
mShadowElement->SetProjectedShadow(mOlderShadow);
}
}
void
ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
{
if (mPoolHost) {
mPoolHost->RemoveMutationObserver(this);
}
// Clear the nodes matched to content insertion points
// because it is no longer relevant.
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
mInsertionPoints[i]->ClearMatchedNodes();
}
mPoolHost = aNewHost;
if (mPoolHost) {
mPoolHost->AddMutationObserver(this);
}
}
bool
ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
{
if (!aContent) {
return false;
}
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
return shadowElem && shadowElem->IsInsertionPoint();
}
/**
* Returns whether the web components pool population algorithm
* on the host would contain |aContent|. This function ignores
* insertion points in the pool, thus should only be used to
* test nodes that have not yet been distributed.
*/
bool
ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
nsIContent* aHost)
{
if (nsContentUtils::IsContentInsertionPoint(aContent) ||
IsShadowInsertionPoint(aContent)) {
// Insertion points never end up in the pool.
return false;
}
if (aContainer == aHost &&
nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
// Children of the host will end up in the pool. We check to ensure
// that the content is in the same anonymous tree as the container
// because anonymous content may report its container as the host
// but it may not be in the host's child list.
return true;
}
if (aContainer) {
// Fallback content will end up in pool if its parent is a child of the host.
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
return content && content->IsInsertionPoint() &&
content->MatchedNodes().IsEmpty() &&
aContainer->GetParentNode() == aHost;
}
return false;
}
void
ShadowRoot::AttributeChanged(nsIDocument* aDocument,
Element* aElement,
@ -614,13 +546,26 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
int32_t aModType,
const nsAttrValue* aOldValue)
{
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
return;
}
// Attributes may change insertion point matching, find its new distribution.
RemoveDistributedNode(aElement);
DistributeSingleNode(aElement);
if (!MaybeReassignElement(aElement, aOldValue)) {
return;
}
if (!aElement->IsInComposedDoc()) {
return;
}
auto* shell = OwnerDoc()->GetShell();
if (!shell) {
return;
}
//XXX optimize this!
shell->DestroyFramesForAndRestyle(aElement);
}
void
@ -629,29 +574,10 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
nsIContent* aFirstNewContent,
int32_t aNewIndexInContainer)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
// Watch for new nodes added to the pool because the node
// may need to be added to an insertion point.
nsIContent* currentChild = aFirstNewContent;
while (currentChild) {
// Add insertion point to destination insertion points of fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
currentChild->DestInsertionPoints().AppendElement(aContainer);
}
}
if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
DistributeSingleNode(currentChild);
}
currentChild = currentChild->GetNextSibling();
for (nsIContent* content = aFirstNewContent;
content;
content = content->GetNextSibling()) {
ContentInserted(aDocument, aContainer, aFirstNewContent, aNewIndexInContainer);
}
}
@ -661,24 +587,30 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
nsIContent* aChild,
int32_t aIndexInContainer)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
// Check to ensure that the content is in the same anonymous tree
// as the container because anonymous content may report its container
// as the host but it may not be in the host's child list.
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
return;
}
// Watch for new nodes added to the pool because the node
// may need to be added to an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
// Add insertion point to destination insertion points of fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
aChild->DestInsertionPoints().AppendElement(aContainer);
}
}
if (!aChild->IsSlotable()) {
return;
}
DistributeSingleNode(aChild);
if (aContainer && aContainer == GetHost()) {
if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
slot->EnqueueSlotChangeEvent();
}
return;
}
// If parent's root is a shadow root, and parent is a slot whose assigned
// nodes is the empty list, then run signal a slot change for parent.
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
if (slot && slot->GetContainingShadow() == this &&
slot->AssignedNodes().IsEmpty()) {
slot->EnqueueSlotChangeEvent();
}
}
@ -689,25 +621,32 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
// Check to ensure that the content is in the same anonymous tree
// as the container because anonymous content may report its container
// as the host but it may not be in the host's child list.
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
return;
}
// Clear destination insertion points for removed
// fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
aChild->DestInsertionPoints().Clear();
}
if (!aChild->IsSlotable()) {
return;
}
// Watch for node that is removed from the pool because
// it may need to be removed from an insertion point.
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
RemoveDistributedNode(aChild);
if (aContainer && aContainer == GetHost()) {
nsAutoString slotName;
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
slot->EnqueueSlotChangeEvent();
}
return;
}
// If parent's root is a shadow root, and parent is a slot whose assigned
// nodes is the empty list, then run signal a slot change for parent.
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
if (slot && slot->GetContainingShadow() == this &&
slot->AssignedNodes().IsEmpty()) {
slot->EnqueueSlotChangeEvent();
}
}
@ -717,49 +656,3 @@ ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
*aResult = nullptr;
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
void
ShadowRoot::DestroyContent()
{
if (mOlderShadow) {
mOlderShadow->DestroyContent();
}
DocumentFragment::DestroyContent();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
mShadowRoot)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
: mShadowRoot(aShadowRoot)
{
MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
}
ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
{
MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
}
StyleSheet*
ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
{
aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
if (!aFound) {
return nullptr;
}
return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
}
uint32_t
ShadowRootStyleSheetList::Length()
{
return mShadowRoot->mProtoBinding->SheetCount();
}

View file

@ -8,8 +8,7 @@
#define mozilla_dom_shadowroot_h__
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/dom/StyleScope.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIContentInlines.h"
@ -21,17 +20,17 @@ class nsIContent;
class nsXBLPrototypeBinding;
namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class Element;
class HTMLContentElement;
class HTMLShadowElement;
class ShadowRootStyleSheetList;
class ShadowRoot final : public DocumentFragment,
public StyleScope,
public nsStubMutationObserver
{
friend class ShadowRootStyleSheetList;
public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
DocumentFragment)
@ -42,46 +41,38 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
ShadowRoot(nsIContent* aContent, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding);
// Shadow DOM v1
Element* Host();
ShadowRootMode Mode() const
{
return mMode;
}
bool IsClosed() const
{
return mMode == ShadowRootMode::Closed;
}
// StyleScope.
nsINode& AsNode() final
{
return *this;
}
// [deprecated] Shadow DOM v0
void AddToIdTable(Element* aElement, nsIAtom* aId);
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
void RemoveSheet(StyleSheet* aSheet);
bool ApplyAuthorStyles();
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
StyleSheetList* StyleSheets();
HTMLShadowElement* GetShadowElement() { return mShadowElement; }
/**
* Sets the current shadow insertion point where the older
* ShadowRoot will be projected.
*/
void SetShadowElement(HTMLShadowElement* aShadowElement);
/**
* Change the node that populates the distribution pool with
* its children. This is distinct from the ShadowRoot host described
* in the specifications. The ShadowRoot host is the element
* which created this ShadowRoot and does not change. The pool host
* is the same as the ShadowRoot host if this is the youngest
* ShadowRoot. If this is an older ShadowRoot, the pool host is
* the <shadow> element in the younger ShadowRoot (if it exists).
*/
void ChangePoolHost(nsIContent* aNewHost);
/**
* Distributes a single explicit child of the pool host to the content
* insertion points in this ShadowRoot.
*/
void DistributeSingleNode(nsIContent* aContent);
/**
* Removes a single explicit child of the pool host from the content
* insertion points in this ShadowRoot.
*/
void RemoveDistributedNode(nsIContent* aContent);
StyleSheetList* StyleSheets()
{
return &StyleScope::EnsureDOMStyleSheets();
}
/**
* Distributes all the explicit children of the pool host to the content
@ -89,29 +80,47 @@ public:
*/
void DistributeAllNodes();
void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
private:
/**
* Try to reassign an element to a slot and returns whether the assignment
* changed.
*/
bool MaybeReassignElement(Element* aElement, const nsAttrValue* aOldValue);
/**
* Try to assign aContent to a slot in the shadow tree, returns the assigned
* slot if found.
*/
const HTMLSlotElement* AssignSlotFor(nsIContent* aContent);
/**
* Unassign aContent from the assigned slot in the shadow tree, returns the
* assigned slot if found.
*
* Note: slot attribute of aContent may have changed already, so pass slot
* name explicity here.
*/
const HTMLSlotElement* UnassignSlotFor(nsIContent* aContent,
const nsAString& aSlotName);
/**
* Called when we redistribute content after insertion points have changed.
*/
void DistributionChanged();
bool IsPooledNode(nsIContent* aChild) const;
public:
void AddSlot(HTMLSlotElement* aSlot);
void RemoveSlot(HTMLSlotElement* aSlot);
void SetYoungerShadow(ShadowRoot* aYoungerShadow);
ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
nsISupports* GetParentObject() const { return mPoolHost; }
nsIContent* GetPoolHost() { return mPoolHost; }
nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
nsIContent* aHost);
static ShadowRoot* FromNode(nsINode* aNode);
static bool IsShadowInsertionPoint(nsIContent* aContent);
static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints);
// WebIDL methods.
Element* GetElementById(const nsAString& aElementId);
@ -124,8 +133,6 @@ public:
GetElementsByClassName(const nsAString& aClasses);
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
Element* Host();
ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
void StyleSheetChanged();
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
@ -134,24 +141,17 @@ public:
mIsComposedDocParticipant = aIsComposedDocParticipant;
}
virtual void DestroyContent() override;
nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
protected:
virtual ~ShadowRoot();
// The pool host is the parent of the nodes that will be distributed
// into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
nsCOMPtr<nsIContent> mPoolHost;
ShadowRootMode mMode;
// An array of content insertion points that are a descendant of the ShadowRoot
// sorted in tree order. Insertion points are responsible for notifying
// the ShadowRoot when they are removed or added as a descendant. The insertion
// points are kept alive by the parent node, thus weak references are held
// by the array.
nsTArray<HTMLContentElement*> mInsertionPoints;
// An array of the <shadow> elements that are descendant of the ShadowRoot
// sorted in tree order. Only the first may be a shadow insertion point.
nsTArray<HTMLShadowElement*> mShadowDescendants;
// Map from name of slot to an array of all slots in the shadow DOM with with
// the given name. The slots are stored as a weak pointer because the elements
// are in the shadow tree and should be kept alive by its parent.
nsClassHashtable<nsStringHashKey, nsTArray<mozilla::dom::HTMLSlotElement*>> mSlotMap;
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsXBLPrototypeBinding* mProtoBinding;
@ -161,19 +161,6 @@ protected:
// owns |mProtoBinding|.
RefPtr<nsXBLBinding> mAssociatedBinding;
RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
// The current shadow insertion point of this ShadowRoot.
HTMLShadowElement* mShadowElement;
// The ShadowRoot that was created by the host element before
// this ShadowRoot was created.
RefPtr<ShadowRoot> mOlderShadow;
// The ShadowRoot that was created by the host element after
// this ShadowRoot was created.
RefPtr<ShadowRoot> mYoungerShadow;
// A boolean that indicates that an insertion point was added or removed
// from this ShadowRoot and that the nodes need to be redistributed into
// the insertion points. After this flag is set, nodes will be distributed
@ -189,28 +176,6 @@ protected:
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
};
class ShadowRootStyleSheetList : public StyleSheetList
{
public:
explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
virtual nsINode* GetParentObject() const override
{
return mShadowRoot;
}
uint32_t Length() override;
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
protected:
virtual ~ShadowRootStyleSheetList();
RefPtr<ShadowRoot> mShadowRoot;
};
} // namespace dom
} // namespace mozilla

27
dom/base/StyleScope.cpp Normal file
View file

@ -0,0 +1,27 @@
/* -*- 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/. */
#include "StyleScope.h"
#include "mozilla/dom/StyleSheetList.h"
namespace mozilla {
namespace dom {
StyleScope::~StyleScope()
{
}
StyleSheetList&
StyleScope::EnsureDOMStyleSheets()
{
if (!mDOMStyleSheets) {
mDOMStyleSheets = new StyleSheetList(*this);
}
return *mDOMStyleSheets;
}
}
}

81
dom/base/StyleScope.h Normal file
View file

@ -0,0 +1,81 @@
/* -*- 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_dom_StyleScope_h__
#define mozilla_dom_StyleScope_h__
#include "nsTArray.h"
class nsINode;
namespace mozilla {
class StyleSheet;
namespace dom {
class StyleSheetList;
/**
* A class meant to be shared by ShadowRoot and Document, that holds a list of
* stylesheets.
*
* TODO(emilio, bug 1418159): In the future this should hold most of the
* relevant style state, this should allow us to fix bug 548397.
*/
class StyleScope
{
public:
virtual nsINode& AsNode() = 0;
const nsINode& AsNode() const
{
return const_cast<StyleScope&>(*this).AsNode();
}
StyleSheet* SheetAt(size_t aIndex) const
{
return mStyleSheets.SafeElementAt(aIndex);
}
size_t SheetCount() const
{
return mStyleSheets.Length();
}
int32_t IndexOfSheet(const StyleSheet& aSheet) const
{
return mStyleSheets.IndexOf(&aSheet);
}
void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
{
mStyleSheets.InsertElementAt(aIndex, &aSheet);
}
void RemoveSheet(StyleSheet& aSheet)
{
mStyleSheets.RemoveElement(&aSheet);
}
void AppendStyleSheet(StyleSheet& aSheet)
{
mStyleSheets.AppendElement(&aSheet);
}
StyleSheetList& EnsureDOMStyleSheets();
~StyleScope();
protected:
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
};
}
}
#endif

View file

@ -8,6 +8,7 @@
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/dom/StyleSheetListBinding.h"
#include "nsStubDocumentObserver.h"
namespace mozilla {
namespace dom {
@ -17,7 +18,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
@ -43,5 +45,24 @@ StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
return NS_OK;
}
void
StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
{
mStyleScope = nullptr;
}
StyleSheetList::StyleSheetList(StyleScope& aScope)
: mStyleScope(&aScope)
{
mStyleScope->AsNode().AddMutationObserver(this);
}
StyleSheetList::~StyleSheetList()
{
if (mStyleScope) {
mStyleScope->AsNode().RemoveMutationObserver(this);
}
}
} // namespace dom
} // namespace mozilla

View file

@ -7,8 +7,10 @@
#ifndef mozilla_dom_StyleSheetList_h
#define mozilla_dom_StyleSheetList_h
#include "mozilla/dom/StyleScope.h"
#include "nsIDOMStyleSheetList.h"
#include "nsWrapperCache.h"
#include "nsStubDocumentObserver.h"
class nsINode;
@ -17,28 +19,54 @@ class StyleSheet;
namespace dom {
class StyleSheetList : public nsIDOMStyleSheetList
, public nsWrapperCache
class StyleSheetList final : public nsIDOMStyleSheetList
, public nsWrapperCache
, public nsStubDocumentObserver
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
NS_DECL_NSIDOMSTYLESHEETLIST
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
explicit StyleSheetList(StyleScope& aScope);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
virtual nsINode* GetParentObject() const = 0;
nsINode* GetParentObject() const
{
return mStyleScope ? &mStyleScope->AsNode() : nullptr;
}
virtual uint32_t Length() = 0;
virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
StyleSheet* Item(uint32_t aIndex)
uint32_t Length() const
{
return mStyleScope ? mStyleScope->SheetCount() : 0;
}
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
{
if (!mStyleScope) {
aFound = false;
return nullptr;
}
StyleSheet* sheet = mStyleScope->SheetAt(aIndex);
aFound = !!sheet;
return sheet;
}
StyleSheet* Item(uint32_t aIndex) const
{
bool dummy = false;
return IndexedGetter(aIndex, dummy);
}
protected:
virtual ~StyleSheetList() {}
virtual ~StyleSheetList();
StyleScope* mStyleScope; // Weak, cleared on "NodeWillBeDestroyed".
};
} // namespace dom

View file

@ -7,10 +7,12 @@
#ifndef TabGroup_h
#define TabGroup_h
#include "nsIDocument.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
#include "nsIPrincipal.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsString.h"
#include "mozilla/RefPtr.h"

View file

@ -10,6 +10,7 @@
#include "nsIChannel.h"
#include "nsIServiceManager.h"
#include "nsIHttpChannelInternal.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"

View file

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TimeoutHandler.h"
#include "nsJSUtils.h"
namespace mozilla {
namespace dom {

View file

@ -7,9 +7,11 @@
#ifndef mozilla_dom_timeout_handler_h
#define mozilla_dom_timeout_handler_h
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsITimeoutHandler.h"
#include "nsString.h"
namespace mozilla {
namespace dom {

View file

@ -7,6 +7,8 @@
#ifndef TimerClamping_h___
#define TimerClamping_h___
#include <math.h>
namespace mozilla {
class TimerClamping

View file

@ -0,0 +1,17 @@
<html>
<head>
<script>
try { o1 = document.createElement('textarea') } catch(e) { }
try { o2 = document.createElement('div') } catch(e) { }
try { o3 = document.createElement('map') } catch(e) { }
try { document.documentElement.appendChild(o2) } catch(e) { }
try { o2.appendChild(o1) } catch(e) { }
try { document.documentElement.getClientRects() } catch(e) { }
try { o4 = o2.attachShadow({ mode: "open" }); } catch(e) { }
try { o1.appendChild(o3) } catch(e) { }
try { o5 = o3.parentElement } catch(e) { }
try { o3.outerHTML = "\n" } catch(e) { }
try { o4.prepend("", o5, "") } catch(e) { }
</script>
</head>
</html>

View file

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
<slot><div></div></slot>
</html>

View file

@ -193,7 +193,7 @@ load 930250.html
load 942979.html
load 973401.html
load 978646.html
pref(dom.webcomponents.enabled,true) load 1024428-1.html
pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1340009
load 1026714.html
pref(dom.webcomponents.enabled,true) load 1027461-1.html
pref(dom.webcomponents.enabled,true) load 1029710.html
@ -209,4 +209,6 @@ load 1230422.html
load 1251361.html
load 1304437.html
pref(clipboard.autocopy,true) load 1385272-1.html
pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
pref(dom.webcomponents.enabled,true) load 1341693.html
pref(dom.webcomponents.enabled,true) load 1419799.html
pref(dom.webcomponents.enabled,false) load 1422931.html

View file

@ -213,6 +213,7 @@ EXPORTS.mozilla.dom += [
'SimpleTreeIterator.h',
'StructuredCloneHolder.h',
'StructuredCloneTags.h',
'StyleScope.h',
'StyleSheetList.h',
'SubtleCrypto.h',
'TabGroup.h',
@ -225,7 +226,7 @@ EXPORTS.mozilla.dom += [
'WindowOrientationObserver.h',
]
UNIFIED_SOURCES += [
SOURCES += [
'AnonymousContent.cpp',
'Attr.cpp',
'BarProps.cpp',
@ -359,6 +360,7 @@ UNIFIED_SOURCES += [
'ScriptSettings.cpp',
'ShadowRoot.cpp',
'StructuredCloneHolder.cpp',
'StyleScope.cpp',
'StyleSheetList.cpp',
'SubtleCrypto.cpp',
'TabGroup.cpp',
@ -376,7 +378,7 @@ UNIFIED_SOURCES += [
]
if CONFIG['MOZ_WEBRTC']:
UNIFIED_SOURCES += [
SOURCES += [
'nsDOMDataChannel.cpp',
]

View file

@ -382,12 +382,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
}
nsresult
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
bool* aHadValue)
{
*aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
*aHadValue = true;
return NS_OK;
}
}
@ -407,21 +410,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
}
nsresult
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
nsAttrValue& aValue, bool* aHadValue)
{
int32_t namespaceID = aName->NamespaceID();
nsIAtom* localName = aName->NameAtom();
if (namespaceID == kNameSpaceID_None) {
return SetAndSwapAttr(localName, aValue);
return SetAndSwapAttr(localName, aValue, aHadValue);
}
*aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
ATTRS(mImpl)[i].mName.SetTo(aName);
ATTRS(mImpl)[i].mValue.Reset();
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
*aHadValue = true;
return NS_OK;
}
}
@ -576,10 +580,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
}
nsresult
nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet)
nsHTMLStyleSheet* aSheet,
bool* aHadValue)
{
bool willAdd = true;
if (mImpl && mImpl->mMappedAttrs) {
@ -589,7 +594,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
RefPtr<nsMappedAttributes> mapped =
GetModifiableMapped(aContent, aSheet, willAdd);
mapped->SetAndTakeAttr(aLocalName, aValue);
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
return MakeMappedUnique(mapped);
}
@ -714,10 +719,19 @@ nsAttrAndChildArray::MappedAttrCount() const
return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
}
nsresult
nsAttrAndChildArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
{
nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
return MakeMappedUnique(mapped);
}
nsMappedAttributes*
nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
bool aWillAddAttr)
bool aWillAddAttr,
int32_t aAttrCount)
{
if (mImpl && mImpl->mMappedAttrs) {
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
@ -727,7 +741,7 @@ nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
nsMapRuleToAttributesFunc mapRuleFunc =
aContent->GetAttributeMappingFunction();
return new nsMappedAttributes(aSheet, mapRuleFunc);
return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
}
nsresult

View file

@ -91,8 +91,13 @@ public:
nsCaseTreatment aCaseSensitive) const;
const nsAttrValue* AttrAt(uint32_t aPos) const;
// SetAndSwapAttr swaps the current attribute value with aValue.
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
// If the attribute was unset, an empty value will be swapped into aValue
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
// true.
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
bool* aHadValue);
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
bool* aHadValue);
// Remove the attr at position aPos. The value of the attr is placed in
// aValue; any value that was already in aValue is destroyed.
@ -110,9 +115,14 @@ public:
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
// SetAndSwapMappedAttr swaps the current attribute value with aValue.
// If the attribute was unset, an empty value will be swapped into aValue
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
// true.
nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet);
nsHTMLStyleSheet* aSheet,
bool* aHadValue);
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
if (!mImpl || !mImpl->mMappedAttrs) {
return NS_OK;
@ -135,6 +145,9 @@ public:
return MappedAttrCount();
}
// Force this to have mapped attributes, even if those attributes are empty.
nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
private:
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
@ -148,7 +161,8 @@ private:
nsMappedAttributes*
GetModifiableMapped(nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
bool aWillAddAttr);
bool aWillAddAttr,
int32_t aAttrCount = 1);
nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
uint32_t AttrSlotsSize() const

View file

@ -49,20 +49,13 @@ public:
, mCheapString(nullptr)
{ }
void TakeParsedValue(nsAttrValue& aValue)
void ResetToAttrValue(const nsAttrValue& aValue)
{
mStoredAttrValue.SwapValueWith(aValue);
mAttrValue = &mStoredAttrValue;
mAttrValue = &aValue;
mStringPtr = nullptr;
// No need to touch mCheapString here. If we need to use it, we will reset
// it to the rigthe value anyway.
}
/**
* If TakeParsedValue has been called, returns the value that it set.
*/
nsAttrValue* GetStoredAttrValue()
{
return mAttrValue == &mStoredAttrValue ? &mStoredAttrValue : nullptr;
}
const nsAttrValue* GetAttrValue() { return mAttrValue; }
/**
* Returns a reference to the string value of the contents of this object.
@ -85,11 +78,24 @@ public:
return aOther.EqualsAsStrings(*mAttrValue);
}
/*
* Returns true if the value stored is empty
*/
bool IsEmpty() const
{
if (mStringPtr) {
return mStringPtr->IsEmpty();
}
if (mAttrValue) {
return mAttrValue->IsEmptyString();
}
return true;
}
protected:
const nsAttrValue* mAttrValue;
mutable const nsAString* mStringPtr;
mutable nsCheapString mCheapString;
nsAttrValue mStoredAttrValue;
};
#endif // nsAttrValueOrString_h___

View file

@ -44,9 +44,8 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FileSystemSecurity.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/dom/Promise.h"
@ -102,7 +101,9 @@
#include "nsHostObjectProtocolHandler.h"
#include "nsHtml5Module.h"
#include "nsHtml5StringParser.h"
#include "nsHTMLTags.h"
#include "nsIAddonPolicyService.h"
#include "nsIAnonymousContentCreator.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICategoryManager.h"
#include "nsIChannelEventSink.h"
@ -500,6 +501,8 @@ nsContentUtils::Init()
return NS_OK;
}
nsHTMLTags::AddRefTable();
sNameSpaceManager = nsNameSpaceManager::GetInstance();
NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
@ -590,7 +593,7 @@ nsContentUtils::Init()
"dom.webcomponents.enabled", false);
Preferences::AddBoolVarCache(&sIsCustomElementsEnabled,
"dom.webcomponents.customelements.enabled", false);
"dom.webcomponents.enabled", false);
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
"dom.url.encode_decode_hash", false);
@ -1926,6 +1929,8 @@ nsContentUtils::Shutdown()
{
sInitialized = false;
nsHTMLTags::ReleaseTable();
NS_IF_RELEASE(sContentPolicyService);
sTriedToGetContentPolicy = false;
uint32_t i;
@ -2390,6 +2395,9 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
bool* aDisconnected)
{
if (aParent1 == aParent2) {
// XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
// of nsINode::IndexOf(), but this compares such invalid offset with
// valid offset.
return aOffset1 < aOffset2 ? -1 :
aOffset1 > aOffset2 ? 1 :
0;
@ -2440,10 +2448,14 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
if (!pos1) {
nsINode* child2 = parents2.ElementAt(--pos2);
// XXX aOffset1 may be -1 as mentioned above. So, why does this return
// it's *before* of the valid DOM point?
return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
}
nsINode* child1 = parents1.ElementAt(--pos1);
// XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
// *after* of the valid DOM point?
return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
}
@ -4943,17 +4955,7 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
return aContent->GetBindingParent() == nullptr;
}
const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode);
// For nodes in a shadow tree, it is insufficient to simply compare
// the binding parent because a node may host multiple ShadowRoots,
// thus nodes in different shadow tree may have the same binding parent.
if (aNode->IsInShadowTree()) {
return nodeAsContent->GetContainingShadow() ==
aContent->GetContainingShadow();
}
return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent();
}
class AnonymousContentDestroyer : public Runnable {
@ -7015,25 +7017,11 @@ nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext)
return editor;
}
bool
nsContentUtils::IsContentInsertionPoint(nsIContent* aContent)
{
// Check if the content is a XBL insertion point.
if (aContent->IsActiveChildrenElement()) {
return true;
}
// Check if the content is a web components content insertion point.
HTMLContentElement* contentElement =
HTMLContentElement::FromContent(aContent);
return contentElement && contentElement->IsInsertionPoint();
}
// static
bool
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
{
if (!aContent) {
if (!aContent || !nsDocument::IsWebComponentsEnabled(aContent)) {
return false;
}
@ -7043,26 +7031,11 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
return true;
}
ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
if (shadow) {
// Children of a shadow root are distributed to
// the shadow insertion point of the younger shadow root.
return shadow->GetYoungerShadowRoot();
}
HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
if (shadowEl && shadowEl->IsInsertionPoint()) {
// Children of a shadow insertion points are distributed
// to the insertion points in the older shadow root.
return shadowEl->GetOlderShadowRoot();
}
HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
if (contentEl && contentEl->IsInsertionPoint()) {
// Children of a content insertion point are distributed to the
// content insertion point if the content insertion point does
// not match any nodes (fallback content).
return contentEl->MatchedNodes().IsEmpty();
HTMLSlotElement* slotEl = HTMLSlotElement::FromContent(aContent);
if (slotEl && slotEl->GetContainingShadow()) {
// Children of a slot are rendered if the slot does not have any assigned
// nodes (fallback content).
return slotEl->AssignedNodes().IsEmpty();
}
return false;
@ -9675,35 +9648,6 @@ nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
aDefinition);
}
/* static */ void
nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
int32_t aNamespaceID,
nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype)
{
MOZ_ASSERT(aDoc);
// To support imported document.
nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
if (aNamespaceID != kNameSpaceID_XHTML ||
!doc->GetDocShell()) {
return;
}
nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
if (!window) {
return;
}
RefPtr<CustomElementRegistry> registry(window->CustomElements());
if (!registry) {
return;
}
return registry->GetCustomPrototype(aAtom, aPrototype);
}
/* static */ bool
nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
{
@ -9837,6 +9781,24 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
return reloadSucceeded;
}
/* static */ void
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
nsIDocument* aDocument,
nsTArray<nsIContent*>& aElements)
{
MOZ_ASSERT(aDocument);
// XXXheycam This probably needs to find the nsCanvasFrame's NAC too.
if (nsIPresShell* presShell = aDocument->GetShell()) {
if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) {
nsIAnonymousContentCreator* creator = do_QueryFrame(scrollFrame);
MOZ_ASSERT(creator,
"scroll frame should always implement nsIAnonymousContentCreator");
creator->AppendAnonymousContentTo(aElements, 0);
}
}
}
/* static */ bool
nsContentUtils::IsLocalRefURL(const nsString& aString)
{
@ -9852,3 +9814,16 @@ nsContentUtils::IsLocalRefURL(const nsString& aString)
return false;
}
/* static */ Element*
nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
{
MOZ_ASSERT(aElement);
MOZ_ASSERT(aElement->IsNativeAnonymous());
Element* e = aElement;
while (e && e->IsNativeAnonymous()) {
e = e->GetParentElement();
}
return e;
}

View file

@ -339,6 +339,13 @@ public:
* NOTE! If the two nodes aren't in the same connected subtree,
* the result is 1, and the optional aDisconnected parameter
* is set to true.
*
* XXX aOffset1 and aOffset2 should be uint32_t since valid offset value is
* between 0 - UINT32_MAX. However, these methods work even with
* negative offset values! E.g., when aOffset1 is -1 and aOffset is 0,
* these methods return -1. Some root callers depend on this behavior.
* On the other hand, nsINode can have ATTRCHILD_ARRAY_MAX_CHILD_COUN
* (0x3FFFFF) at most. Therefore, they can be int32_t for now.
*/
static int32_t ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* aParent2, int32_t aOffset2,
@ -582,7 +589,7 @@ public:
/**
* Returns true if |aName| is a valid name to be registered via
* document.registerElement.
* customElements.define.
*/
static bool IsCustomElementName(nsIAtom* aName);
@ -2407,18 +2414,6 @@ public:
*/
static mozilla::LogModule* DOMDumpLog();
/**
* Returns whether a content is an insertion point for XBL
* bindings or web components ShadowRoot. In web components,
* this corresponds to a <content> element that participates
* in node distribution. In XBL this corresponds to an
* <xbl:children> element in anonymous content.
*
* @param aContent The content to test for being an insertion point.
*/
static bool IsContentInsertionPoint(nsIContent* aContent);
/**
* Returns whether the children of the provided content are
* nodes that are distributed to Shadow DOM insertion points.
@ -2735,13 +2730,18 @@ public:
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
static void GetCustomPrototype(nsIDocument* aDoc,
int32_t aNamespaceID,
nsIAtom* aAtom,
JS::MutableHandle<JSObject*> prototype);
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
/**
* Appends all "document level" native anonymous content subtree roots for
* aDocument to aElements. Document level NAC subtrees are those created
* by ancestor frames of the document element's primary frame, such as
* the scrollbar elements created by the root scroll frame.
*/
static void AppendDocumentLevelNativeAnonymousContentTo(
nsIDocument* aDocument,
nsTArray<nsIContent*>& aElements);
/**
* Detect whether a string is a (CSS) local-url.
* https://drafts.csswg.org/css-values/#local-urls
@ -2752,6 +2752,12 @@ public:
static bool
IsWebComponentsEnabled() { return sIsWebComponentsEnabled; }
/**
* Walks up the tree from aElement until it finds an element that is
* not native anonymous content. aElement must be NAC itself.
*/
static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
static bool
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }

View file

@ -524,3 +524,9 @@ nsDOMAttributeMap::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return NamedNodeMapBinding::Wrap(aCx, this, aGivenProto);
}
DocGroup*
nsDOMAttributeMap::GetDocGroup() const
{
return mContent ? mContent->OwnerDoc()->GetDocGroup() : nullptr;
}

View file

@ -22,6 +22,11 @@
class nsIAtom;
class nsIDocument;
namespace mozilla {
namespace dom {
class DocGroup;
} // namespace dom
} // namespace mozilla
/**
* Structure used as a key for caching Attrs in nsDOMAttributeMap's mAttributeCache.
@ -87,6 +92,7 @@ class nsDOMAttributeMap final : public nsIDOMMozNamedAttrMap
{
public:
typedef mozilla::dom::Attr Attr;
typedef mozilla::dom::DocGroup DocGroup;
typedef mozilla::dom::Element Element;
typedef mozilla::ErrorResult ErrorResult;
@ -135,6 +141,7 @@ public:
return mContent;
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
DocGroup* GetDocGroup() const;
// WebIDL
Attr* GetNamedItem(const nsAString& aAttrName);

View file

@ -7,11 +7,13 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/dom/DocGroup.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
@ -29,6 +31,9 @@ using mozilla::dom::TreeOrderComparator;
using mozilla::dom::Animation;
using mozilla::dom::Element;
using namespace mozilla;
using namespace mozilla::dom;
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
@ -609,6 +614,28 @@ public:
}
};
/* static */ void
nsDOMMutationObserver::QueueMutationObserverMicroTask()
{
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (!ccjs) {
return;
}
RefPtr<MutationObserverMicroTask> momt =
new MutationObserverMicroTask();
ccjs->DispatchMicroTaskRunnable(momt.forget());
}
void
nsDOMMutationObserver::HandleMutations(mozilla::AutoSlowOperation& aAso)
{
if (sScheduledMutationObservers ||
mozilla::dom::DocGroup::sPendingDocGroups) {
HandleMutationsInternal(aAso);
}
}
void
nsDOMMutationObserver::RescheduleForRun()
{
@ -887,7 +914,23 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
{
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
while (sScheduledMutationObservers) {
// Let signalList be a copy of unit of related similar-origin browsing
// contexts' signal slot list.
nsTArray<RefPtr<HTMLSlotElement>> signalList;
if (DocGroup::sPendingDocGroups) {
for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
signalList.AppendElements(docGroup->SignalSlotList());
// Empty unit of related similar-origin browsing contexts' signal slot
// list.
docGroup->ClearSignalSlotList();
}
delete DocGroup::sPendingDocGroups;
DocGroup::sPendingDocGroups = nullptr;
}
if (sScheduledMutationObservers) {
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
sScheduledMutationObservers;
sScheduledMutationObservers = nullptr;
@ -917,6 +960,11 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
delete suppressedObservers;
suppressedObservers = nullptr;
}
// Fire slotchange event for each slot in signalList.
for (uint32_t i = 0; i < signalList.Length(); ++i) {
signalList[i]->FireSlotChangeEvent();
}
}
nsDOMMutationRecord*

View file

@ -552,12 +552,9 @@ public:
}
// static methods
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
{
if (sScheduledMutationObservers) {
HandleMutationsInternal(aAso);
}
}
static void QueueMutationObserverMicroTask();
static void HandleMutations(mozilla::AutoSlowOperation& aAso);
static bool AllScheduledMutationObserversAreSuppressed()
{

View file

@ -366,6 +366,12 @@ nsDOMTokenList::Stringify(nsAString& aResult)
mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
}
DocGroup*
nsDOMTokenList::GetDocGroup() const
{
return mElement ? mElement->OwnerDoc()->GetDocGroup() : nullptr;
}
JSObject*
nsDOMTokenList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
{

View file

@ -22,7 +22,9 @@
namespace mozilla {
class ErrorResult;
namespace dom {
class DocGroup;
} // namespace dom
} // namespace mozilla
class nsAttrValue;
@ -35,6 +37,7 @@ class nsDOMTokenList : public nsISupports,
{
protected:
typedef mozilla::dom::Element Element;
typedef mozilla::dom::DocGroup DocGroup;
typedef nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
WhitespaceTokenizer;
@ -52,6 +55,8 @@ public:
return mElement;
}
DocGroup* GetDocGroup() const;
uint32_t Length();
void Item(uint32_t aIndex, nsAString& aResult)
{

View file

@ -3473,7 +3473,7 @@ nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
if (sheet->GetOwningDocument()) {
if (sheet->GetAssociatedDocument()) {
return NS_ERROR_INVALID_ARG;
}
return doc->AddAdditionalStyleSheet(type, sheet);
@ -3657,11 +3657,11 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
nsIFrame* frame = element->GetPrimaryFrame();
if (frame && !aPseudoElement.IsEmpty()) {
if (!aPseudoElement.IsEmpty()) {
if (aPseudoElement.EqualsLiteral("::before")) {
frame = nsLayoutUtils::GetBeforeFrame(frame);
frame = nsLayoutUtils::GetBeforeFrame(element);
} else if (aPseudoElement.EqualsLiteral("::after")) {
frame = nsLayoutUtils::GetAfterFrame(frame);
frame = nsLayoutUtils::GetAfterFrame(element);
} else {
return NS_ERROR_INVALID_ARG;
}

View file

@ -116,7 +116,6 @@
#include "nsBidiUtils.h"
#include "nsIParserService.h"
#include "nsContentCreatorFunctions.h"
#include "nsIScriptContext.h"
@ -571,78 +570,6 @@ struct nsRadioGroupStruct
bool mGroupSuffersFromValueMissing;
};
nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
{
mLength = -1;
// Not reference counted to avoid circular references.
// The document will tell us when its going away.
mDocument = aDocument;
mDocument->AddObserver(this);
}
nsDOMStyleSheetList::~nsDOMStyleSheetList()
{
if (mDocument) {
mDocument->RemoveObserver(this);
}
}
NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList,
nsIDocumentObserver,
nsIMutationObserver)
uint32_t
nsDOMStyleSheetList::Length()
{
if (!mDocument) {
return 0;
}
// XXX Find the number and then cache it. We'll use the
// observer notification to figure out if new ones have
// been added or removed.
if (-1 == mLength) {
mLength = mDocument->GetNumberOfStyleSheets();
}
return mLength;
}
StyleSheet*
nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
{
if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
aFound = false;
return nullptr;
}
aFound = true;
return mDocument->GetStyleSheetAt(aIndex);
}
void
nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
{
mDocument = nullptr;
}
void
nsDOMStyleSheetList::StyleSheetAdded(StyleSheet* aStyleSheet,
bool aDocumentSheet)
{
if (aDocumentSheet && -1 != mLength) {
mLength++;
}
}
void
nsDOMStyleSheetList::StyleSheetRemoved(StyleSheet* aStyleSheet,
bool aDocumentSheet)
{
if (aDocumentSheet && -1 != mLength) {
mLength--;
}
}
// nsOnloadBlocker implementation
NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
@ -1200,10 +1127,10 @@ nsDOMStyleSheetSetList::EnsureFresh()
// no document, for sure
}
int32_t count = mDocument->GetNumberOfStyleSheets();
size_t count = mDocument->SheetCount();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
StyleSheet* sheet = mDocument->GetStyleSheetAt(index);
for (size_t index = 0; index < count; index++) {
StyleSheet* sheet = mDocument->SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam ServoStyleSheets don't expose their title yet.
if (sheet->IsServo()) {
@ -1333,6 +1260,10 @@ nsIDocument::nsIDocument()
{
SetIsInDocument();
// Set this when document is created and value stays the same for the lifetime
// of the document.
mIsWebComponentsEnabled = nsContentUtils::IsWebComponentsEnabled();
PR_INIT_CLIST(&mDOMMediaQueryLists);
}
@ -1452,11 +1383,11 @@ nsDocument::~nsDocument()
// Let the stylesheets know we're going away
for (StyleSheet* sheet : mStyleSheets) {
sheet->SetOwningDocument(nullptr);
sheet->ClearAssociatedDocument();
}
for (auto& sheets : mAdditionalSheets) {
for (StyleSheet* sheet : sheets) {
sheet->SetOwningDocument(nullptr);
sheet->ClearAssociatedDocument();
}
}
if (mAttrStyleSheet) {
@ -2113,7 +2044,7 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
{
// The stylesheets should forget us
for (StyleSheet* sheet : Reversed(mStyleSheets)) {
sheet->SetOwningDocument(nullptr);
sheet->ClearAssociatedDocument();
if (sheet->IsApplicable()) {
nsCOMPtr<nsIPresShell> shell = GetShell();
@ -2132,7 +2063,7 @@ nsDocument::RemoveStyleSheetsFromStyleSets(
{
// The stylesheets should forget us
for (StyleSheet* sheet : Reversed(aSheets)) {
sheet->SetOwningDocument(nullptr);
sheet->ClearAssociatedDocument();
if (sheet->IsApplicable()) {
nsCOMPtr<nsIPresShell> shell = GetShell();
@ -2311,6 +2242,29 @@ WarnIfSandboxIneffective(nsIDocShell* aDocShell,
}
}
bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
if (!nsContentUtils::IsWebComponentsEnabled()) {
return false;
}
JS::Rooted<JSObject*> obj(aCx, aObject);
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
if (doc && doc->IsStyledByServo()) {
NS_WARNING("stylo: Web Components not supported yet");
return false;
}
return true;
}
nsresult
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,
@ -3927,24 +3881,6 @@ nsDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
NotifyStyleSheetAdded(aSheet, false);
}
int32_t
nsDocument::GetNumberOfStyleSheets() const
{
return mStyleSheets.Length();
}
StyleSheet*
nsDocument::GetStyleSheetAt(int32_t aIndex) const
{
return mStyleSheets.SafeElementAt(aIndex, nullptr);
}
int32_t
nsDocument::GetIndexOfStyleSheet(const StyleSheet* aSheet) const
{
return mStyleSheets.IndexOf(aSheet);
}
void
nsDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
{
@ -4007,7 +3943,7 @@ nsDocument::AddStyleSheet(StyleSheet* aSheet)
{
NS_PRECONDITION(aSheet, "null arg");
mStyleSheets.AppendElement(aSheet);
aSheet->SetOwningDocument(this);
aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (aSheet->IsApplicable()) {
AddStyleSheetToStyleSets(aSheet);
@ -4044,7 +3980,7 @@ nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
NotifyStyleSheetRemoved(aSheet, true);
}
aSheet->SetOwningDocument(nullptr);
aSheet->ClearAssociatedDocument();
}
void
@ -4072,7 +4008,7 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
StyleSheet* newSheet = aNewSheets[i];
if (newSheet) {
mStyleSheets.InsertElementAt(oldIndex, newSheet);
newSheet->SetOwningDocument(this);
newSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (newSheet->IsApplicable()) {
AddStyleSheetToStyleSets(newSheet);
}
@ -4085,13 +4021,13 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
}
void
nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
{
NS_PRECONDITION(aSheet, "null ptr");
MOZ_ASSERT(aSheet);
mStyleSheets.InsertElementAt(aIndex, aSheet);
aSheet->SetOwningDocument(this);
aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
if (aSheet->IsApplicable()) {
AddStyleSheetToStyleSets(aSheet);
@ -4216,7 +4152,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
NS_ENSURE_SUCCESS(rv, rv);
sheet->SetOwningDocument(this);
sheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
MOZ_ASSERT(sheet->IsApplicable());
return AddAdditionalStyleSheet(aType, sheet);
@ -4274,7 +4210,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
NotifyStyleSheetRemoved(sheetRef, false);
EndUpdate(UPDATE_STYLE);
sheetRef->SetOwningDocument(nullptr);
sheetRef->ClearAssociatedDocument();
}
}
@ -5353,29 +5289,18 @@ bool IsLowercaseASCII(const nsAString& aValue)
return true;
}
already_AddRefed<mozilla::dom::CustomElementRegistry>
nsDocument::GetCustomElementRegistry()
// We only support pseudo-elements with two colons in this function.
static CSSPseudoElementType
GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
{
nsAutoString contentType;
GetContentType(contentType);
if (!IsHTMLDocument() &&
!contentType.EqualsLiteral("application/xhtml+xml")) {
return nullptr;
MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return CSSPseudoElementType::NotPseudo;
}
nsCOMPtr<nsPIDOMWindowInner> window(
do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
: GetScopeObject()));
if (!window) {
return nullptr;
}
RefPtr<CustomElementRegistry> registry = window->CustomElements();
if (!registry) {
return nullptr;
}
return registry.forget();
nsCOMPtr<nsIAtom> pseudo = NS_Atomize(Substring(aString, 1));
return nsCSSPseudoElements::GetPseudoType(pseudo,
nsCSSProps::EnabledState::eInUASheets);
}
already_AddRefed<Element>
@ -5395,10 +5320,36 @@ nsDocument::CreateElement(const nsAString& aTagName,
}
const nsString* is = nullptr;
CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
if (aOptions.IsElementCreationOptions()) {
const ElementCreationOptions& options =
aOptions.GetAsElementCreationOptions();
if (CustomElementRegistry::IsCustomElementEnabled() &&
options.mIs.WasPassed()) {
is = &options.mIs.Value();
}
// Check 'pseudo' and throw an exception if it's not one allowed
// with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC.
if (options.mPseudo.WasPassed()) {
pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv);
if (rv.Failed() ||
pseudoType == CSSPseudoElementType::NotPseudo ||
!nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
}
}
RefPtr<Element> elem = CreateElem(
needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
if (pseudoType != CSSPseudoElementType::NotPseudo) {
elem->SetPseudoElementType(pseudoType);
}
if (is) {
elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
}
@ -5413,8 +5364,8 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
{
*aReturn = nullptr;
ElementCreationOptionsOrString options;
options.SetAsString();
options.SetAsString();
ErrorResult rv;
nsCOMPtr<Element> element =
CreateElementNS(aNamespaceURI, aQualifiedName, options, rv);
@ -5439,6 +5390,13 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
}
const nsString* is = nullptr;
if (CustomElementRegistry::IsCustomElementEnabled() &&
aOptions.IsElementCreationOptions()) {
const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions();
if (options.mIs.WasPassed()) {
is = &options.mIs.Value();
}
}
nsCOMPtr<Element> element;
rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
@ -5647,278 +5605,9 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
}
bool
nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
{
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
JS::Rooted<JSObject*> global(aCx,
JS_GetGlobalForObject(aCx, &args.callee()));
RefPtr<nsGlobalWindow> window;
UNWRAP_OBJECT(Window, global, window);
MOZ_ASSERT(window, "Should have a non-null window");
nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
// Function name is the type of the custom element.
JSString* jsFunName =
JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
nsAutoJSString elemName;
if (!elemName.init(aCx, jsFunName)) {
return true;
}
RefPtr<mozilla::dom::CustomElementRegistry> registry = window->CustomElements();
if (!registry) {
return true;
}
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
CustomElementDefinition* definition =
registry->mCustomDefinitions.GetWeak(typeAtom);
if (!definition) {
return true;
}
RefPtr<Element> element;
// We integrate with construction stack and do prototype swizzling here, so
// that old upgrade behavior could also share the new upgrade steps.
// And this old upgrade will be remove at some point (when everything is
// switched to latest custom element spec).
nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
definition->mConstructionStack;
if (constructionStack.Length()) {
element = constructionStack.LastElement();
NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false);
// Do prototype swizzling if dom reflector exists.
JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
if (reflector) {
Maybe<JSAutoCompartment> ac;
JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype);
if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) {
ac.emplace(aCx, reflector);
if (!JS_WrapObject(aCx, &prototype) ||
!JS_SetPrototype(aCx, reflector, prototype)) {
return false;
}
} else {
// We want to set the custom prototype in the compartment where it was
// registered. We store the prototype from define() without unwrapped,
// hence the prototype's compartment is the compartment where it was
// registered.
// In the case that |reflector| and |prototype| are in different
// compartments, this will set the prototype on the |reflector|'s wrapper
// and thus only visible in the wrapper's compartment, since we know
// reflector's principal does not subsume prototype's in this case.
ac.emplace(aCx, prototype);
if (!JS_WrapObject(aCx, &reflector) ||
!JS_SetPrototype(aCx, reflector, prototype)) {
return false;
}
}
// Wrap into current context.
if (!JS_WrapObject(aCx, &reflector)) {
return false;
}
args.rval().setObject(*reflector);
return true;
}
} else {
nsDependentAtomString localName(definition->mLocalName);
element =
document->CreateElem(localName, nullptr, kNameSpaceID_XHTML,
(definition->mLocalName != typeAtom) ? &elemName
: nullptr);
NS_ENSURE_TRUE(element, false);
}
// The prototype setup happens in Element::WrapObject().
nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
NS_ENSURE_SUCCESS(rv, true);
return true;
}
bool
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
{
JS::Rooted<JSObject*> obj(aCx, aObject);
if (nsContentUtils::IsWebComponentsEnabled()) {
return true;
}
// Check for the webcomponents permission. See Bug 1181555.
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
return IsWebComponentsEnabled(window);
}
bool
nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
{
if (nsContentUtils::IsWebComponentsEnabled()) {
return true;
}
nsIDocument* doc = aNodeInfo->GetDocument();
// Use GetScopeObject() here so that data documents work the same way as the
// main document they're associated with.
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(doc->GetScopeObject());
return IsWebComponentsEnabled(window);
}
bool
nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow)
{
if (aWindow) {
nsresult rv;
nsCOMPtr<nsIPermissionManager> permMgr =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, false);
uint32_t perm;
rv = permMgr->TestPermissionFromWindow(
aWindow, "moz-extremely-unstable-and-will-change-webcomponents", &perm);
NS_ENSURE_SUCCESS(rv, false);
return perm == nsIPermissionManager::ALLOW_ACTION;
}
return false;
}
void
nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
const ElementRegistrationOptions& aOptions,
JS::MutableHandle<JSObject*> aRetval,
ErrorResult& rv)
{
RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry());
if (!registry) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(),
aCx);
// Unconditionally convert TYPE to lowercase.
nsAutoString lcType;
nsContentUtils::ASCIIToLower(aType, lcType);
nsIGlobalObject* sgo = GetScopeObject();
if (!sgo) {
rv.Throw(NS_ERROR_UNEXPECTED);
return;
}
JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
JS::Rooted<JSObject*> protoObject(aCx);
if (!aOptions.mPrototype) {
JS::Rooted<JSObject*> htmlProto(aCx);
htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
if (!htmlProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
if (!protoObject) {
rv.Throw(NS_ERROR_UNEXPECTED);
return;
}
} else {
protoObject = aOptions.mPrototype;
// Get the unwrapped prototype to do some checks.
JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
if (!protoObjectUnwrapped) {
// If the caller's compartment does not have permission to access the
// unwrapped prototype then throw.
rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
// If PROTOTYPE is already an interface prototype object for any interface
// object or PROTOTYPE has a non-configurable property named constructor,
// throw a NotSupportedError and stop.
const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
if (IsDOMIfaceAndProtoClass(clasp)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
// This check may go through a wrapper, but as we checked above
// it should be transparent or an xray. This should be fine for now,
// until the spec is sorted out.
if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
rv.Throw(NS_ERROR_UNEXPECTED);
return;
}
if (!desc.configurable()) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
}
JS::Rooted<JSFunction*> constructor(aCx);
{
// Go into the document's global compartment when creating the constructor
// function because we want to get the correct document (where the
// definition is registered) when it is called.
JSAutoCompartment ac(aCx, global);
// Create constructor to return. Store the name of the custom element as the
// name of the function.
constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
JSFUN_CONSTRUCTOR,
NS_ConvertUTF16toUTF8(lcType).get());
if (!constructor) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
}
JS::Rooted<JSObject*> wrappedConstructor(aCx);
wrappedConstructor = JS_GetFunctionObject(constructor);
if (!JS_WrapObject(aCx, &wrappedConstructor)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
ElementDefinitionOptions options;
if (!aOptions.mExtends.IsVoid()) {
// Only convert NAME to lowercase in HTML documents.
nsAutoString lcName;
IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
: lcName.Assign(aOptions.mExtends);
options.mExtends.Construct(lcName);
}
RootedCallback<OwningNonNull<binding_detail::FastFunction>> functionConstructor(aCx);
functionConstructor = new binding_detail::FastFunction(aCx, wrappedConstructor, sgo);
registry->Define(lcType, functionConstructor, options, rv);
aRetval.set(wrappedConstructor);
return aNode->OwnerDoc()->IsWebComponentsEnabled();
}
NS_IMETHODIMP
@ -6006,15 +5695,6 @@ nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
return NS_OK;
}
StyleSheetList*
nsDocument::StyleSheets()
{
if (!mDOMStyleSheets) {
mDOMStyleSheets = new nsDOMStyleSheetList(this);
}
return mDOMStyleSheets;
}
NS_IMETHODIMP
nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet)
{
@ -6028,10 +5708,10 @@ nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
aSheetSet.Truncate();
// Look through our sheets, find the selected set title
int32_t count = GetNumberOfStyleSheets();
size_t count = SheetCount();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
StyleSheet* sheet = GetStyleSheetAt(index);
for (size_t index = 0; index < count; index++) {
StyleSheet* sheet = SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam Make this work with ServoStyleSheets.
@ -6148,10 +5828,10 @@ nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
bool aUpdateCSSLoader)
{
BeginUpdate(UPDATE_STYLE);
int32_t count = GetNumberOfStyleSheets();
size_t count = SheetCount();
nsAutoString title;
for (int32_t index = 0; index < count; index++) {
StyleSheet* sheet = GetStyleSheetAt(index);
for (size_t index = 0; index < count; index++) {
StyleSheet* sheet = SheetAt(index);
NS_ASSERTION(sheet, "Null sheet in sheet list!");
// XXXheycam Make this work with ServoStyleSheets.
@ -6421,7 +6101,7 @@ already_AddRefed<nsRange>
nsIDocument::CreateRange(ErrorResult& rv)
{
RefPtr<nsRange> range = new nsRange(this);
nsresult res = range->Set(this, 0, this, 0);
nsresult res = range->CollapseTo(this, 0);
if (NS_FAILED(res)) {
rv.Throw(res);
return nullptr;
@ -7712,7 +7392,7 @@ nsDocument::GetExistingListenerManager() const
}
nsresult
nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
// FIXME! This is a hack to make middle mouse paste working also in Editor.
@ -7722,8 +7402,8 @@ nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Load events must not propagate to |window| object, see bug 335251.
if (aVisitor.mEvent->mMessage != eLoad) {
nsGlobalWindow* window = nsGlobalWindow::Cast(GetWindow());
aVisitor.mParentTarget =
window ? window->GetTargetForEventTargetChain() : nullptr;
aVisitor.SetParentTarget(
window ? window->GetTargetForEventTargetChain() : nullptr, false);
}
return NS_OK;
}
@ -9859,9 +9539,9 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
clonedDoc->mOriginalDocument->mStaticCloneCount++;
int32_t sheetsCount = GetNumberOfStyleSheets();
for (int32_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = GetStyleSheetAt(i);
size_t sheetsCount = SheetCount();
for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = SheetAt(i);
if (sheet) {
if (sheet->IsApplicable()) {
// XXXheycam Need to make ServoStyleSheet cloning work.
@ -12079,7 +11759,7 @@ SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
size_t n = 0;
n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (StyleSheet* sheet : aSheets) {
if (!sheet->GetOwningDocument()) {
if (!sheet->GetAssociatedDocument()) {
// Avoid over-reporting shared sheets.
continue;
}

View file

@ -293,36 +293,6 @@ public:
nsDocHeaderData* mNext;
};
class nsDOMStyleSheetList : public mozilla::dom::StyleSheetList,
public nsStubDocumentObserver
{
public:
explicit nsDOMStyleSheetList(nsIDocument* aDocument);
NS_DECL_ISUPPORTS_INHERITED
// nsIDocumentObserver
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
virtual nsINode* GetParentObject() const override
{
return mDocument;
}
uint32_t Length() override;
mozilla::StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
protected:
virtual ~nsDOMStyleSheetList();
int32_t mLength;
nsIDocument* mDocument;
};
class nsOnloadBlocker final : public nsIRequest
{
public:
@ -624,14 +594,6 @@ public:
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) override;
/**
* Get the (document) style sheets owned by this document.
* These are ordered, highest priority last
*/
virtual int32_t GetNumberOfStyleSheets() const override;
virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
virtual int32_t GetIndexOfStyleSheet(
const mozilla::StyleSheet* aSheet) const override;
virtual void AddStyleSheet(mozilla::StyleSheet* aSheet) override;
virtual void RemoveStyleSheet(mozilla::StyleSheet* aSheet) override;
@ -642,7 +604,7 @@ public:
virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
int32_t aIndex) override;
size_t aIndex) override;
virtual void SetStyleSheetApplicableState(mozilla::StyleSheet* aSheet,
bool aApplicable) override;
@ -793,7 +755,11 @@ public:
virtual void NotifyLayerManagerRecreated() override;
// Check whether web components are enabled for the global of aObject.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
// Check whether web components are enabled for the document this node belongs
// to.
static bool IsWebComponentsEnabled(const nsINode* aNode);
private:
void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
@ -810,7 +776,7 @@ public:
NS_DECL_NSIDOMDOCUMENTXBL
// nsIDOMEventTarget
virtual nsresult PreHandleEvent(
virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual mozilla::EventListenerManager*
GetOrCreateListenerManager() override;
@ -1129,12 +1095,7 @@ public:
// WebIDL bits
virtual mozilla::dom::DOMImplementation*
GetImplementation(mozilla::ErrorResult& rv) override;
virtual void
RegisterElement(JSContext* aCx, const nsAString& aName,
const mozilla::dom::ElementRegistrationOptions& aOptions,
JS::MutableHandle<JSObject*> aRetval,
mozilla::ErrorResult& rv) override;
virtual mozilla::dom::StyleSheetList* StyleSheets() override;
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
virtual mozilla::dom::DOMStringList* StyleSheetSets() override;
@ -1356,7 +1317,6 @@ protected:
// EndLoad() has already happened.
nsWeakPtr mWeakSink;
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
@ -1385,23 +1345,8 @@ protected:
// non-null when this document is in fullscreen mode.
nsWeakPtr mFullscreenRoot;
private:
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
public:
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
GetCustomElementRegistry() override;
// Check whether web components are enabled for the global of aObject.
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
// Check whether web components are enabled for the global of the document
// this nodeinfo comes from.
static bool IsWebComponentsEnabled(mozilla::dom::NodeInfo* aNodeInfo);
// Check whether web components are enabled for the given window.
static bool IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow);
RefPtr<mozilla::EventListenerManager> mListenerManager;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
RefPtr<nsScriptLoader> mScriptLoader;
nsDocHeaderData* mHeaderData;

View file

@ -32,7 +32,6 @@
#include "nsIDOMDocument.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
#include "nsIParserService.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
@ -40,6 +39,7 @@
#include "nsISelectionPrivate.h"
#include "nsITransferable.h" // for kUnicodeMime
#include "nsContentUtils.h"
#include "nsElementTable.h"
#include "nsNodeUtils.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
@ -1588,10 +1588,13 @@ nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
nsresult
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
{
if (!inRange) return NS_ERROR_NULL_POINTER;
RefPtr<nsRange> range = static_cast<nsRange*>(inRange);
if (!range) {
return NS_ERROR_NULL_POINTER;
}
nsresult rv;
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
int32_t startOffset, endOffset;
uint32_t startOffset, endOffset;
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
NS_ENSURE_SUCCESS(rv, rv);
@ -1609,9 +1612,11 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
int32_t opStartOffset, opEndOffset;
// examine range endpoints.
rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
rv = GetPromotedPoint(kStart, startNode, static_cast<int32_t>(startOffset),
address_of(opStartNode), &opStartOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
rv = GetPromotedPoint(kEnd, endNode, static_cast<int32_t>(endOffset),
address_of(opEndNode), &opEndOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
@ -1623,9 +1628,9 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
}
// set the range to the new values
rv = inRange->SetStart(opStartNode, opStartOffset);
rv = inRange->SetStart(opStartNode, static_cast<uint32_t>(opStartOffset));
NS_ENSURE_SUCCESS(rv, rv);
rv = inRange->SetEnd(opEndNode, opEndOffset);
rv = inRange->SetEnd(opEndNode, static_cast<uint32_t>(opEndOffset));
return rv;
}
@ -1736,9 +1741,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
if (offset == -1) return NS_OK; // we hit generated content; STOP
nsIParserService *parserService = nsContentUtils::GetParserService();
if (!parserService)
return NS_ERROR_OUT_OF_MEMORY;
while ((IsFirstNode(node)) && (!IsRoot(parent)) && (parent != common))
{
if (bResetPromotion)
@ -1746,11 +1748,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (content && content->IsHTMLElement())
{
bool isBlock = false;
parserService->IsBlock(parserService->HTMLAtomTagToId(
content->NodeInfo()->NameAtom()), isBlock);
if (isBlock)
{
if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
content->NodeInfo()->NameAtom()))) {
bResetPromotion = false;
}
}
@ -1819,9 +1818,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
if (offset == -1) return NS_OK; // we hit generated content; STOP
nsIParserService *parserService = nsContentUtils::GetParserService();
if (!parserService)
return NS_ERROR_OUT_OF_MEMORY;
while ((IsLastNode(node)) && (!IsRoot(parent)) && (parent != common))
{
if (bResetPromotion)
@ -1829,11 +1825,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
if (content && content->IsHTMLElement())
{
bool isBlock = false;
parserService->IsBlock(parserService->HTMLAtomTagToId(
content->NodeInfo()->NameAtom()), isBlock);
if (isBlock)
{
if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
content->NodeInfo()->NameAtom()))) {
bResetPromotion = false;
}
}

View file

@ -2457,7 +2457,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
nsCOMPtr<nsIDOMNode> startNode, endNode;
bool isCollapsed = false;
nsCOMPtr<nsIContent> startContent, endContent;
int32_t startOffset = 0;
uint32_t startOffset = 0;
if (domSelection) {
domSelection->GetIsCollapsed(&isCollapsed);
nsCOMPtr<nsIDOMRange> domRange;
@ -2471,7 +2471,6 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
startContent = do_QueryInterface(startNode);
if (startContent && startContent->IsElement()) {
NS_ASSERTION(startOffset >= 0, "Start offset cannot be negative");
childContent = startContent->GetChildAt(startOffset);
if (childContent) {
startContent = childContent;
@ -2480,9 +2479,8 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
endContent = do_QueryInterface(endNode);
if (endContent && endContent->IsElement()) {
int32_t endOffset = 0;
uint32_t endOffset = 0;
domRange->GetEndOffset(&endOffset);
NS_ASSERTION(endOffset >= 0, "End offset cannot be negative");
childContent = endContent->GetChildAt(endOffset);
if (childContent) {
endContent = childContent;
@ -2510,7 +2508,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
bool isFormControl =
startContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL);
if (nodeValue.Length() == (uint32_t)startOffset && !isFormControl &&
if (nodeValue.Length() == startOffset && !isFormControl &&
startContent != aDocument->GetRootElement()) {
// Yes, indeed we were at the end of the last node
nsCOMPtr<nsIFrameEnumerator> frameTraversal;

View file

@ -57,6 +57,7 @@
#include "nsGlobalWindow.h"
#include "nsPIWindowRoot.h"
#include "nsLayoutUtils.h"
#include "nsMappedAttributes.h"
#include "nsView.h"
#include "GroupedSHistory.h"
#include "PartialSHistory.h"
@ -936,6 +937,8 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
RefPtr<nsPresContext> presContext;
mDocShell->GetPresContext(getter_AddRefs(presContext));
if (presContext)
// rebuild, because now the same nsMappedAttributes* will produce
// a different style
presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
}

View file

@ -46,7 +46,7 @@ public:
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override
{
MOZ_ASSERT(IsInNativeAnonymousSubtree());
if (aVisitor.mEvent->mMessage == eLoad ||
@ -54,7 +54,7 @@ public:
// Don't propagate the events to the parent.
return NS_OK;
}
return nsXMLElement::PreHandleEvent(aVisitor);
return nsXMLElement::GetEventTargetParent(aVisitor);
}
private:

View file

@ -15,6 +15,7 @@
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
@ -736,21 +737,18 @@ nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot)
{
}
nsTArray<nsIContent*>&
nsGenericDOMDataNode::DestInsertionPoints()
{
nsDataSlots *slots = DataSlots();
return slots->mDestInsertionPoints;
}
nsTArray<nsIContent*>*
nsGenericDOMDataNode::GetExistingDestInsertionPoints() const
HTMLSlotElement*
nsGenericDOMDataNode::GetAssignedSlot() const
{
nsDataSlots *slots = GetExistingDataSlots();
if (slots) {
return &slots->mDestInsertionPoints;
}
return nullptr;
return slots ? slots->mAssignedSlot.get() : nullptr;
}
void
nsGenericDOMDataNode::SetAssignedSlot(HTMLSlotElement* aSlot)
{
nsDataSlots *slots = DataSlots();
slots->mAssignedSlot = aSlot;
}
nsXBLBinding *
@ -843,6 +841,9 @@ nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAssignedSlot");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mAssignedSlot.get()));
}
void
@ -850,6 +851,7 @@ nsGenericDOMDataNode::nsDataSlots::Unlink()
{
mXBLInsertionParent = nullptr;
mContainingShadow = nullptr;
mAssignedSlot = nullptr;
}
//----------------------------------------------------------------------

View file

@ -26,6 +26,12 @@
class nsIDocument;
class nsIDOMText;
namespace mozilla {
namespace dom {
class HTMLSlotElement;
} // namespace dom
} // namespace mozilla
#define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
// Data node specific flags
@ -154,9 +160,9 @@ public:
virtual void SetXBLBinding(nsXBLBinding* aBinding,
nsBindingManager* aOldBindingManager = nullptr) override;
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const override;
virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
virtual nsIContent *GetXBLInsertionParent() const override;
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
virtual bool IsNodeOfType(uint32_t aFlags) const override;
@ -261,9 +267,9 @@ protected:
RefPtr<mozilla::dom::ShadowRoot> mContainingShadow;
/**
* @see nsIContent::GetDestInsertionPoints
* @see nsIContent::GetAssignedSlot
*/
nsTArray<nsIContent*> mDestInsertionPoints;
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
};
// Override from nsINode

View file

@ -1560,11 +1560,11 @@ GK_ATOM(saturate, "saturate")
GK_ATOM(saturation, "saturation")
GK_ATOM(set, "set")
GK_ATOM(seed, "seed")
GK_ATOM(shadow, "shadow")
GK_ATOM(shape_rendering, "shape-rendering")
GK_ATOM(skewX, "skewX")
GK_ATOM(skewY, "skewY")
GK_ATOM(slope, "slope")
GK_ATOM(slot, "slot")
GK_ATOM(softLight, "soft-light")
GK_ATOM(spacing, "spacing")
GK_ATOM(spacingAndGlyphs, "spacingAndGlyphs")
@ -2144,12 +2144,14 @@ GK_ATOM(ongamepaddisconnected, "ongamepaddisconnected")
#endif
// Content property names
GK_ATOM(afterPseudoProperty, "afterPseudoProperty") // nsXMLElement*
GK_ATOM(animationsProperty, "AnimationsProperty") // FrameAnimations*
GK_ATOM(animationsOfBeforeProperty, "AnimationsOfBeforeProperty") // FrameAnimations*
GK_ATOM(animationsOfAfterProperty, "AnimationsOfAfterProperty") // FrameAnimations*
GK_ATOM(animationEffectsProperty, "AnimationEffectsProperty") // EffectSet*
GK_ATOM(animationEffectsForBeforeProperty, "AnimationsEffectsForBeforeProperty") // EffectSet*
GK_ATOM(animationEffectsForAfterProperty, "AnimationsEffectsForAfterProperty") // EffectSet*
GK_ATOM(beforePseudoProperty, "beforePseudoProperty") // nsXMLElement*
GK_ATOM(cssPseudoElementBeforeProperty, "CSSPseudoElementBeforeProperty") // CSSPseudoElement*
GK_ATOM(cssPseudoElementAfterProperty, "CSSPseudoElementAfterProperty") // CSSPseudoElement*
GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions*
@ -2162,6 +2164,7 @@ GK_ATOM(lockedStyleStates, "lockedStyleStates")
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
GK_ATOM(paintRequestTime, "PaintRequestTime")
GK_ATOM(pseudoProperty, "PseudoProperty") // CSSPseudoElementType
// Languages for lang-specific transforms
GK_ATOM(Japanese, "ja")

View file

@ -3577,9 +3577,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
}
nsresult
nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
NS_PRECONDITION(IsInnerWindow(),
"GetEventTargetParent is used on outer window!?");
EventMessage msg = aVisitor.mEvent->mMessage;
aVisitor.mCanHandle = true;
@ -3607,7 +3608,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
aVisitor.mParentTarget = GetParentTarget();
aVisitor.SetParentTarget(GetParentTarget(), true);
// Handle 'active' event.
if (!mIdleObservers.IsEmpty() &&
@ -3812,7 +3813,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
} else if (aVisitor.mEvent->mMessage == eLoad &&
aVisitor.mEvent->IsTrusted()) {
// This is page load event since load events don't propagate to |window|.
// @see nsDocument::PreHandleEvent.
// @see nsDocument::GetEventTargetParent.
mIsDocumentLoaded = true;
nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();

View file

@ -15,6 +15,7 @@
#include "nsIDOMElement.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsElementTable.h"
#include "nsNameSpaceManager.h"
#include "nsString.h"
#include "nsUnicharUtils.h"
@ -347,20 +348,13 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
}
if (ns == kNameSpaceID_XHTML) {
nsIParserService* parserService = nsContentUtils::GetParserService();
if (parserService) {
bool isContainer;
parserService->
IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
isContainer);
if (!isContainer) {
// Keep this in sync with the cleanup at the end of this method.
MOZ_ASSERT(name != nsGkAtoms::body);
MaybeLeaveFromPreContent(content);
return NS_OK;
}
bool isContainer =
nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(name));
if (!isContainer) {
// Keep this in sync with the cleanup at the end of this method.
MOZ_ASSERT(name != nsGkAtoms::body);
MaybeLeaveFromPreContent(content);
return NS_OK;
}
}

View file

@ -26,6 +26,7 @@ namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class ShadowRoot;
class HTMLSlotElement;
} // namespace dom
namespace widget {
struct IMEState;
@ -144,7 +145,14 @@ public:
* Skip native anonymous content created for placeholder of HTML input,
* used in conjunction with eAllChildren or eAllButXBL.
*/
eSkipPlaceholderContent = 2
eSkipPlaceholderContent = 2,
/**
* Skip native anonymous content created by ancestor frames of the root
* element's primary frame, such as scrollbar elements created by the root
* scroll frame.
*/
eSkipDocumentLevelNativeAnonymousContent = 4,
};
/**
@ -186,7 +194,7 @@ public:
void SetIsNativeAnonymousRoot()
{
SetFlags(NODE_IS_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
NODE_IS_NATIVE_ANONYMOUS_ROOT);
NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_NATIVE_ANONYMOUS);
}
/**
@ -689,18 +697,27 @@ public:
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const = 0;
/**
* Gets an array of destination insertion points where this content
* is distributed by web component distribution algorithms.
* The array is created if it does not already exist.
* Gets the assigned slot associated with this content.
*
* @return The assigned slot element or null.
*/
virtual nsTArray<nsIContent*> &DestInsertionPoints() = 0;
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const = 0;
/**
* Same as DestInsertionPoints except that this method will return
* null if the array of destination insertion points does not already
* exist.
* Sets the assigned slot associated with this content.
*
* @param aSlot The assigned slot.
*/
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const = 0;
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) = 0;
/**
* Gets the assigned slot associated with this content based on parent's
* shadow root mode. Returns null if parent's shadow root is "closed".
* https://dom.spec.whatwg.org/#dom-slotable-assignedslot
*
* @return The assigned slot element or null.
*/
mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const;
/**
* Gets the insertion parent element of the XBL binding.
@ -723,10 +740,9 @@ public:
*/
inline nsIContent *GetFlattenedTreeParent() const;
/**
* Helper method, which we leave public so that it's accessible from nsINode.
*/
nsINode *GetFlattenedTreeParentNodeInternal() const;
// Helper method, which we leave public so that it's accessible from nsINode.
enum FlattenedParentType { eNotForStyle, eForStyle };
nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
/**
* API to check if this is a link that's traversed in response to user input
@ -944,10 +960,18 @@ public:
return false;
}
// Returns true if this element is native-anonymous scrollbar content.
bool IsNativeScrollbarContent() const {
return IsNativeAnonymous() &&
IsAnyOfXULElements(nsGkAtoms::scrollbar,
nsGkAtoms::resizer,
nsGkAtoms::scrollcorner);
}
// Overloaded from nsINode
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
virtual nsresult PreHandleEvent(
virtual nsresult GetEventTargetParent(
mozilla::EventChainPreVisitor& aVisitor) override;
virtual bool IsPurple() = 0;
@ -961,6 +985,12 @@ protected:
*/
nsIAtom* DoGetID() const;
/**
* Returns the assigned slot, if it exists, or the direct parent, if it's a
* fallback content of a slot.
*/
nsINode* GetFlattenedTreeParentForMaybeAssignedNode() const;
public:
#ifdef DEBUG
/**
@ -1014,7 +1044,15 @@ inline nsIContent* nsINode::AsContent()
{ \
return aContent->_check ? static_cast<_class*>(aContent) : nullptr; \
} \
static const _class* FromContent(const nsIContent* aContent) \
{ \
return aContent->_check ? static_cast<const _class*>(aContent) : nullptr; \
} \
static _class* FromContentOrNull(nsIContent* aContent) \
{ \
return aContent ? FromContent(aContent) : nullptr; \
} \
static const _class* FromContentOrNull(const nsIContent* aContent) \
{ \
return aContent ? FromContent(aContent) : nullptr; \
}

View file

@ -33,14 +33,15 @@ inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const
return AsElement()->FastGetShadowRoot();
}
inline nsINode* nsINode::GetFlattenedTreeParentNode() const
template<nsIContent::FlattenedParentType Type>
static inline nsINode*
GetFlattenedTreeParentNode(const nsINode* aNode)
{
nsINode* parent = GetParentNode();
nsINode* parent = aNode->GetParentNode();
// Try to short-circuit past the complicated and not-exactly-fast logic for
// computing the flattened parent.
//
// There are three cases where we need might something other than parentNode:
// There are four cases where we need might something other than parentNode:
// (1) The node is an explicit child of an XBL-bound element, re-bound
// to an XBL insertion point.
// (2) The node is a top-level element in a shadow tree, whose flattened
@ -48,18 +49,31 @@ inline nsINode* nsINode::GetFlattenedTreeParentNode() const
// is the shadow root).
// (3) The node is an explicit child of an element with a shadow root,
// re-bound to an insertion point.
bool needSlowCall = HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
IsInShadowTree() ||
(parent && parent->IsContent() &&
parent->AsContent()->GetShadowRoot());
// (4) We want the flattened parent for style, and the node is the root
// of a native anonymous content subtree parented to the document's
// root element.
bool needSlowCall = aNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
aNode->IsInShadowTree() ||
(parent &&
parent->IsContent() &&
parent->AsContent()->GetShadowRoot()) ||
(Type == nsIContent::eForStyle &&
aNode->IsContent() &&
aNode->AsContent()->IsRootOfNativeAnonymousSubtree() &&
aNode->OwnerDoc()->GetRootElement() == parent);
if (MOZ_UNLIKELY(needSlowCall)) {
MOZ_ASSERT(IsContent());
return AsContent()->GetFlattenedTreeParentNodeInternal();
MOZ_ASSERT(aNode->IsContent());
return aNode->AsContent()->GetFlattenedTreeParentNodeInternal(Type);
}
return parent;
}
inline nsINode*
nsINode::GetFlattenedTreeParentNode() const
{
return ::GetFlattenedTreeParentNode<nsIContent::eNotForStyle>(this);
}
inline nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
@ -67,5 +81,16 @@ nsIContent::GetFlattenedTreeParent() const
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
}
inline nsINode*
nsINode::GetFlattenedTreeParentNodeForStyle() const
{
return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
}
inline bool
nsINode::NodeOrAncestorHasDirAuto() const
{
return AncestorHasDirAuto() || (IsElement() && AsElement()->HasDirAuto());
}
#endif // nsIContentInlines_h

View file

@ -34,6 +34,7 @@
#include "prclist.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/CORSMode.h"
#include "mozilla/dom/StyleScope.h"
#include "mozilla/LinkedList.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
@ -133,7 +134,6 @@ class DOMIntersectionObserver;
class DOMStringList;
class Element;
struct ElementCreationOptions;
struct ElementRegistrationOptions;
class Event;
class EventTarget;
class FontFaceSet;
@ -197,7 +197,8 @@ class nsContentList;
// Document interface. This is implemented by all document objects in
// Gecko.
class nsIDocument : public nsINode
class nsIDocument : public nsINode,
public mozilla::dom::StyleScope
{
typedef mozilla::dom::GlobalObject GlobalObject;
@ -1070,40 +1071,24 @@ public:
*/
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) = 0;
/**
* Get the number of (document) stylesheets
*
* @return the number of stylesheets
* @throws no exceptions
*/
virtual int32_t GetNumberOfStyleSheets() const = 0;
nsINode& AsNode() final
{
return *this;
}
/**
* Get a particular stylesheet
* @param aIndex the index the stylesheet lives at. This is zero-based
* @return the stylesheet at aIndex. Null if aIndex is out of range.
* @throws no exceptions
*/
virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
mozilla::dom::StyleSheetList* StyleSheets()
{
return &StyleScope::EnsureDOMStyleSheets();
}
/**
* Insert a sheet at a particular spot in the stylesheet list (zero-based)
* @param aSheet the sheet to insert
* @param aIndex the index to insert at. This index will be
* adjusted for the "special" sheets.
* @param aIndex the index to insert at.
* @throws no exceptions
*/
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
int32_t aIndex) = 0;
/**
* Get the index of a particular stylesheet. This will _always_
* consider the "special" sheets as part of the sheet list.
* @param aSheet the sheet to get the index of
* @return aIndex the index of the sheet in the full list
*/
virtual int32_t GetIndexOfStyleSheet(
const mozilla::StyleSheet* aSheet) const = 0;
size_t aIndex) = 0;
/**
* Replace the stylesheets in aOldSheets with the stylesheets in
@ -1154,11 +1139,13 @@ public:
* sheets for this document, returns the index that aSheet should
* be inserted at to maintain document ordering.
*
* Type T has to cast to StyleSheet*.
*
* Defined in nsIDocumentInlines.h.
*/
template<typename T>
size_t FindDocStyleSheetInsertionPoint(const nsTArray<RefPtr<T>>& aDocSheets,
T* aSheet);
size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
const mozilla::StyleSheet& aSheet);
/**
* Get this document's CSSLoader. This is guaranteed to not return null.
@ -2587,14 +2574,6 @@ public:
nsIDocument* GetTopLevelContentDocument();
virtual void
RegisterElement(JSContext* aCx, const nsAString& aName,
const mozilla::dom::ElementRegistrationOptions& aOptions,
JS::MutableHandle<JSObject*> aRetval,
mozilla::ErrorResult& rv) = 0;
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
GetCustomElementRegistry() = 0;
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aTagName)
{
@ -2706,7 +2685,6 @@ public:
return mVisibilityState;
}
#endif
virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
void GetSelectedStyleSheetSet(nsAString& aSheetSet);
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
@ -2894,6 +2872,11 @@ public:
--mThrowOnDynamicMarkupInsertionCounter;
}
bool IsWebComponentsEnabled() const
{
return mIsWebComponentsEnabled;
}
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
@ -3037,6 +3020,9 @@ protected:
// container for per-context fonts (downloadable, SVG, etc.)
RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
// True if dom.webcomponents.enabled pref is set when document is created.
bool mIsWebComponentsEnabled : 1;
// Compatibility mode
nsCompatibility mCompatMode;

View file

@ -19,24 +19,23 @@ nsIDocument::GetBodyElement()
template<typename T>
size_t
nsIDocument::FindDocStyleSheetInsertionPoint(
const nsTArray<RefPtr<T>>& aDocSheets,
T* aSheet)
const nsTArray<T>& aDocSheets,
const mozilla::StyleSheet& aSheet)
{
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
// lowest index first
int32_t newDocIndex = GetIndexOfStyleSheet(aSheet);
int32_t newDocIndex = IndexOfSheet(aSheet);
int32_t count = aDocSheets.Length();
int32_t index;
for (index = 0; index < count; index++) {
T* sheet = aDocSheets[index];
int32_t sheetDocIndex = GetIndexOfStyleSheet(sheet);
size_t count = aDocSheets.Length();
size_t index = 0;
for (; index < count; index++) {
auto* sheet = static_cast<mozilla::StyleSheet*>(aDocSheets[index]);
MOZ_ASSERT(sheet);
int32_t sheetDocIndex = IndexOfSheet(*sheet);
if (sheetDocIndex > newDocIndex)
break;
mozilla::StyleSheet* sheetHandle = sheet;
// If the sheet is not owned by the document it can be an author
// sheet registered at nsStyleSheetService or an additional author
// sheet on the document, which means the new
@ -44,11 +43,11 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
if (sheetDocIndex < 0) {
if (sheetService) {
auto& authorSheets = *sheetService->AuthorStyleSheets();
if (authorSheets.IndexOf(sheetHandle) != authorSheets.NoIndex) {
if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
break;
}
}
if (sheetHandle == GetFirstAdditionalAuthorSheet()) {
if (sheet == GetFirstAdditionalAuthorSheet()) {
break;
}
}

View file

@ -1243,7 +1243,7 @@ nsINode::RemoveEventListener(const nsAString& aType,
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
nsresult
nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
NS_ABORT();
@ -1515,7 +1515,6 @@ nsINode::SetExplicitBaseURI(nsIURI* aURI)
{
nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
if (NS_SUCCEEDED(rv)) {
SetHasExplicitBaseURI();
NS_ADDREF(aURI);
}
return rv;
@ -3133,3 +3132,9 @@ nsINode::IsStyledByServo() const
return OwnerDoc()->IsStyledByServo();
}
#endif
DocGroup*
nsINode::GetDocGroup() const
{
return OwnerDoc()->GetDocGroup();
}

View file

@ -72,6 +72,7 @@ inline bool IsSpaceCharacter(char aChar) {
class AccessibleNode;
struct BoxQuadOptions;
struct ConvertCoordinateOptions;
class DocGroup;
class DOMPoint;
class DOMQuad;
class DOMRectReadOnly;
@ -126,9 +127,28 @@ enum {
NODE_IS_EDITABLE = NODE_FLAG_BIT(7),
// For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
// node in fact has a class, but may be set even if it doesn't.
NODE_MAY_HAVE_CLASS = NODE_FLAG_BIT(8),
// This node was created by layout as native anonymous content. This
// generally corresponds to things created by nsIAnonymousContentCreator,
// though there are exceptions (svg:use content does not have this flag
// set, and any non-nsIAnonymousContentCreator callers of
// SetIsNativeAnonymousRoot also get this flag).
//
// One very important aspect here is that this node is not transitive over
// the subtree (if you want that, use NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE).
// If Gecko code somewhere attaches children to a node with this bit set,
// the children will not have the bit themselves unless the calling code sets
// it explicitly. This means that XBL content bound to NAC doesn't get this
// bit, nor do nodes inserted by editor.
//
// For now, this bit exists primarily to control style inheritance behavior,
// since the nodes for which we set it are often used to implement pseudo-
// elements, which need to inherit style from a script-visible element.
//
// A more general principle for this bit might be this: If the node is entirely
// a detail of layout, is not script-observable in any way, and other engines
// might accomplish the same task with a nodeless layout frame, then the node
// should have this bit set.
NODE_IS_NATIVE_ANONYMOUS = NODE_FLAG_BIT(8),
// Whether the node participates in a shadow tree.
NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(9),
@ -280,6 +300,7 @@ class nsINode : public mozilla::dom::EventTarget
public:
typedef mozilla::dom::BoxQuadOptions BoxQuadOptions;
typedef mozilla::dom::ConvertCoordinateOptions ConvertCoordinateOptions;
typedef mozilla::dom::DocGroup DocGroup;
typedef mozilla::dom::DOMPoint DOMPoint;
typedef mozilla::dom::DOMPointInit DOMPointInit;
typedef mozilla::dom::DOMQuad DOMQuad;
@ -389,6 +410,12 @@ public:
*/
virtual bool IsNodeOfType(uint32_t aFlags) const = 0;
bool
IsSlotable() const
{
return IsElement() || IsNodeOfType(eTEXT);
}
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
/**
@ -588,6 +615,11 @@ public:
return mNodeInfo->NamespaceID() == aNamespace;
}
/**
* Returns the DocGroup of the "node document" of this node.
*/
DocGroup* GetDocGroup() const;
/**
* Print a debugger friendly descriptor of this element. This will describe
* the position of this element in the document.
@ -920,6 +952,14 @@ public:
*/
inline nsINode* GetFlattenedTreeParentNode() const;
/**
* Like GetFlattenedTreeParentNode, but returns null for any native
* anonymous content that was generated for ancestor frames of the
* root element's primary frame, such as scrollbar elements created
* by the root scroll frame.
*/
inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
/**
* Get the parent nsINode for this node if it is an Element.
* @return the parent node
@ -1203,6 +1243,15 @@ public:
#endif
}
/**
* Returns true if |this| is native anonymous (i.e. created by
* nsIAnonymousContentCreator);
*/
bool IsNativeAnonymous() const
{
return HasFlag(NODE_IS_NATIVE_ANONYMOUS);
}
/**
* Returns true if |this| or any of its ancestors is native anonymous.
*/
@ -1335,10 +1384,11 @@ public:
protected:
nsIURI* GetExplicitBaseURI() const {
if (HasExplicitBaseURI()) {
return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
if (!HasProperties()) {
return nullptr;
}
return nullptr;
return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
}
public:
@ -1541,6 +1591,8 @@ private:
// cases lie for nsXMLElement, such as when the node has been moved between
// documents with different id mappings.
ElementHasID,
// Set if the element might have a class.
ElementMayHaveClass,
// Set if the element might have inline style.
ElementMayHaveStyle,
// Set if the element has a name attribute set.
@ -1559,8 +1611,6 @@ private:
// Maybe set if the node is a root of a subtree
// which needs to be kept in the purple buffer.
NodeIsPurpleRoot,
// Set if the node has an explicit base URI stored
NodeHasExplicitBaseURI,
// Set if the element has some style states locked
ElementHasLockedStyleStates,
// Set if element has pointer locked
@ -1571,10 +1621,11 @@ private:
NodeIsContent,
// Set if the node has animations or transitions
ElementHasAnimations,
// Set if node has a dir attribute with a valid value (ltr, rtl, or auto)
// Set if node has a dir attribute with a valid value (ltr, rtl, or auto).
// Note that we cannot compute this from the dir attribute event state
// flags, because we can't use those to distinguish
// <bdi dir="some-invalid-value"> and <bdi dir="auto">.
NodeHasValidDirAttribute,
// Set if node has a dir attribute with a fixed value (ltr or rtl, NOT auto)
NodeHasFixedDir,
// Set if the node has dir=auto and has a property pointing to the text
// node that determines its direction
NodeHasDirAutoSet,
@ -1582,8 +1633,6 @@ private:
// and has a TextNodeDirectionalityMap property listing the elements whose
// direction it determines.
NodeHasTextNodeDirectionalityMap,
// Set if the node has dir=auto.
NodeHasDirAuto,
// Set if a node in the node's parent chain has dir=auto.
NodeAncestorHasDirAuto,
// Set if the element is in the scope of a scoped style sheet; this flag is
@ -1637,6 +1686,8 @@ public:
{ SetBoolFlag(NodeHasRenderingObservers, aValue); }
bool IsContent() const { return GetBoolFlag(NodeIsContent); }
bool HasID() const { return GetBoolFlag(ElementHasID); }
bool MayHaveClass() const { return GetBoolFlag(ElementMayHaveClass); }
void SetMayHaveClass() { SetBoolFlag(ElementMayHaveClass); }
bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
bool HasName() const { return GetBoolFlag(ElementHasName); }
bool MayHaveContentEditableAttr() const
@ -1676,17 +1727,6 @@ public:
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
void SetHasFixedDir() {
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
"SetHasFixedDir on text node");
SetBoolFlag(NodeHasFixedDir);
}
void ClearHasFixedDir() {
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
"ClearHasFixedDir on text node");
ClearBoolFlag(NodeHasFixedDir);
}
bool HasFixedDir() const { return GetBoolFlag(NodeHasFixedDir); }
void SetHasDirAutoSet() {
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
"SetHasDirAutoSet on text node");
@ -1715,16 +1755,12 @@ public:
return GetBoolFlag(NodeHasTextNodeDirectionalityMap);
}
void SetHasDirAuto() { SetBoolFlag(NodeHasDirAuto); }
void ClearHasDirAuto() { ClearBoolFlag(NodeHasDirAuto); }
bool HasDirAuto() const { return GetBoolFlag(NodeHasDirAuto); }
void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
bool AncestorHasDirAuto() const { return GetBoolFlag(NodeAncestorHasDirAuto); }
bool NodeOrAncestorHasDirAuto() const
{ return HasDirAuto() || AncestorHasDirAuto(); }
// Implemented in nsIContentInlines.h.
inline bool NodeOrAncestorHasDirAuto() const;
void SetIsElementInStyleScope(bool aValue) {
MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
@ -1766,8 +1802,6 @@ protected:
void ClearHasName() { ClearBoolFlag(ElementHasName); }
void SetMayHaveContentEditableAttr()
{ SetBoolFlag(ElementMayHaveContentEditableAttr); }
bool HasExplicitBaseURI() const { return GetBoolFlag(NodeHasExplicitBaseURI); }
void SetHasExplicitBaseURI() { SetBoolFlag(NodeHasExplicitBaseURI); }
void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
void ClearHasLockedStyleStates() { ClearBoolFlag(ElementHasLockedStyleStates); }
bool HasLockedStyleStates() const

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