Compare commits

..
9 Commits
Author SHA1 Message Date
wolfbeast 8efaf64266 Issue #1462 - Part 7: Add OID changes anyway. 2020-04-03 14:50:26 +02:00
wolfbeast f23b96fa7d Issue #1462 - Part 3b: Actually commit -all- the code, and fix space 2020-04-02 16:38:13 +02:00
wolfbeast d3594baa4b Issue #1462 - Part 6: Don't mess with OIDs, that's a different spec. 2020-04-02 16:36:34 +02:00
wolfbeast 3388887038 Issue #1462 - Part 5: Security manager changes for Camellia-GCM suites. 2020-04-02 12:53:15 +02:00
wolfbeast a0aae25860 Issue #1462 - Part 4: Add Camellia-GCM suites to NSS
This excludes non-ephemeral suites and DSS suites listed in the RFC
because they would not see use, and is primarily based on what GnuTLS
and mbedTLS support in practice, reducing the 20 listed suites to 8.
2020-04-02 12:51:58 +02:00
wolfbeast 51e6c2cf48 Issue #1462 - Part 3: Add Camellia-GCM capabilities to NSS 2020-04-02 12:47:17 +02:00
wolfbeast 83d4264496 Merge branch 'master' into RFC6367 2020-04-02 10:19:53 +02:00
wolfbeast 813dd63694 Issue #1462 Part 2: Implement security manager changes for RFC 6367 §2.1
This prefs and enables ECDHA-ECDSA and ECDHA-RSA variants of Camellia
CBC suites (128/256-bit)
2020-02-24 22:23:04 +01:00
wolfbeast 099a1ea88c Issue #1462 - Part 1: Implement HMAC-based Camellia suites in NSS.
This implements the ephemeral suites from RFC 6367 section 2.1 in NSS,
providing the back-end support for these suites.
2020-02-24 22:20:40 +01:00
3053 changed files with 398283 additions and 22520 deletions

No files matched your search

+1 -1
View File
@@ -52,7 +52,7 @@ $(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status $(BUILD_BAC
# try and make this not have to happen, we actually want dist/bin to be
# completely removed regardless.
default alldep all::
@$(RM) -r $(DIST)/bin
$(RM) -r $(DIST)/bin
ifndef JS_STANDALONE
ifdef COMPILE_ENVIRONMENT
$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
+1 -1
View File
@@ -18,7 +18,7 @@ directory. This will contain relevant documentation regarding contributing,
using and distributing this code and its binaries.
If you are interested in the development and building side of things, some
information will be available on the [Pale Moon developer site](http://developer.palemoon.org).
information will be available on the [Pale Moon developer wiki](http://developer.palemoon.org).
You are also always welcome to get in touch with our community on the [Pale Moon forum](https://forum.palemoon.org/).
### A note about trademarks and branding
-36
View File
@@ -1,36 +0,0 @@
# 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).
+10
View File
@@ -347,6 +347,16 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
eLandmark,
kNoReqStates
},
{ // marquee
&nsGkAtoms::marquee,
roles::ANIMATION,
kUseMapRole,
eNoValue,
eNoAction,
eOffLiveAttr,
kGenericAccType,
kNoReqStates
},
{ // math
&nsGkAtoms::math,
roles::FLAT_EQUATION,
+3
View File
@@ -732,6 +732,8 @@ using namespace mozilla::a11y;
return @"AXDocument";
if (roleAtom == nsGkAtoms::log_)
return @"AXApplicationLog";
if (roleAtom == nsGkAtoms::marquee)
return @"AXApplicationMarquee";
if (roleAtom == nsGkAtoms::math)
return @"AXDocumentMath";
if (roleAtom == nsGkAtoms::note_)
@@ -867,6 +869,7 @@ static const RoleDescrMap sRoleDescrMap[] = {
{ @"AXApplicationAlert", NS_LITERAL_STRING("alert") },
{ @"AXApplicationAlertDialog", NS_LITERAL_STRING("alertDialog") },
{ @"AXApplicationLog", NS_LITERAL_STRING("log") },
{ @"AXApplicationMarquee", NS_LITERAL_STRING("marquee") },
{ @"AXApplicationStatus", NS_LITERAL_STRING("status") },
{ @"AXApplicationTimer", NS_LITERAL_STRING("timer") },
{ @"AXContentSeparator", NS_LITERAL_STRING("separator") },
@@ -62,6 +62,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036
testAbsentAttrs("live3", {"live" : ""});
testAttrs("log", {"live" : "polite"}, true);
testAttrs("logAssertive", {"live" : "assertive"}, true);
testAttrs("marquee", {"live" : "off"}, true);
testAttrs("status", {"live" : "polite"}, true);
testAttrs("timer", {"live" : "off"}, true);
testAbsentAttrs("tablist", {"live" : "polite"});
@@ -71,6 +72,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036
testAttrs("live2Child", {"container-live" : "polite"}, true);
testAttrs("logChild", {"container-live" : "polite"}, true);
testAttrs("logAssertiveChild", {"container-live" : "assertive"}, true);
testAttrs("marqueeChild", {"container-live" : "off"}, true);
testAttrs("statusChild", {"container-live" : "polite"}, true);
testAttrs("timerChild", {"container-live" : "off"}, true);
testAbsentAttrs("tablistChild", {"container-live" : "polite"});
@@ -78,11 +80,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036
// container-live-role object attribute
testAttrs("log", {"container-live-role" : "log"}, true);
testAttrs("logAssertive", {"container-live-role" : "log"}, true);
testAttrs("marquee", {"container-live-role" : "marquee"}, true);
testAttrs("status", {"container-live-role" : "status"}, true);
testAttrs("timer", {"container-live-role" : "timer"}, true);
testAttrs("logChild", {"container-live-role" : "log"}, true);
testAttrs("logAssertive", {"container-live-role" : "log"}, true);
testAttrs("logAssertiveChild", {"container-live-role" : "log"}, true);
testAttrs("marqueeChild", {"container-live-role" : "marquee"}, true);
testAttrs("statusChild", {"container-live-role" : "status"}, true);
testAttrs("timerChild", {"container-live-role" : "timer"}, true);
testAbsentAttrs("tablistChild", {"container-live-role" : "tablist"});
@@ -226,9 +230,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=558036
<!-- back to aria -->
<div id="live" aria-live="polite">excuse <div id="liveChild">me</div></div>
<div id="live2" role="marquee" aria-live="polite">excuse <div id="live2Child">me</div></div>
<div id="live3" role="region">excuse</div>
<div id="log" role="log">excuse <div id="logChild">me</div></div>
<div id="logAssertive" role="log" aria-live="assertive">excuse <div id="logAssertiveChild">me</div></div>
<div id="marquee" role="marquee">excuse <div id="marqueeChild">me</div></div>
<div id="status" role="status">excuse <div id="statusChild">me</div></div>
<div id="tablist" role="tablist">tablist <div id="tablistChild">tab</div></div>
<div id="timer" role="timer">excuse <div id="timerChild">me</div></div>
@@ -83,7 +83,7 @@
'listitem-2-3']);
queueTraversalSequence(gQueue, docAcc, TraversalRules.Graphic, null,
['image-1', 'image-2', 'image-3']);
['image-2', 'image-3']);
queueTraversalSequence(gQueue, docAcc, TraversalRules.Link, null,
['link-0', 'link-1', 'link-2', 'link-3']);
@@ -117,7 +117,7 @@
'1. Scheme', '2. Racket', '3. Clojure',
'4. Standard Lisp', 'link-0', ' Lisp',
'checkbox-1-5', ' LeLisp', '• JavaScript',
'heading-5', 'image-1', 'image-2', 'image-3',
'heading-5', 'image-2', 'image-3',
'Not actually an image', 'link-1', 'anchor-1',
'link-2', 'anchor-2', 'link-3', '3', '1', '4',
'1', 'Sunday', 'M', 'Week 1', '3', '4', '7', '2',
@@ -41,6 +41,7 @@
testRole("aria_listbox", ROLE_LISTBOX);
testRole("aria_listitem", ROLE_LISTITEM);
testRole("aria_log", ROLE_TEXT); // weak role
testRole("aria_marquee", ROLE_ANIMATION);
testRole("aria_math", ROLE_FLAT_EQUATION);
testRole("aria_menu", ROLE_MENUPOPUP);
testRole("aria_menubar", ROLE_MENUBAR);
@@ -88,6 +89,9 @@
testRole("log_table", ROLE_TABLE);
testRole("timer_div", ROLE_SECTION);
// other roles that are forms of "live regions"
testRole("marquee_h1", ROLE_ANIMATION);
// strong landmark
testRole("application", ROLE_APPLICATION);
testRole("form", ROLE_FORM);
@@ -215,6 +219,7 @@
<span id="aria_listbox" role="listbox"/>
<span id="aria_listitem" role="listitem"/>
<span id="aria_log" role="log"/>
<span id="aria_marquee" role="marquee"/>
<span id="aria_math" role="math"/>
<span id="aria_menu" role="menu"/>
<span id="aria_menubar" role="menubar"/>
@@ -258,6 +263,7 @@
<table role="log" id="log_table">
<tr><td>Table based log</td></tr>
</table>
<h1 role="marquee" id="marquee_h1">marquee</h1>
<div role="timer" id="timer_div">timer</div>
<!-- landmarks -->
@@ -20,8 +20,8 @@
document.getElementsByTagName("img")[0].firstChild.data = "2";
var accTree = {
role: ROLE_GRAPHIC,
children: []
role: ROLE_TEXT,
children: [ { role: ROLE_TEXT_LEAF } ]
};
testAccessibleTree("the_img", accTree);
SimpleTest.finish();
+5 -8
View File
@@ -381,14 +381,11 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
SUN_ARCH=i386
_ISAINFO=`isainfo -k 2>/dev/null`
if [ "$_ISAINFO" = "amd64" ]; then
SUN_ARCH=x86_64
elif [ "$CC_FOR_BUILD" != no_compiler_found ]; then
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
+1 -1
View File
@@ -38,7 +38,7 @@ if test -n "$USE_ICU"; then
dnl We also don't do it on Windows because sometimes the file goes
dnl missing -- possibly due to overzealous antivirus software? --
dnl which prevents the browser from starting up :(
if test -z "$JS_STANDALONE"; then
if test -z "$JS_STANDALONE" -a "$OS_TARGET" != WINNT -a "$MOZ_WIDGET_TOOLKIT" != "android"; then
MOZ_ICU_DATA_ARCHIVE=1
else
MOZ_ICU_DATA_ARCHIVE=
+16 -27
View File
@@ -610,7 +610,7 @@ imply_option('--enable-project', application)
def default_project(build_env, help):
if build_env.topobjdir.endswith('/js/src'):
return 'js'
return 'application/xulrunner'
return 'browser'
option('--enable-project', nargs=1, default=default_project,
help='Project to build')
@@ -618,22 +618,28 @@ option('--enable-project', nargs=1, default=default_project,
option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
help='External directory containing additional build files')
@depends('--enable-project', '--with-external-source-dir', check_build_environment, '--help')
@depends('--enable-project', '--with-external-source-dir',
check_build_environment, '--help')
@imports(_from='os.path', _import='exists')
def include_project_configure(project, external_source_dir, build_env, help):
base_dir = build_env.topsrcdir
if not project:
die('--enable-project is required.')
base_dir = build_env.topsrcdir
if external_source_dir:
base_dir = os.path.join(base_dir, external_source_dir[0])
build_app = project[0]
if not external_source_dir and build_app not in ('xulrunner', 'js'):
die('Cannot find project %s', build_app)
path_project_src_dir_root = os.path.join(base_dir, build_app, 'moz.configure')
if exists(path_project_src_dir_root):
return path_project_src_dir_root
else:
return os.path.join(build_env.topsrcdir, 'toolkit', 'moz.configure')
die('Cannot find project %s', build_app)
@depends('--with-external-source-dir')
def external_source_dir(value):
@@ -643,29 +649,12 @@ def external_source_dir(value):
set_config('EXTERNAL_SOURCE_DIR', external_source_dir)
add_old_configure_assignment('EXTERNAL_SOURCE_DIR', external_source_dir)
@depends('--enable-project', '--with-external-source-dir', check_build_environment, '--help')
@imports(_from='os.path', _import='exists')
def build_project(project, external_source_dir, build_env, help):
if not project:
die('--enable-project is required.')
base_dir = build_env.topsrcdir
if external_source_dir:
base_dir = os.path.join(base_dir, external_source_dir[0])
build_app = project[0]
if not external_source_dir and build_app not in ('xulrunner', 'js'):
die('Cannot find project %s', build_app)
build_app_abspath = os.path.join(base_dir, build_app)
if exists(build_app_abspath):
return os.path.relpath(build_app_abspath, build_env.topsrcdir)
else:
die('Cannot find project %s', build_app)
@depends(include_project_configure, check_build_environment, '--help')
def build_project(include_project_configure, build_env, help):
ret = os.path.dirname(os.path.relpath(include_project_configure,
build_env.topsrcdir))
return ret
set_config('MOZ_BUILD_APP', build_project)
set_define('MOZ_BUILD_APP', build_project)
-1
View File
@@ -157,7 +157,6 @@ def old_configure_options(*options):
'--enable-accessibility',
'--enable-address-sanitizer',
'--enable-alsa',
'--enable-av1',
'--enable-b2g-bt',
'--enable-b2g-camera',
'--enable-b2g-ril',
+5
View File
@@ -16,6 +16,11 @@ ac_add_options --enable-crashreporter
ac_add_options --enable-release
# Disable checking that add-ons are signed by the trusted root
MOZ_ADDON_SIGNING=${MOZ_ADDON_SIGNING-0}
# Disable enforcing that add-ons are signed by the trusted root
MOZ_REQUIRE_SIGNING=${MOZ_REQUIRE_SIGNING-0}
ac_add_options --enable-js-shell
. "$topsrcdir/build/mozconfig.automation"
-72
View File
@@ -1,72 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
import os, sys
if not len(sys.argv) is 2 or not os.path.exists(sys.argv[1]):
print("\nYou did not supply a valid path to check.")
exit(1)
else:
print("\nChecking for un-preprocessed files...", end = ' ')
DIST_PATH = sys.argv[1]
PP_FILE_TYPES = (
'.css',
'.dtd',
'.html',
'.js',
'.jsm',
'.xhtml',
'.xml',
'.xul',
'.manifest',
'.properties',
'.rdf'
)
PP_SPECIAL_TYPES = ('.css')
PP_DIRECTIVES = [
'define',
'if',
'ifdef',
'ifndef',
'elif',
'elifdef',
'endif',
'error',
'expand',
'filter',
'include',
'literal',
'undef',
'unfilter'
]
PP_FILES = []
PP_BAD_FILES = []
for root, directories, filenames in os.walk(DIST_PATH):
for filename in filenames:
if filename.endswith(PP_FILE_TYPES):
PP_FILES += [ os.path.join(root, filename).replace(os.sep, '/') ]
for file in PP_FILES:
with open(file) as fp:
marker = '%' if file.endswith(PP_SPECIAL_TYPES) else '#'
directives = tuple(marker + directive for directive in PP_DIRECTIVES)
for line in fp:
if line.startswith(directives):
PP_BAD_FILES += [ file.replace(DIST_PATH + '/', '') ]
fp.close()
PP_BAD_FILES = list(dict.fromkeys(PP_BAD_FILES))
print('Done!')
if len(PP_BAD_FILES) > 0:
print("\nWARNING: The following {0} file(s) in {1} may require preprocessing:\n".format(len(PP_BAD_FILES), DIST_PATH))
for file in PP_BAD_FILES:
print(file)
exit(0)
+5 -4
View File
@@ -436,22 +436,23 @@ nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
NS_ENSURE_SUCCESS(rv, rv);
}
size_t count = document->SheetCount();
int32_t count = document->GetNumberOfStyleSheets();
// 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 (size_t i = 0; i < count; i++) {
for (int32_t i = 0; i < count; i++) {
// Get the style sheet
oldSheets.AppendElement(document->SheetAt(i));
StyleSheet* styleSheet = document->GetStyleSheetAt(i);
oldSheets.AppendElement(styleSheet);
}
// 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, "SheetAt shouldn't return nullptr for "
MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
"in-range sheet indexes");
nsIURI* uri = sheet->GetSheetURI();
+6
View File
@@ -40,6 +40,12 @@ external_dirs += ['media/libwebp']
if CONFIG['CPU_ARCH'] == 'arm':
external_dirs += ['media/openmax_dl']
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
external_dirs += [
'media/sphinxbase',
'media/pocketsphinx',
]
if CONFIG['MOZ_FFVPX']:
external_dirs += ['media/ffvpx']
-3
View File
@@ -112,7 +112,6 @@ CERT_GetCertChainFromCert
CERT_GetCertEmailAddress
CERT_GetCertificateDer
CERT_GetCertificateRequestExtensions
CERT_GetCertKeyType
CERT_GetCertTimes
CERT_GetCertTrust
CERT_GetCommonName
@@ -271,7 +270,6 @@ NSS_Init
NSS_Initialize
NSS_InitWithMerge
NSS_IsInitialized
NSS_OptionGet
NSS_OptionSet
NSS_NoDB_Init
NSS_SecureMemcmp
@@ -385,7 +383,6 @@ PK11_GetNextSymKey
PK11_GetPadMechanism
PK11_GetPrivateKeyNickname
PK11_GetPrivateModulusLen
PK11_GetSlotFromPrivateKey
PK11_GetSlotID
PK11_GetSlotInfo
PK11_GetSlotName
+1 -1
View File
@@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
4.6.0
4.5.9
@@ -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, "96px", "The computed view shows the correct top");
is(top, "50%", "The computed view shows the correct top");
left = getComputedViewPropertyValue(view, "left");
is(left, "96px", "The computed view shows the correct left");
is(left, "50%", "The computed view shows the correct left");
}
+3 -9
View File
@@ -91,7 +91,7 @@ const Curl = {
if (utils.isUrlEncodedRequest(data) ||
["PUT", "POST", "PATCH"].includes(data.method)) {
postDataText = data.postDataText;
addPostData("--data-raw");
addPostData("--data");
addPostData(utils.writePostDataTextParams(postDataText));
ignoredHeaders.add("content-length");
} else if (multipartRequest) {
@@ -400,12 +400,7 @@ const CurlUtils = {
* Credit: Google DevTools
*/
escapeStringWin: function (str) {
/*
Replace dollar sign because of commands (e.g $(cmd.exe)) in
powershell when using double quotes.
Useful details http://www.rlmueller.net/PowerShellEscape.htm
Replace quote by double quote (but not by \") because it is
/* Replace quote by double quote (but not by \") because it is
recognized by both cmd.exe and MS Crt arguments parser.
Replace % by "%" because it could be expanded to an environment
@@ -419,8 +414,7 @@ const CurlUtils = {
Replace new line outside of quotes since cmd.exe doesn't let
to do it inside.
*/
return "\"" + str.replace(/\$/g, "`$")
.replace(/"/g, "\"\"")
return "\"" + str.replace(/"/g, "\"\"")
.replace(/%/g, "\"%\"")
.replace(/\\/g, "\\\\")
.replace(/[\r\n]+/g, "\"^$&\"") + "\"";
-1
View File
@@ -14,7 +14,6 @@
a {
-moz-user-focus: normal;
-moz-user-input: enabled;
cursor: pointer;
text-decoration: underline;
}
@@ -1440,8 +1440,6 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"auto",
"disabled",
"enabled",
"inherit",
"initial",
"none",
+10 -4
View File
@@ -126,7 +126,7 @@ switch (variable) {
code_for_1;
code_for_1;
break;
case value2: // Comment describing 2 (alternative)
case value2:
code_for_2;
code_for_2;
// fallthrough
@@ -273,7 +273,7 @@ Applies to `*.js` and `*.jsm`.
}
}, false);
```
- Don't use a space between `{` `}` braces in empty js objects, `{` `}` braces in empty function scopes, or `[` `]` brackets in empty arrays.
- Use a single space between `{` `}` braces in empty js objects.
### Flow control
Flow control expressions should follow the following guidelines:
@@ -343,7 +343,7 @@ switch (variable) {
code_for_1;
code_for_1;
break;
case value2: // Comment describing 2 (alternative)
case value2:
code_for_2;
code_for_2;
// fallthrough
@@ -397,7 +397,8 @@ try {
try {
do_something();
} catch(e) {}
} catch(e) {
}
try {
do_something();
@@ -413,6 +414,11 @@ try {
// No error processing
do_something_else();
}
// No closing brace on its own line
try {
do_something();
} catch(ex) { }
```
### Long line wrapping
-6
View File
@@ -860,12 +860,6 @@ nsDocShell::~nsDocShell()
shPrivate->SetRootDocShell(nullptr);
}
if (mContentViewer) {
mContentViewer->Close(nullptr);
mContentViewer->Destroy();
mContentViewer = nullptr;
}
if (--gDocShellCount == 0) {
NS_IF_RELEASE(sURIFixup);
}
-98
View File
@@ -1,98 +0,0 @@
/* -*- 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 "AbortController.h"
#include "AbortSignal.h"
#include "mozilla/dom/AbortControllerBinding.h"
#include "WorkerPrivate.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AbortController, mGlobal, mSignal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortController)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortController)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortController)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
/* static */ bool
AbortController::IsEnabled(JSContext* aCx, JSObject* aGlobal)
{
if (NS_IsMainThread()) {
return Preferences::GetBool("dom.abortController.enabled", false);
}
using namespace workers;
// Otherwise, check the pref via the WorkerPrivate
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
if (!workerPrivate) {
return false;
}
return workerPrivate->AbortControllerEnabled();
}
/* static */ already_AddRefed<AbortController>
AbortController::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<AbortController> abortController = new AbortController(global);
return abortController.forget();
}
AbortController::AbortController(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
, mAborted(false)
{}
JSObject*
AbortController::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return AbortControllerBinding::Wrap(aCx, this, aGivenProto);
}
nsIGlobalObject*
AbortController::GetParentObject() const
{
return mGlobal;
}
AbortSignal*
AbortController::Signal()
{
if (!mSignal) {
mSignal = new AbortSignal(this, mAborted);
}
return mSignal;
}
void
AbortController::Abort()
{
if (mAborted) {
return;
}
mAborted = true;
if (mSignal) {
mSignal->Abort();
}
}
} // dom namespace
} // mozilla namespace
-59
View File
@@ -1,59 +0,0 @@
/* -*- 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_AbortController_h
#define mozilla_dom_AbortController_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/AbortSignal.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/ErrorResult.h"
#include "nsIGlobalObject.h"
namespace mozilla {
namespace dom {
class AbortController final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbortController)
static bool
IsEnabled(JSContext* aCx, JSObject* aGlobal);
static already_AddRefed<AbortController>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
explicit AbortController(nsIGlobalObject* aGlobal);
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsIGlobalObject*
GetParentObject() const;
AbortSignal*
Signal();
void
Abort();
private:
~AbortController() = default;
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<AbortSignal> mSignal;
bool mAborted;
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_AbortController_h
-124
View File
@@ -1,124 +0,0 @@
/* -*- 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 "AbortSignal.h"
#include "AbortController.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/AbortSignalBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AbortSignal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AbortSignal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mController)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AbortSignal)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(AbortSignal, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(AbortSignal, DOMEventTargetHelper)
AbortSignal::AbortSignal(AbortController* aController,
bool aAborted)
: DOMEventTargetHelper(aController->GetParentObject())
, mController(aController)
, mAborted(aAborted)
{}
AbortSignal::AbortSignal(bool aAborted)
: mAborted(aAborted)
{}
JSObject*
AbortSignal::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return AbortSignalBinding::Wrap(aCx, this, aGivenProto);
}
bool
AbortSignal::Aborted() const
{
return mAborted;
}
void
AbortSignal::Abort()
{
MOZ_ASSERT(!mAborted);
mAborted = true;
// Let's inform the followers.
for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
mFollowers[i]->Aborted();
}
EventInit init;
init.mBubbles = false;
init.mCancelable = false;
RefPtr<Event> event =
Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
event->SetTrusted(true);
bool dummy;
DispatchEvent(event, &dummy);
}
void
AbortSignal::AddFollower(AbortSignal::Follower* aFollower)
{
MOZ_DIAGNOSTIC_ASSERT(aFollower);
if (!mFollowers.Contains(aFollower)) {
mFollowers.AppendElement(aFollower);
}
}
void
AbortSignal::RemoveFollower(AbortSignal::Follower* aFollower)
{
MOZ_DIAGNOSTIC_ASSERT(aFollower);
mFollowers.RemoveElement(aFollower);
}
// AbortSignal::Follower
// ----------------------------------------------------------------------------
AbortSignal::Follower::~Follower()
{
Unfollow();
}
void
AbortSignal::Follower::Follow(AbortSignal* aSignal)
{
MOZ_DIAGNOSTIC_ASSERT(aSignal);
Unfollow();
mFollowingSignal = aSignal;
aSignal->AddFollower(this);
}
void
AbortSignal::Follower::Unfollow()
{
if (mFollowingSignal) {
mFollowingSignal->RemoveFollower(this);
mFollowingSignal = nullptr;
}
}
} // dom namespace
} // mozilla namespace
-76
View File
@@ -1,76 +0,0 @@
/* -*- 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_AbortSignal_h
#define mozilla_dom_AbortSignal_h
#include "mozilla/DOMEventTargetHelper.h"
namespace mozilla {
namespace dom {
class AbortController;
class AbortSignal;
class AbortSignal final : public DOMEventTargetHelper
{
public:
// This class must be implemented by objects who want to follow a AbortSignal.
class Follower
{
public:
virtual void Aborted() = 0;
protected:
virtual ~Follower();
void
Follow(AbortSignal* aSignal);
void
Unfollow();
RefPtr<AbortSignal> mFollowingSignal;
};
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AbortSignal, DOMEventTargetHelper)
AbortSignal(AbortController* aController, bool aAborted);
explicit AbortSignal(bool aAborted);
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
bool
Aborted() const;
void
Abort();
IMPL_EVENT_HANDLER(abort);
void
AddFollower(Follower* aFollower);
void
RemoveFollower(Follower* aFollower);
private:
~AbortSignal() = default;
RefPtr<AbortController> mController;
// Raw pointers. Follower unregisters itself in the DTOR.
nsTArray<Follower*> mFollowers;
bool mAborted;
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_AbortSignal_h
-113
View File
@@ -1,113 +0,0 @@
<script>
function ok(a, msg) {
parent.postMessage({ type: "check", status: !!a, message: msg }, "*");
}
function is(a, b, msg) {
ok(a === b, msg);
}
function testWebIDL() {
ok("FetchController" in self, "We have a FetchController prototype");
ok("FetchSignal" in self, "We have a FetchSignal prototype");
var fc = new FetchController();
ok(!!fc, "FetchController can be created");
ok(fc instanceof FetchController, "FetchController is a FetchController");
ok(!!fc.signal, "FetchController has a signal");
ok(fc.signal instanceof FetchSignal, "fetchSignal is a FetchSignal");
is(fc.signal.aborted, false, "By default FetchSignal.aborted is false");
next();
}
function testUpdateData() {
var fc = new FetchController();
is(fc.signal.aborted, false, "By default FetchSignal.aborted is false");
fc.abort();
is(fc.signal.aborted, true, "Signal is aborted");
next();
}
function testAbortEvent() {
var fc = new FetchController();
fc.signal.onabort = function(e) {
is(e.type, "abort", "Abort received");
next();
}
fc.abort();
}
function testAbortedFetch() {
var fc = new FetchController();
fc.abort();
fetch('slow.sjs', { signal: fc.signal }).then(() => {
ok(false, "Fetch should not return a resolved promise");
}, e => {
is(e.name, "AbortError", "We have an abort error");
}).then(next);
}
function testFetchAndAbort() {
var fc = new FetchController();
var p = fetch('slow.sjs', { signal: fc.signal });
fc.abort();
p.then(() => {
ok(false, "Fetch should not return a resolved promise");
}, e => {
is(e.name, "AbortError", "We have an abort error");
}).then(next);
}
function testWorkerAbortedFetch() {
var w = new Worker('worker_fetch_controller.js');
w.onmessage = function(e) {
ok(e.data, "Abort + Fetch works in workers");
next();
}
w.postMessage('testWorkerAbortedFetch');
}
function testWorkerFetchAndAbort() {
var w = new Worker('worker_fetch_controller.js');
w.onmessage = function(e) {
ok(e.data, "Abort + Fetch works in workers");
next();
}
w.postMessage('testWorkerFetchAndAbort');
}
var steps = [
// Simple stuff
testWebIDL,
testUpdateData,
// Event propagation
testAbortEvent,
// fetch + signaling
testAbortedFetch,
testFetchAndAbort,
testWorkerAbortedFetch,
testWorkerFetchAndAbort,
];
function next() {
if (!steps.length) {
parent.postMessage({ type: "finish" }, "*");
return;
}
var step = steps.shift();
step();
}
next();
</script>
-6
View File
@@ -1,6 +0,0 @@
[DEFAULT]
support-files =
file_abort_controller.html
worker_fetch_controller.js
[test_abort_controller.html]
@@ -1,40 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test FetchController</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
SpecialPowers.pushPrefEnv({"set": [["dom.fetchController.enabled", true ]]}, () => {
let ifr = document.createElement('iframe');
ifr.src = "file_fetch_controller.html";
document.body.appendChild(ifr);
onmessage = function(e) {
if (e.data.type == "finish") {
SimpleTest.finish();
return;
}
if (e.data.type == "check") {
ok(e.data.status, e.data.message);
return;
}
ok(false, "Something when wrong.");
}
});
SimpleTest.waitForExplicitFinish();
</script>
</body>
</html>
@@ -1,27 +0,0 @@
function testWorkerAbortedFetch() {
var fc = new AbortController();
fc.abort();
fetch('slow.sjs', { signal: fc.signal }).then(() => {
postMessage(false);
}, e => {
postMessage(e.name == "AbortError");
});
}
function testWorkerFetchAndAbort() {
var fc = new AbortController();
var p = fetch('slow.sjs', { signal: fc.signal });
fc.abort();
p.then(() => {
postMessage(false);
}, e => {
postMessage(e.name == "AbortError");
});
}
onmessage = function(e) {
self[e.data]();
}
-2
View File
@@ -7,8 +7,6 @@
#ifndef mozilla_AnimationComparator_h
#define mozilla_AnimationComparator_h
#include "mozilla/dom/Animation.h"
namespace mozilla {
// Although this file is called AnimationComparator, we don't actually
@@ -6,7 +6,6 @@
#include "mozilla/dom/AnimationEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/FloatingPoint.h"
@@ -9,9 +9,6 @@
#include <initializer_list>
#include "mozilla/Maybe.h"
#include "nsTArray.h"
class nsXPIDLString;
namespace mozilla {
-1
View File
@@ -7,7 +7,6 @@
#include "mozilla/dom/CSSPseudoElement.h"
#include "mozilla/dom/CSSPseudoElementBinding.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/KeyframeEffectBinding.h" // for ElementOrCSSPseudoElement class
#include "mozilla/AnimationComparator.h"
namespace mozilla {
+15 -7
View File
@@ -356,16 +356,24 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement,
return aElement;
}
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (!primaryFrame) {
return nullptr;
}
nsIFrame* pseudoFrame;
if (aPseudoType == CSSPseudoElementType::before) {
return nsLayoutUtils::GetBeforePseudo(aElement);
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;
}
if (aPseudoType == CSSPseudoElementType::after) {
return nsLayoutUtils::GetAfterPseudo(aElement);
if (!pseudoFrame) {
return nullptr;
}
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
"other that :before or :after");
return nullptr;
return pseudoFrame->GetContent()->AsElement();
}
bool
-1
View File
@@ -11,7 +11,6 @@
#include "mozilla/dom/AnimationEffectTiming.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/KeyframeUtils.h"
#include "nsContentUtils.h"
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsIScriptError.h"
+7 -7
View File
@@ -6,7 +6,6 @@
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
#include "mozilla/dom/CSSPseudoElement.h"
@@ -26,7 +25,6 @@
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsIPresShell.h"
#include "nsIScriptError.h"
#include "nsRefreshDriver.h"
namespace mozilla {
@@ -1107,17 +1105,19 @@ KeyframeEffectReadOnly::GetAnimationFrame() const
return nullptr;
}
nsIFrame* frame;
nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
if (!frame) {
return nullptr;
}
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
frame = nsLayoutUtils::GetBeforeFrame(frame);
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
frame = nsLayoutUtils::GetAfterFrame(frame);
} else {
frame = mTarget->mElement->GetPrimaryFrame();
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
"unknown mTarget->mPseudoType");
}
if (!frame) {
return nullptr;
}
+2 -5
View File
@@ -37,11 +37,6 @@ EXPORTS.mozilla += [
]
UNIFIED_SOURCES += [
'KeyframeEffect.cpp',
'KeyframeEffectReadOnly.cpp',
]
SOURCES += [
'Animation.cpp',
'AnimationEffectReadOnly.cpp',
'AnimationEffectTiming.cpp',
@@ -55,7 +50,9 @@ SOURCES += [
'DocumentTimeline.cpp',
'EffectCompositor.cpp',
'EffectSet.cpp',
'KeyframeEffect.cpp',
'KeyframeEffectParams.cpp',
'KeyframeEffectReadOnly.cpp',
'KeyframeUtils.cpp',
'PendingAnimationTracker.cpp',
'TimingParams.cpp',
+2 -4
View File
@@ -8,12 +8,10 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/ArchiveRequestBinding.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsContentUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
USING_ARCHIVEREADER_NAMESPACE
@@ -71,10 +69,10 @@ ArchiveRequest::~ArchiveRequest()
}
nsresult
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
aVisitor.SetParentTarget(nullptr, false);
aVisitor.mParentTarget = nullptr;
return NS_OK;
}
+1 -2
View File
@@ -38,8 +38,7 @@ public:
ArchiveReader* aReader);
// nsIDOMEventTarget
virtual nsresult GetEventTargetParent(
EventChainPreVisitor& aVisitor) override;
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
public:
// This is called by the DOMArchiveRequestEvent
-1
View File
@@ -12,7 +12,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/dom/File.h"
using namespace mozilla;
using namespace mozilla::dom;
USING_ARCHIVEREADER_NAMESPACE
+1 -1
View File
@@ -13,7 +13,7 @@ EXPORTS.mozilla.dom.archivereader += [
'ArchiveZipFile.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'ArchiveEvent.cpp',
'ArchiveReader.cpp',
'ArchiveRequest.cpp',
+4 -2
View File
@@ -16,12 +16,14 @@ EXPORTS += [
'AudioChannelService.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'AudioChannelAgent.cpp',
'AudioChannelService.cpp',
]
LOCAL_INCLUDES += ['/dom/base/']
LOCAL_INCLUDES += [
'/dom/base/',
]
include('/ipc/chromium/chromium-config.mozbuild')
-27
View File
@@ -7,7 +7,6 @@
#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"
@@ -209,31 +208,5 @@ 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
-5
View File
@@ -68,11 +68,6 @@ 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;
+1 -1
View File
@@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
}
nsresult
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
return NS_OK;
+1 -1
View File
@@ -54,7 +54,7 @@ public:
// nsIDOMAttr interface
NS_DECL_NSIDOMATTR
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
// nsIAttribute interface
void SetMap(nsDOMAttributeMap *aMap) override;
-3
View File
@@ -8,9 +8,6 @@
#define mozilla_dom_BlobSet_h
#include "mozilla/RefPtr.h"
#include "jsfriendapi.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
-2
View File
@@ -4,8 +4,6 @@
* 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_
+179 -122
View File
@@ -6,27 +6,61 @@
#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 {
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
bool aStartAtBeginning)
: mParent(aParent),
mChild(nullptr),
mDefaultChild(nullptr),
mIsFirst(aStartAtBeginning),
mIndexInInserted(0)
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)
{
mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
HTMLSlotElement::FromContent(mParent) : nullptr;
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));
}
nsIContent*
@@ -35,29 +69,30 @@ 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);
if (mParentAsSlot) {
const nsTArray<RefPtr<nsINode>>& assignedNodes =
mParentAsSlot->AssignedNodes();
mChild = (mIndexInInserted < assignedNodes.Length()) ?
assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
return mChild;
}
MOZ_ASSERT(mChild->IsActiveChildrenElement());
auto* childrenElement =
static_cast<XBLChildrenElement*>(mChild);
if (mIndexInInserted < childrenElement->InsertedChildrenLength()) {
return childrenElement->InsertedChild(mIndexInInserted++);
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;
}
mShadowIterator = nullptr;
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(mChild->IsActiveChildrenElement());
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
mDefaultChild = mDefaultChild->GetNextSibling();
if (mDefaultChild) {
@@ -66,19 +101,6 @@ 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
@@ -88,16 +110,31 @@ ExplicitChildIterator::GetNextChild()
// Iterate until we find a non-insertion point, or an insertion point with
// content.
while (mChild) {
if (mChild->IsActiveChildrenElement()) {
// 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 the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
auto* childrenElement =
static_cast<XBLChildrenElement*>(mChild);
if (childrenElement->HasInsertedChildren()) {
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (!assignedChildren.IsEmpty()) {
// Iterate through elements projected on insertion point.
mIndexInInserted = 1;
return childrenElement->InsertedChild(0);
return assignedChildren[0];
}
// Insertion points inside fallback/default content
@@ -155,17 +192,19 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
}
bool
ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
{
if (aChildToFind->GetParent() == mParent &&
!aChildToFind->IsRootOfAnonymousSubtree()) {
// Fast path: just point ourselves to aChildToFind, which is a
// normal DOM child of ours.
mChild = const_cast<nsIContent*>(aChildToFind);
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
mChild = aChildToFind;
mIndexInInserted = 0;
mShadowIterator = nullptr;
mDefaultChild = nullptr;
mIsFirst = false;
MOZ_ASSERT(!mChild->IsActiveChildrenElement());
return true;
}
@@ -181,18 +220,12 @@ ExplicitChildIterator::Get() const
{
MOZ_ASSERT(!mIsFirst);
// 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);
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
return assignedChildren[mIndexInInserted - 1];
} else if (mShadowIterator) {
return mShadowIterator->Get();
}
return mDefaultChild ? mDefaultChild : mChild;
}
@@ -201,28 +234,20 @@ 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.
MOZ_ASSERT(mChild->IsActiveChildrenElement());
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (--mIndexInInserted) {
return childrenElement->InsertedChild(mIndexInInserted - 1);
return assignedChildren[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();
@@ -236,32 +261,35 @@ 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 (mChild->IsActiveChildrenElement()) {
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 the current child being iterated is a content insertion point
// then the iterator needs to return the nodes distributed into
// the content insertion point.
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
if (childrenElement->HasInsertedChildren()) {
mIndexInInserted = childrenElement->InsertedChildrenLength();
return childrenElement->InsertedChild(mIndexInInserted - 1);
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
if (!assignedChildren.IsEmpty()) {
mIndexInInserted = assignedChildren.Length();
return assignedChildren[mIndexInInserted - 1];
}
mDefaultChild = mChild->GetLastChild();
@@ -289,9 +317,11 @@ AllChildrenIterator::Get() const
{
switch (mPhase) {
case eAtBeforeKid: {
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
return before;
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();
}
case eAtExplicitKids:
@@ -301,9 +331,11 @@ AllChildrenIterator::Get() const
return mAnonKids[mAnonKidsIdx];
case eAtAfterKid: {
Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
return after;
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();
}
default:
@@ -313,14 +345,19 @@ AllChildrenIterator::Get() const
bool
AllChildrenIterator::Seek(const nsIContent* aChildToFind)
AllChildrenIterator::Seek(nsIContent* aChildToFind)
{
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
mPhase = eAtExplicitKids;
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforePseudo && beforePseudo == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
if (beforeFrame->GetContent() == aChildToFind) {
mPhase = eAtBeforeKid;
return true;
}
}
}
}
@@ -346,10 +383,12 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
mOriginalContent->OwnerDoc(), mAnonKids);
if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
if (scrollFrame) {
AppendNativeAnonymousChildrenFromFrame(scrollFrame);
}
}
}
@@ -367,10 +406,13 @@ AllChildrenIterator::GetNextChild()
{
if (mPhase == eAtBegin) {
mPhase = eAtExplicitKids;
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforeContent) {
mPhase = eAtBeforeKid;
return beforeContent;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
@@ -406,10 +448,13 @@ AllChildrenIterator::GetNextChild()
return mAnonKids[mAnonKidsIdx];
}
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
if (afterContent) {
mPhase = eAtAfterKid;
return afterContent;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
@@ -423,10 +468,13 @@ AllChildrenIterator::GetPreviousChild()
if (mPhase == eAtEnd) {
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
mPhase = eAtAnonKids;
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
if (afterContent) {
mPhase = eAtAfterKid;
return afterContent;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
if (afterFrame) {
mPhase = eAtAfterKid;
return afterFrame->GetContent();
}
}
}
@@ -455,10 +503,13 @@ AllChildrenIterator::GetPreviousChild()
return kid;
}
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
if (beforeContent) {
mPhase = eAtBeforeKid;
return beforeContent;
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
if (frame) {
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
if (beforeFrame) {
mPhase = eAtBeforeKid;
return beforeFrame->GetContent();
}
}
}
@@ -534,6 +585,12 @@ 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;
}
+36 -41
View File
@@ -36,20 +36,27 @@ class ExplicitChildIterator
{
public:
explicit ExplicitChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true);
bool aStartAtBeginning = true)
: mParent(aParent),
mChild(nullptr),
mDefaultChild(nullptr),
mIndexInInserted(0),
mIsFirst(aStartAtBeginning)
{
}
ExplicitChildIterator(const ExplicitChildIterator& aOther)
: mParent(aOther.mParent),
mParentAsSlot(aOther.mParentAsSlot),
mChild(aOther.mChild),
: mParent(aOther.mParent), 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),
mParentAsSlot(aOther.mParentAsSlot),
mChild(aOther.mChild),
: mParent(aOther.mParent), mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(Move(aOther.mShadowIterator)),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
nsIContent* GetNextChild();
@@ -58,13 +65,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(const nsIContent* aChildToFind);
bool Seek(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(const nsIContent* aChildToFind, nsIContent* aBound)
bool Seek(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
@@ -95,10 +102,6 @@ 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
@@ -111,6 +114,11 @@ 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
@@ -131,29 +139,19 @@ class FlattenedChildIterator : public ExplicitChildIterator
public:
explicit FlattenedChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
{
Init(false);
}
FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther))
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
: ExplicitChildIterator(aOther)
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
{}
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
bool XBLInvolved() { return mXBLInvolved; }
const nsIContent* Parent() const { return mOriginalContent; }
protected:
/**
* This constructor is a hack to help AllChildrenIterator which sometimes
@@ -161,9 +159,7 @@ protected:
*/
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
{
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
Init(ignoreXBL);
@@ -174,8 +170,6 @@ 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;
};
/**
@@ -193,11 +187,12 @@ public:
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
bool aStartAtBeginning = true) :
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
mOriginalContent(aNode), 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
@@ -216,10 +211,11 @@ 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(const nsIContent* aChildToFind);
bool Seek(nsIContent* aChildToFind);
nsIContent* GetNextChild();
nsIContent* GetPreviousChild();
const nsIContent* Parent() const { return mOriginalContent; }
enum IteratorPhase
{
@@ -237,6 +233,8 @@ 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
@@ -258,11 +256,10 @@ 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 | 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).
* 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).
*
* 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.
@@ -270,9 +267,7 @@ private:
class StyleChildrenIterator : private AllChildrenIterator {
public:
explicit StyleChildrenIterator(const nsIContent* aContent)
: AllChildrenIterator(aContent,
nsIContent::eAllChildren |
nsIContent::eSkipDocumentLevelNativeAnonymousContent)
: AllChildrenIterator(aContent, nsIContent::eAllChildren)
{
MOZ_COUNT_CTOR(StyleChildrenIterator);
}
-1
View File
@@ -6,7 +6,6 @@
#include "mozilla/dom/ChromeNodeList.h"
#include "mozilla/dom/ChromeNodeListBinding.h"
#include "nsPIDOMWindow.h"
using namespace mozilla;
using namespace mozilla::dom;
-1
View File
@@ -6,7 +6,6 @@
#include "nsCOMArray.h"
#include "nsContentList.h"
#include "nsIDocument.h"
namespace mozilla {
class ErrorResult;
-1
View File
@@ -7,7 +7,6 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
#include "jsfriendapi.h"
namespace mozilla {
namespace dom {
-1
View File
@@ -10,7 +10,6 @@
#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 {
+27 -13
View File
@@ -11,9 +11,7 @@
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/Promise.h"
#include "nsContentUtils.h"
#include "nsHTMLTags.h"
#include "nsIParserService.h"
#include "jsapi.h"
namespace mozilla {
@@ -293,6 +291,7 @@ 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;
}
@@ -415,6 +414,19 @@ 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,
@@ -454,12 +466,6 @@ nsISupports* CustomElementRegistry::GetParentObject() const
return mWindow;
}
DocGroup*
CustomElementRegistry::GetDocGroup() const
{
return mWindow ? mWindow->GetDocGroup() : nullptr;
}
static const char* kLifeCycleCallbackNames[] = {
"connectedCallback",
"disconnectedCallback",
@@ -582,8 +588,14 @@ 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 = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
tag == eHTMLTag_multicol) {
@@ -618,9 +630,9 @@ CustomElementRegistry::Define(const nsAString& aName,
*/
JSAutoCompartment ac(cx, constructor);
JS::Rooted<JS::Value> prototypev(cx);
// 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.
// 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.
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
aRv.StealExceptionFromJSContext(cx);
return;
@@ -866,6 +878,8 @@ 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");
+7 -6
View File
@@ -27,7 +27,6 @@ struct CustomElementData;
struct ElementDefinitionOptions;
class CallbackFunction;
class CustomElementReaction;
class DocGroup;
class Function;
class Promise;
@@ -424,6 +423,9 @@ 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
@@ -432,7 +434,8 @@ public:
/**
* Registers an unresolved custom element that is a candidate for
* upgrade. |aTypeName| is the name of the custom element type, if it is not
* upgrade when the definition is registered via registerElement.
* |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">.
@@ -469,8 +472,8 @@ private:
js::SystemAllocPolicy> ConstructorMap;
// Hashtable for custom element definitions in web components.
// Custom prototypes are stored in the compartment where definition was
// defined.
// Custom prototypes are stored in the compartment where
// registerElement was called.
DefinitionMap mCustomDefinitions;
// Hashtable for looking up definitions by using constructor as key.
@@ -514,8 +517,6 @@ 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,
+2 -2
View File
@@ -728,7 +728,7 @@ WalkDescendantsResetAutoDirection(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
if (child->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
@@ -791,7 +791,7 @@ WalkDescendantsClearAncestorDirAuto(Element* aElement)
{
nsIContent* child = aElement->GetFirstChild();
while (child) {
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
if (child->HasDirAuto()) {
child = child->GetNextNonChildNode(aElement);
continue;
}
-26
View File
@@ -1,7 +1,3 @@
/* 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"
@@ -10,14 +6,10 @@
#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)
{
@@ -62,23 +54,5 @@ 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);
}
}
}
-19
View File
@@ -15,7 +15,6 @@
#include "mozilla/RefPtr.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/HTMLSlotElement.h"
namespace mozilla {
namespace dom {
@@ -74,23 +73,6 @@ 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();
@@ -99,7 +81,6 @@ private:
RefPtr<TabGroup> mTabGroup;
nsTArray<nsIDocument*> mDocuments;
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
};
} // namespace dom
-2
View File
@@ -125,8 +125,6 @@ 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
+9 -4
View File
@@ -43,7 +43,6 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
// interface nsIDOMNode
NS_FORWARD_NSIDOMNODE_TO_NSINODE
@@ -122,9 +121,15 @@ public:
return nullptr;
}
Element* GetHost() const { return mHost; }
nsIContent* GetHost() const
{
return mHost;
}
void SetHost(Element* aHost) { mHost = aHost; }
void SetHost(nsIContent* aHost)
{
mHost = aHost;
}
static already_AddRefed<DocumentFragment>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
@@ -140,7 +145,7 @@ protected:
}
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
nsCOMPtr<Element> mHost;
nsIContent* mHost; // Weak
};
} // namespace dom
-149
View File
@@ -1,149 +0,0 @@
/* -*- 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 "DocumentOrShadowRoot.h"
#include "mozilla/dom/StyleSheetList.h"
#include "nsDocument.h"
#include "nsFocusManager.h"
#include "ShadowRoot.h"
#include "XULDocument.h"
class nsINode;
class nsIDocument;
class ShadowRoot;
namespace mozilla {
namespace dom {
DocumentOrShadowRoot::DocumentOrShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot)
: mAsNode(aShadowRoot)
, mKind(Kind::ShadowRoot)
{
MOZ_ASSERT(mAsNode);
}
DocumentOrShadowRoot::DocumentOrShadowRoot(nsIDocument* aDoc)
: mAsNode(aDoc)
, mKind(Kind::Document)
{
MOZ_ASSERT(mAsNode);
}
StyleSheetList&
DocumentOrShadowRoot::EnsureDOMStyleSheets()
{
if (!mDOMStyleSheets) {
mDOMStyleSheets = new StyleSheetList(*this);
}
return *mDOMStyleSheets;
}
Element*
DocumentOrShadowRoot::GetElementById(const nsAString& aElementId)
{
if (MOZ_UNLIKELY(aElementId.IsEmpty())) {
nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
return nullptr;
}
if (nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId)) {
if (Element* el = entry->GetIdElement()) {
return el;
}
}
if (MOZ_UNLIKELY(mKind == Kind::Document &&
static_cast<nsIDocument&>(AsNode()).IsXULDocument())) {
return static_cast<XULDocument&>(AsNode()).GetRefById(aElementId);
}
return nullptr;
}
already_AddRefed<nsContentList>
DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName)
{
ErrorResult rv;
RefPtr<nsContentList> list =
GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
if (rv.Failed()) {
return nullptr;
}
return list.forget();
}
already_AddRefed<nsContentList>
DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName,
mozilla::ErrorResult& aResult)
{
int32_t nameSpaceId = kNameSpaceID_Wildcard;
if (!aNamespaceURI.EqualsLiteral("*")) {
aResult =
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
nameSpaceId);
if (aResult.Failed()) {
return nullptr;
}
}
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
return NS_GetContentList(&AsNode(), nameSpaceId, aLocalName);
}
already_AddRefed<nsContentList>
DocumentOrShadowRoot::GetElementsByClassName(const nsAString& aClasses)
{
return nsContentUtils::GetElementsByClassName(&AsNode(), aClasses);
}
nsIContent*
DocumentOrShadowRoot::Retarget(nsIContent* aContent) const
{
for (nsIContent* cur = aContent;
cur;
cur = cur->GetContainingShadowHost()) {
if (cur->SubtreeRoot() == &AsNode()) {
return cur;
}
}
return nullptr;
}
Element*
DocumentOrShadowRoot::GetRetargetedFocusedElement()
{
if (nsCOMPtr<nsPIDOMWindowOuter> window = AsNode().OwnerDoc()->GetWindow()) {
nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
nsIContent* focusedContent =
nsFocusManager::GetFocusedDescendant(window,
false,
getter_AddRefs(focusedWindow));
// be safe and make sure the element is from this document
if (focusedContent && focusedContent->OwnerDoc() == AsNode().OwnerDoc()) {
if (focusedContent->ChromeOnlyAccess()) {
focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
}
if (focusedContent) {
if (!nsDocument::IsWebComponentsEnabled(focusedContent)) {
return focusedContent->AsElement();
}
if (nsIContent* retarget = Retarget(focusedContent)) {
return retarget->AsElement();
}
}
}
}
return nullptr;
}
}
}
-160
View File
@@ -1,160 +0,0 @@
/* -*- 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_DocumentOrShadowRoot_h__
#define mozilla_dom_DocumentOrShadowRoot_h__
#include "nsTArray.h"
#include "nsIdentifierMapEntry.h"
#include "nsContentListDeclarations.h"
#include "nsNameSpaceManager.h"
#include "mozilla/dom/NameSpaceConstants.h"
class nsContentList;
class nsINode;
namespace mozilla {
class StyleSheet;
namespace dom {
class StyleSheetList;
class ShadowRoot;
/**
* 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 DocumentOrShadowRoot
{
enum class Kind {
Document,
ShadowRoot,
};
public:
explicit DocumentOrShadowRoot(nsIDocument*);
explicit DocumentOrShadowRoot(mozilla::dom::ShadowRoot*);
nsINode& AsNode()
{
return *mAsNode;
}
const nsINode& AsNode() const
{
return *mAsNode;
}
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();
Element* GetElementById(const nsAString& aElementId);
/**
* This method returns _all_ the elements in this scope which have id
* aElementId, if there are any. Otherwise it returns null.
*
* This is useful for stuff like QuerySelector optimization and such.
*/
inline const nsTArray<Element*>*
GetAllElementsForId(const nsAString& aElementId) const;
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aTagName)
{
return NS_GetContentList(&AsNode(), kNameSpaceID_Unknown, aTagName);
}
already_AddRefed<nsContentList>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName);
already_AddRefed<nsContentList>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName,
mozilla::ErrorResult&);
already_AddRefed<nsContentList>
GetElementsByClassName(const nsAString& aClasses);
~DocumentOrShadowRoot() = default;
protected:
nsIContent* Retarget(nsIContent* aContent) const;
/**
* If focused element's subtree root is this document or shadow root, return
* focused element, otherwise, get the shadow host recursively until the
* shadow host's subtree root is this document or shadow root.
*/
Element* GetRetargetedFocusedElement();
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
/*
* mIdentifierMap works as follows for IDs:
* 1) Attribute changes affect the table immediately (removing and adding
* entries as needed).
* 2) Removals from the DOM affect the table immediately
* 3) Additions to the DOM always update existing entries for names, and add
* new ones for IDs.
*/
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsINode* mAsNode;
const Kind mKind;
};
inline const nsTArray<Element*>*
DocumentOrShadowRoot::GetAllElementsForId(const nsAString& aElementId) const
{
if (aElementId.IsEmpty()) {
return nullptr;
}
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId);
return entry ? &entry->GetIdElements() : nullptr;
}
}
}
#endif
+249 -313
View File
@@ -166,7 +166,8 @@ nsIContent::DoGetID() const
const nsAttrValue*
Element::DoGetClasses() const
{
MOZ_ASSERT(MayHaveClass(), "Unexpected call");
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
if (IsSVGElement()) {
const nsAttrValue* animClass =
static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
@@ -469,11 +470,50 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
JSObject*
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, 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));
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();
@@ -1053,102 +1093,9 @@ 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 object’s 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 object’s 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 object’s 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;
@@ -1166,9 +1113,12 @@ Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
return nullptr;
}
if (nsIDocument* doc = GetComposedDoc()) {
if (nsIPresShell* shell = doc->GetShell()) {
shell->DestroyFramesForAndRestyle(this);
nsIDocument* doc = GetComposedDoc();
nsIContent* destroyedFramesFor = nullptr;
if (doc) {
nsIPresShell* shell = doc->GetShell();
if (shell) {
shell->DestroyFramesFor(this, &destroyedFramesFor);
MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
}
}
@@ -1180,20 +1130,29 @@ Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
// Calling SetPrototypeBinding takes ownership of protoBinding.
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
/**
* 4. Let shadow be a new shadow root whose node document is
* context object’s node document, host is context object,
* and mode is init’s mode.
*/
RefPtr<ShadowRoot> shadowRoot =
new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
protoBinding);
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
/**
* 5. Set context object’s shadow root to shadow.
*/
// 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();
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);
@@ -1202,12 +1161,96 @@ Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
SetXBLBinding(xblBinding);
/**
* 6. Return shadow.
*/
// 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);
}
}
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)
{
@@ -2340,8 +2383,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
bool aNotify,
nsAttrValue& aOldValue,
uint8_t* aModType,
bool* aHasListeners,
bool* aOldValueSet)
bool* aHasListeners)
{
bool modification = false;
*aHasListeners = aNotify &&
@@ -2349,8 +2391,6 @@ 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
@@ -2374,7 +2414,6 @@ 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()) {
@@ -2394,12 +2433,10 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
uint8_t* aModType, bool* aHasListeners,
bool* aOldValueSet)
uint8_t* aModType, bool* aHasListeners)
{
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
aOldValue, aModType, aHasListeners,
aOldValueSet)) {
aOldValue, aModType, aHasListeners)) {
return false;
}
@@ -2408,45 +2445,12 @@ 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 and SetSingleClassFromParser
// above.
// Keep this in sync with SetParsedAttr below
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@@ -2458,27 +2462,17 @@ 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, &oldValueSet)) {
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
oldValue, &modType, &hasListeners)) {
return NS_OK;
}
nsAttrValue attrValue;
nsAttrValue* preparsedAttrValue;
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
attrValue.ParseAtomArray(aValue);
value.ResetToAttrValue(attrValue);
preparsedAttrValue = &attrValue;
} else {
preparsedAttrValue = nullptr;
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
@@ -2487,23 +2481,21 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
// Hold a script blocker while calling ParseAttribute since that can call
// out to id-observers
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
nsAutoScriptBlocker scriptBlocker;
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (!preparsedAttrValue &&
!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
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)) {
attrValue.SetTo(aValue);
}
PreIdMaybeChange(aNamespaceID, aName, &value);
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
oldValueSet ? &oldValue : nullptr,
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
attrValue, modType, hasListeners, aNotify,
kCallAfterSetAttr, document, updateBatch);
kCallAfterSetAttr);
}
nsresult
@@ -2511,7 +2503,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
bool aNotify)
{
// Keep this in sync with SetAttr and SetSingleClassFromParser above
// Keep this in sync with SetAttr above
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@@ -2526,46 +2518,41 @@ 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, &oldValueSet)) {
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
oldValue, &modType, &hasListeners)) {
return NS_OK;
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
&aParsedValue);
}
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,
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
aParsedValue, modType, hasListeners, aNotify,
kCallAfterSetAttr, document, updateBatch);
kCallAfterSetAttr);
}
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,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate&)
bool aCallAfterSetAttr)
{
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
@@ -2577,7 +2564,6 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
bool hadValidDir = false;
bool hadDirAuto = false;
bool oldValueSet;
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::dir) {
@@ -2588,8 +2574,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
// XXXbz Perhaps we should push up the attribute mapping function
// stuff to Element?
if (!IsAttributeMapped(aName) ||
!SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) {
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
}
}
else {
@@ -2598,34 +2584,24 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
aNamespaceID,
nsIDOMNode::ATTRIBUTE_NODE);
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
}
NS_ENSURE_SUCCESS(rv, rv);
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;
}
const nsAttrValue* oldValue =
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
NS_ENSURE_SUCCESS(rv, rv);
if (document || 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 =
@@ -2635,14 +2611,7 @@ 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;
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> oldValueAtom = oldValue->GetAsAtom();
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
@@ -2662,8 +2631,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
}
if (aCallAfterSetAttr) {
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
aNotify);
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
@@ -2672,14 +2640,12 @@ 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,
aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
oldValue == &aParsedValue ? &aParsedValue : nullptr);
}
if (aFireMutation) {
@@ -2697,7 +2663,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = NS_Atomize(newValue);
}
if (oldValue && !oldValue->IsEmptyString()) {
if (!oldValue->IsEmptyString()) {
mutation.mPrevAttrValue = oldValue->GetAsAtom();
}
mutation.mAttrChange = aModType;
@@ -2709,6 +2675,25 @@ 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,
@@ -2716,16 +2701,22 @@ Element::ParseAttribute(int32_t aNamespaceID,
nsAttrValue& aResult)
{
if (aNamespaceID == kNameSpaceID_None) {
MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
"The class attribute should be preparsed and therefore should "
"never be passed to Element::ParseAttribute");
if (aAttribute == nsGkAtoms::_class) {
SetFlags(NODE_MAY_HAVE_CLASS);
// Result should have been preparsed above.
return true;
}
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;
}
}
@@ -2734,71 +2725,15 @@ Element::ParseAttribute(int32_t aNamespaceID,
}
bool
Element::SetAndSwapMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
bool* aValueWasSet,
nsresult* aRetval)
Element::SetMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
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)
@@ -2875,6 +2810,9 @@ 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);
@@ -2884,16 +2822,11 @@ 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) {
@@ -2912,6 +2845,12 @@ 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;
@@ -2924,8 +2863,6 @@ 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) {
@@ -2933,6 +2870,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
}
}
UpdateState(aNotify);
if (CustomElementRegistry::IsCustomElementEnabled()) {
if (CustomElementData* data = GetCustomElementData()) {
if (CustomElementDefinition* definition =
@@ -2959,11 +2898,6 @@ 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.
@@ -2971,6 +2905,9 @@ 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);
}
@@ -3192,7 +3129,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
}
nsresult
Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
Element::PreHandleEventForLinks(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!
@@ -3214,9 +3151,8 @@ Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
nsresult rv = NS_OK;
// 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.
// 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.
switch (aVisitor.mEvent->mMessage) {
// Set the status bar similarly for mouseover and focus
case eMouseOver:
+61 -192
View File
@@ -41,7 +41,6 @@
#include "Units.h"
#include "DOMIntersectionObserver.h"
class mozAutoDocUpdate;
class nsIFrame;
class nsIDOMMozNamedAttrMap;
class nsIURI;
@@ -139,12 +138,12 @@ class EventStateManager;
namespace dom {
struct CustomElementDefinition;
class Animation;
class CustomElementRegistry;
class Link;
class DOMRect;
class DOMRectList;
class DestinationInsertionPointList;
class Grid;
// IID for the dom::Element interface
@@ -255,23 +254,6 @@ 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.
*/
@@ -397,9 +379,16 @@ public:
bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
Directionality GetComputedDirectionality() const;
// 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)));
}
inline Element* GetFlattenedTreeParentElementForStyle() const;
Directionality GetComputedDirectionality() const;
/**
* Gets the custom element data used by web components custom element.
@@ -471,9 +460,6 @@ 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
@@ -512,16 +498,6 @@ 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;
@@ -544,7 +520,6 @@ 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)
{
@@ -559,57 +534,25 @@ 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 [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
* @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
* nsAttrValue::eString or nsAttrValue::eAtom.
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
* @param aModType 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.
* @param aHasListeners Set to true if there are mutation event listeners
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
*/
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
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.
*/
uint8_t* aModType, bool* aHasListeners);
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
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);
uint8_t* aModType, bool* aHasListeners);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify) override;
@@ -646,7 +589,7 @@ public:
* guaranteed (e.g. we could have class="").
*/
const nsAttrValue* GetClasses() const {
if (MayHaveClass()) {
if (HasFlag(NODE_MAY_HAVE_CLASS)) {
return DoGetClasses();
}
return nullptr;
@@ -818,25 +761,6 @@ 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
@@ -924,15 +848,8 @@ 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
{
@@ -1322,10 +1239,7 @@ 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 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.
* aOldValue will not be used.
* @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.
@@ -1334,19 +1248,16 @@ 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,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate& aGuard);
bool aCallAfterSetAttr);
/**
* Scroll to a new position using behavior evaluated from CSS and
@@ -1384,21 +1295,14 @@ protected:
*
* @param aDocument the current document of this node (an optimization)
* @param aName the name of the attribute
* @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 aValue the nsAttrValue to set
* @param [out] aRetval the nsresult status of the operation, if any.
* @return true if the setting was attempted, false otherwise.
*/
virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
bool* aValueWasSet,
nsresult* aRetval);
virtual bool SetMappedAttribute(nsIDocument* aDocument,
nsIAtom* aName,
nsAttrValue& aValue,
nsresult* aRetval);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
@@ -1411,92 +1315,33 @@ 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.
* will be null. BeforeSetAttr is allowed to modify aValue by parsing
* the string to an nsAttrValue (to avoid having to reparse it in
* ParseAttribute).
* @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,
const nsAttrValueOrString* aValue,
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
* SetAndSwapAttr (that is, after we have actually set the attr). It will
* always be called under a scriptblocker.
* SetAndTakeAttr and AttributeChanged (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,
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)
const nsAttrValue* aValue, bool aNotify)
{
return NS_OK;
}
@@ -1555,7 +1400,7 @@ protected:
/**
* Handle status bar updates before they can be cancelled.
*/
nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
/**
* Handle default actions for link event if the event isn't consumed yet.
@@ -1615,6 +1460,30 @@ 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
-12
View File
@@ -8,7 +8,6 @@
#define mozilla_dom_ElementInlines_h
#include "mozilla/dom/Element.h"
#include "nsIContentInlines.h"
#include "nsIDocument.h"
namespace mozilla {
@@ -26,17 +25,6 @@ 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
+85 -135
View File
@@ -123,7 +123,6 @@
#include "mozilla/CORSMode.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "nsStyledElement.h"
@@ -152,56 +151,8 @@ 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 slotable’s parent’s shadow root's mode is not "open",
* then return null.
*/
if (GetParent()->GetShadowRoot()->IsClosed()) {
return nullptr;
}
return slot;
}
nsINode*
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
nsIContent::GetFlattenedTreeParentNodeInternal() const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
@@ -210,51 +161,18 @@ nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) 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)) {
return GetFlattenedTreeParentForMaybeAssignedNode();
}
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
// 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)) {
nsIContent* insertionParent = GetXBLInsertionParent();
if (insertionParent) {
parent = insertionParent;
@@ -657,9 +575,6 @@ 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));
@@ -703,7 +618,6 @@ 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) {
@@ -804,7 +718,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
}
nsresult
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
{
//FIXME! Document how this event retargeting works, Bug 329124.
aVisitor.mCanHandle = true;
@@ -813,7 +727,6 @@ nsIContent::GetEventTargetParent(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 ||
@@ -825,7 +738,7 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
((this == aVisitor.mEvent->mOriginalTarget &&
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
nsCOMPtr<nsIContent> relatedTarget =
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
if (relatedTarget &&
relatedTarget->OwnerDoc() == OwnerDoc()) {
@@ -835,7 +748,7 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
nsIContent* adjustedTarget =
Event::GetShadowRelatedTarget(this, relatedTarget);
if (this == adjustedTarget) {
aVisitor.SetParentTarget(nullptr, false);
aVisitor.mParentTarget = nullptr;
aVisitor.mCanHandle = false;
return NS_OK;
}
@@ -892,7 +805,7 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
originalTarget->FindFirstNonChromeOnlyAccessContent())
? "" : "Wrong event propagation!?!\n");
#endif
aVisitor.SetParentTarget(nullptr, false);
aVisitor.mParentTarget = nullptr;
// Event should not propagate to non-anon content.
aVisitor.mCanHandle = isAnonForEvents;
return NS_OK;
@@ -903,10 +816,58 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
}
}
// Event parent is the assigned slot, if node is assigned, or node's parent
// otherwise.
HTMLSlotElement* slot = GetAssignedSlot();
nsIContent* parent = slot ? slot : GetParent();
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 may need to be retargeted if this is the root of a native
// anonymous content subtree or event is dispatched somewhere inside XBL.
@@ -944,17 +905,11 @@ nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
OwnerDoc()->GetWindow()) {
aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
} else if (parent) {
aVisitor.SetParentTarget(parent, false);
if (slot) {
ShadowRoot* root = slot->GetContainingShadow();
if (root && root->IsClosed()) {
aVisitor.mParentIsSlotInClosedTree = true;
}
}
aVisitor.mParentTarget = parent;
} else {
aVisitor.SetParentTarget(GetComposedDoc(), false);
aVisitor.mParentTarget = GetComposedDoc();
}
return NS_OK;
}
@@ -1131,27 +1086,21 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
slots->mShadowRoot = aShadowRoot;
}
HTMLSlotElement*
FragmentOrElement::GetAssignedSlot() const
{
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
return slots ? slots->mAssignedSlot.get() : nullptr;
}
nsIContent*
nsIContent::GetContainingShadowHost() const
{
if (mozilla::dom::ShadowRoot* shadow = GetContainingShadow()) {
return shadow->GetHost();
}
return nullptr;
}
void
FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
nsTArray<nsIContent*>&
FragmentOrElement::DestInsertionPoints()
{
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
slots->mAssignedSlot = aSlot;
return slots->mDestInsertionPoints;
}
nsTArray<nsIContent*>*
FragmentOrElement::GetExistingDestInsertionPoints() const
{
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
if (slots) {
return &slots->mDestInsertionPoints;
}
return nullptr;
}
void
@@ -2419,8 +2368,9 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
"on a non-Element is useless");
ShadowRoot* shadowRoot = GetShadowRoot();
if (shadowRoot) {
while (shadowRoot) {
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
shadowRoot = shadowRoot->GetOlderShadowRoot();
}
}
+5 -5
View File
@@ -62,7 +62,6 @@ public:
// nsIWeakReference
NS_DECL_NSIWEAKREFERENCE
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
virtual bool IsAlive() const override { return mNode != nullptr; }
void NoticeNodeDestruction()
{
@@ -155,9 +154,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;
@@ -295,9 +294,10 @@ public:
RefPtr<ShadowRoot> mContainingShadow;
/**
* The assigned slot associated with this element.
* An array of web component insertion points to which this element
* is distributed.
*/
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
nsTArray<nsIContent*> mDestInsertionPoints;
/**
* XBL binding installed on the element.
-2
View File
@@ -7,8 +7,6 @@
#ifndef GroupedSHistory_h
#define GroupedSHistory_h
#include "nsCOMArray.h"
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
#include "nsIFrameLoader.h"
#include "nsIGroupedSHistory.h"
#include "nsIPartialSHistory.h"
-2
View File
@@ -8,8 +8,6 @@
* animating */
#include "ImageTracker.h"
#include "mozilla/Preferences.h"
#include "nsAppRunner.h" // for XRE_IsContentProcess
namespace mozilla {
namespace dom {
-1
View File
@@ -10,7 +10,6 @@
#ifndef mozilla_dom_ImageTracker
#define mozilla_dom_ImageTracker
#include "imgIRequest.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
-3
View File
@@ -7,9 +7,6 @@
#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"
-1
View File
@@ -5,7 +5,6 @@
#include "MutableBlobStreamListener.h"
#include "MutableBlobStorage.h"
#include "nsIInputStream.h"
namespace mozilla {
namespace dom {
-1
View File
@@ -15,7 +15,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Likely.h"
#include "mozilla/Unused.h"
#include "nsNodeInfoManager.h"
#include "nsCOMPtr.h"
-1
View File
@@ -8,7 +8,6 @@
#define mozilla_dom_Pose_h
#include "nsWrapperCache.h"
#include "mozilla/ErrorResult.h"
namespace mozilla {
namespace dom {
+474 -337
View File
@@ -14,11 +14,9 @@
#include "nsIDOMHTMLElement.h"
#include "nsIStyleSheetLinkingElement.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@@ -29,7 +27,10 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
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(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@@ -37,14 +38,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
if (tmp->GetHost()) {
tmp->GetHost()->RemoveMutationObserver(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
if (tmp->mPoolHost) {
tmp->mPoolHost->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
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(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
@@ -54,17 +59,14 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
ShadowRoot::ShadowRoot(nsIContent* aContent,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
nsXBLPrototypeBinding* aProtoBinding)
: DocumentFragment(aNodeInfo)
, DocumentOrShadowRoot(this)
, mProtoBinding(aProtoBinding)
, mInsertionPointChanged(false)
, mIsComposedDocParticipant(false)
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
{
SetHost(aElement);
mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
SetHost(aContent);
// Nodes in a shadow tree should never store a value
// in the subtree root pointer, nodes in the shadow tree
@@ -73,27 +75,29 @@ ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
SetFlags(NODE_IS_IN_SHADOW_TREE);
ExtendedDOMSlots()->mBindingParent = aElement;
ExtendedDOMSlots()->mBindingParent = aContent;
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.
GetHost()->AddMutationObserver(this);
mPoolHost->AddMutationObserver(this);
}
ShadowRoot::~ShadowRoot()
{
if (auto* host = GetHost()) {
// mHost may have been unlinked or a new ShadowRoot may have been
// created, making this one obsolete.
host->RemoveMutationObserver(this);
if (mPoolHost) {
// mPoolHost may have been unlinked or a new ShadowRoot may have been
// creating, making this one obsolete.
mPoolHost->RemoveMutationObserver(this);
}
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
SetSubtreeRootPointer(this);
SetHost(nullptr);
}
JSObject*
@@ -114,116 +118,13 @@ 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();
if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
nsIPresShell* shell = OwnerDoc()->GetShell();
if (shell) {
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
shell->RecordShadowStyleChange(this);
OwnerDoc()->EndUpdate(UPDATE_STYLE);
@@ -241,30 +142,16 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == DocumentOrShadowRoot::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 <= SheetCount(); i++) {
if (i == SheetCount()) {
AppendStyleSheet(*aSheet);
for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
if (i == mProtoBinding->SheetCount()) {
mProtoBinding->AppendStyleSheet(aSheet);
break;
}
nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
InsertSheetAt(i, *aSheet);
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
@@ -279,17 +166,48 @@ void
ShadowRoot::RemoveSheet(StyleSheet* aSheet)
{
mProtoBinding->RemoveStyleSheet(aSheet);
DocumentOrShadowRoot::RemoveSheet(*aSheet);
if (aSheet->IsApplicable()) {
StyleSheetChanged();
}
}
Element*
ShadowRoot::GetElementById(const nsAString& aElementId)
{
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
return entry ? entry->GetIdElement() : nullptr;
}
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByTagName(const nsAString& aTagName)
{
return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
}
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName)
{
int32_t nameSpaceId = kNameSpaceID_Wildcard;
if (!aNamespaceURI.EqualsLiteral("*")) {
nsresult rv =
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
nameSpaceId);
NS_ENSURE_SUCCESS(rv, nullptr);
}
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
return NS_GetContentList(this, nameSpaceId, aLocalName);
}
void
ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
{
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
nsIdentifierMapEntry *entry =
mIdentifierMap.PutEntry(nsDependentAtomString(aId));
if (entry) {
entry->AddIdElement(aElement);
}
@@ -298,7 +216,8 @@ ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
void
ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
{
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
nsIdentifierMapEntry *entry =
mIdentifierMap.GetEntry(nsDependentAtomString(aId));
if (entry) {
entry->RemoveIdElement(aElement);
if (entry->IsEmpty()) {
@@ -307,164 +226,244 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
}
}
nsresult
ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
already_AddRefed<nsContentList>
ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
{
aVisitor.mCanHandle = true;
aVisitor.mRootOfClosedTree = IsClosed();
// 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;
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;
return nsContentUtils::GetElementsByClassName(this, aClasses);
}
const HTMLSlotElement*
ShadowRoot::AssignSlotFor(nsIContent* aContent)
void
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
{
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;
TreeOrderComparator comparator;
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
}
void
ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
{
mInsertionPoints.RemoveElement(aInsertionPoint);
}
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);
}
}
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;
void
ShadowRoot::DistributeSingleNode(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;
}
currentContent = currentContent->GetNextSibling();
}
if (indexFound) {
// 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];
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();
// 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 (newSlot) {
newSlot->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);
}
return true;
}
}
return false;
}
void
ShadowRoot::DistributionChanged()
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
{
// FIXME(emilio): We could be more granular in a bunch of cases.
auto* host = GetHost();
if (!host || !host->IsInComposedDoc()) {
return;
}
// 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;
}
auto* shell = OwnerDoc()->GetShell();
if (!shell) {
return;
}
mInsertionPoints[i]->RemoveMatchedNode(aContent);
shell->DestroyFramesForAndRestyle(host);
// 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;
}
}
}
void
ShadowRoot::DistributeAllNodes()
{
//XXX Handle <slot>.
// Create node pool.
nsTArray<nsIContent*> nodePool;
DistributionChanged();
}
// 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);
}
}
Element*
ShadowRoot::GetActiveElement()
{
return GetRetargetedFocusedElement();
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();
}
}
void
@@ -508,6 +507,105 @@ 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,
@@ -516,26 +614,13 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
int32_t aModType,
const nsAttrValue* aOldValue)
{
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
return;
}
// Attributes may change insertion point matching, find its new distribution.
if (!MaybeReassignElement(aElement, aOldValue)) {
return;
}
if (!aElement->IsInComposedDoc()) {
return;
}
auto* shell = OwnerDoc()->GetShell();
if (!shell) {
return;
}
//XXX optimize this!
shell->DestroyFramesForAndRestyle(aElement);
RemoveDistributedNode(aElement);
DistributeSingleNode(aElement);
}
void
@@ -544,10 +629,29 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
nsIContent* aFirstNewContent,
int32_t aNewIndexInContainer)
{
for (nsIContent* content = aFirstNewContent;
content;
content = content->GetNextSibling()) {
ContentInserted(aDocument, aContainer, aFirstNewContent, 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();
}
}
@@ -557,30 +661,24 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
nsIContent* aChild,
int32_t aIndexInContainer)
{
// 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)) {
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
if (!aChild->IsSlotable()) {
return;
}
if (aContainer && aContainer == GetHost()) {
if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
slot->EnqueueSlotChangeEvent();
// 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);
}
}
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();
DistributeSingleNode(aChild);
}
}
@@ -591,32 +689,25 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
// 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)) {
if (mInsertionPointChanged) {
DistributeAllNodes();
mInsertionPointChanged = false;
return;
}
if (!aChild->IsSlotable()) {
return;
}
if (aContainer && aContainer == GetHost()) {
nsAutoString slotName;
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
slot->EnqueueSlotChangeEvent();
// Clear destination insertion points for removed
// fallback content.
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
if (content->MatchedNodes().IsEmpty()) {
aChild->DestInsertionPoints().Clear();
}
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();
// 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);
}
}
@@ -626,3 +717,49 @@ 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();
}
+115 -70
View File
@@ -8,30 +8,30 @@
#define mozilla_dom_shadowroot_h__
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/StyleSheet.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIContentInlines.h"
#include "nsIdentifierMapEntry.h"
#include "nsTHashtable.h"
#include "nsXBLBinding.h"
#include "nsDocument.h"
class nsIAtom;
class nsIContent;
class nsXBLPrototypeBinding;
namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class Element;
class HTMLContentElement;
class HTMLShadowElement;
class ShadowRootStyleSheetList;
class ShadowRoot final : public DocumentFragment,
public DocumentOrShadowRoot,
public nsStubMutationObserver
{
friend class ShadowRootStyleSheetList;
public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
DocumentFragment)
@@ -42,30 +42,46 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
ShadowRoot(Element* aElement, bool aClosed,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
ShadowRoot(nsIContent* aContent, 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;
}
// [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()
{
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
}
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);
/**
* Distributes all the explicit children of the pool host to the content
@@ -73,57 +89,43 @@ public:
*/
void DistributeAllNodes();
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 AddInsertionPoint(HTMLContentElement* aInsertionPoint);
void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
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);
void AddToIdTable(Element* aElement, nsIAtom* aId);
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
nsTArray<nsIContent*>& aDestInsertionPoints);
// WebIDL methods.
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
Element* GetActiveElement();
Element* GetElementById(const nsAString& aElementId);
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aNamespaceURI);
already_AddRefed<nsContentList>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName);
already_AddRefed<nsContentList>
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; }
@@ -132,18 +134,26 @@ public:
mIsComposedDocParticipant = aIsComposedDocParticipant;
}
nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual void DestroyContent() override;
protected:
virtual ~ShadowRoot();
ShadowRootMode mMode;
// 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;
// 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;
// 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;
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsXBLPrototypeBinding* mProtoBinding;
// It is necessary to hold a reference to the associated nsXBLBinding
@@ -151,6 +161,19 @@ 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
@@ -166,6 +189,28 @@ 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
+1 -22
View File
@@ -8,7 +8,6 @@
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/dom/StyleSheetListBinding.h"
#include "nsStubDocumentObserver.h"
namespace mozilla {
namespace dom {
@@ -18,8 +17,7 @@ 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(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
@@ -45,24 +43,5 @@ StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
return NS_OK;
}
void
StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
{
mDocumentOrShadowRoot = nullptr;
}
StyleSheetList::StyleSheetList(DocumentOrShadowRoot& aScope)
: mDocumentOrShadowRoot(&aScope)
{
mDocumentOrShadowRoot->AsNode().AddMutationObserver(this);
}
StyleSheetList::~StyleSheetList()
{
if (mDocumentOrShadowRoot) {
mDocumentOrShadowRoot->AsNode().RemoveMutationObserver(this);
}
}
} // namespace dom
} // namespace mozilla
+8 -36
View File
@@ -7,10 +7,8 @@
#ifndef mozilla_dom_StyleSheetList_h
#define mozilla_dom_StyleSheetList_h
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "nsIDOMStyleSheetList.h"
#include "nsWrapperCache.h"
#include "nsStubDocumentObserver.h"
class nsINode;
@@ -19,54 +17,28 @@ class StyleSheet;
namespace dom {
class StyleSheetList final : public nsIDOMStyleSheetList
, public nsWrapperCache
, public nsStubDocumentObserver
class StyleSheetList : public nsIDOMStyleSheetList
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
NS_DECL_NSIDOMSTYLESHEETLIST
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
explicit StyleSheetList(DocumentOrShadowRoot& aScope);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
nsINode* GetParentObject() const
{
return mDocumentOrShadowRoot ? &mDocumentOrShadowRoot->AsNode() : nullptr;
}
virtual nsINode* GetParentObject() const = 0;
uint32_t Length() const
{
return mDocumentOrShadowRoot ? mDocumentOrShadowRoot->SheetCount() : 0;
}
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
{
if (!mDocumentOrShadowRoot) {
aFound = false;
return nullptr;
}
StyleSheet* sheet = mDocumentOrShadowRoot->SheetAt(aIndex);
aFound = !!sheet;
return sheet;
}
StyleSheet* Item(uint32_t aIndex) const
virtual uint32_t Length() = 0;
virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
StyleSheet* Item(uint32_t aIndex)
{
bool dummy = false;
return IndexedGetter(aIndex, dummy);
}
protected:
virtual ~StyleSheetList();
DocumentOrShadowRoot* mDocumentOrShadowRoot; // Weak, cleared on "NodeWillBeDestroyed".
virtual ~StyleSheetList() {}
};
} // namespace dom
-2
View File
@@ -7,12 +7,10 @@
#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"
-1
View File
@@ -10,7 +10,6 @@
#include "nsIChannel.h"
#include "nsIServiceManager.h"
#include "nsIHttpChannelInternal.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"
-1
View File
@@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TimeoutHandler.h"
#include "nsJSUtils.h"
namespace mozilla {
namespace dom {
-2
View File
@@ -7,11 +7,9 @@
#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 {
-2
View File
@@ -7,8 +7,6 @@
#ifndef TimerClamping_h___
#define TimerClamping_h___
#include <math.h>
namespace mozilla {
class TimerClamping
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
var frameRoot;
function boom()
{
var frameWin = f.contentWindow;
frameRoot = frameWin.document.documentElement;
frameWin.location.replace("data:text/html;charset=UTF-8,<body onload='parent.g();'>2");
}
function g()
{
setTimeout(h, 0);
}
function h()
{
var newDoc = document.implementation.createDocument('', '', null);
newDoc.adoptNode(frameRoot);
}
</script>
<body onload="boom();">
<iframe id="f" src="data:text/html;charset=UTF-8,<marquee>1"></iframe>
</body>
</html>
-17
View File
@@ -1,17 +0,0 @@
<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>
-6
View File
@@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
<slot><div></div></slot>
</html>
+24
View File
@@ -0,0 +1,24 @@
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<script>
function boom()
{
var marquee = document.getElementById("marquee");
var span = document.getElementById("span");
marquee.appendChild(span);
marquee.removeChild(span);
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="setTimeout(boom, 30);">
<marquee id="marquee" />
<span id="span"><div>Foo</div><textarea/></span>
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
<html class="reftest-wait">
<head>
<script type="text/javascript">
var i = 0;
function mmf()
{
if (++i == 2) {
document.body.innerHTML = "<marquee>";
document.documentElement.removeAttribute("class");
}
}
function init()
{
document.documentElement.offsetHeight;
for (var j = 0; j < 2; ++j) {
var iframe = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
iframe.addEventListener("load", mmf, false);
document.body.appendChild(iframe);
}
}
</script>
</head>
<body onload="setTimeout(init, 0);"></body>
</html>
+2 -4
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 # bug 1340009
pref(dom.webcomponents.enabled,true) load 1024428-1.html
load 1026714.html
pref(dom.webcomponents.enabled,true) load 1027461-1.html
pref(dom.webcomponents.enabled,true) load 1029710.html
@@ -209,6 +209,4 @@ load 1230422.html
load 1251361.html
load 1304437.html
pref(clipboard.autocopy,true) load 1385272-1.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
pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
+2 -5
View File
@@ -86,7 +86,6 @@ EXPORTS += [
'nsIContentInlines.h',
'nsIContentIterator.h',
'nsIContentSerializer.h',
'nsIdentifierMapEntry.h',
'nsIDocument.h',
'nsIDocumentInlines.h',
'nsIDocumentObserver.h',
@@ -164,7 +163,6 @@ EXPORTS.mozilla.dom += [
'DirectionalityUtils.h',
'DocGroup.h',
'DocumentFragment.h',
'DocumentOrShadowRoot.h',
'DocumentType.h',
'DOMCursor.h',
'DOMError.h',
@@ -227,7 +225,7 @@ EXPORTS.mozilla.dom += [
'WindowOrientationObserver.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'AnonymousContent.cpp',
'Attr.cpp',
'BarProps.cpp',
@@ -243,7 +241,6 @@ SOURCES += [
'DirectionalityUtils.cpp',
'DocGroup.cpp',
'DocumentFragment.cpp',
'DocumentOrShadowRoot.cpp',
'DocumentType.cpp',
'DOMCursor.cpp',
'DOMError.cpp',
@@ -379,7 +376,7 @@ SOURCES += [
]
if CONFIG['MOZ_WEBRTC']:
SOURCES += [
UNIFIED_SOURCES += [
'nsDOMDataChannel.cpp',
]
+10 -24
View File
@@ -382,15 +382,12 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
}
nsresult
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
bool* aHadValue)
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
{
*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;
}
}
@@ -410,22 +407,21 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
}
nsresult
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
nsAttrValue& aValue, bool* aHadValue)
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
{
int32_t namespaceID = aName->NamespaceID();
nsIAtom* localName = aName->NameAtom();
if (namespaceID == kNameSpaceID_None) {
return SetAndSwapAttr(localName, aValue, aHadValue);
return SetAndSwapAttr(localName, aValue);
}
*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;
}
}
@@ -580,11 +576,10 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
}
nsresult
nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
bool* aHadValue)
nsHTMLStyleSheet* aSheet)
{
bool willAdd = true;
if (mImpl && mImpl->mMappedAttrs) {
@@ -594,7 +589,7 @@ nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
RefPtr<nsMappedAttributes> mapped =
GetModifiableMapped(aContent, aSheet, willAdd);
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
mapped->SetAndTakeAttr(aLocalName, aValue);
return MakeMappedUnique(mapped);
}
@@ -719,19 +714,10 @@ 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,
int32_t aAttrCount)
bool aWillAddAttr)
{
if (mImpl && mImpl->mMappedAttrs) {
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
@@ -741,7 +727,7 @@ nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
nsMapRuleToAttributesFunc mapRuleFunc =
aContent->GetAttributeMappingFunction();
return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
return new nsMappedAttributes(aSheet, mapRuleFunc);
}
nsresult
+5 -19
View File
@@ -91,13 +91,8 @@ public:
nsCaseTreatment aCaseSensitive) const;
const nsAttrValue* AttrAt(uint32_t aPos) const;
// SetAndSwapAttr 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 SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
bool* aHadValue);
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
bool* aHadValue);
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
// Remove the attr at position aPos. The value of the attr is placed in
// aValue; any value that was already in aValue is destroyed.
@@ -115,14 +110,9 @@ public:
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
// 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,
nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
bool* aHadValue);
nsHTMLStyleSheet* aSheet);
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
if (!mImpl || !mImpl->mMappedAttrs) {
return NS_OK;
@@ -145,9 +135,6 @@ 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;
@@ -161,8 +148,7 @@ private:
nsMappedAttributes*
GetModifiableMapped(nsMappedAttributeElement* aContent,
nsHTMLStyleSheet* aSheet,
bool aWillAddAttr,
int32_t aAttrCount = 1);
bool aWillAddAttr);
nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
uint32_t AttrSlotsSize() const
+12 -18
View File
@@ -49,13 +49,20 @@ public:
, mCheapString(nullptr)
{ }
void ResetToAttrValue(const nsAttrValue& aValue)
void TakeParsedValue(nsAttrValue& aValue)
{
mAttrValue = &aValue;
mStoredAttrValue.SwapValueWith(aValue);
mAttrValue = &mStoredAttrValue;
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.
@@ -78,24 +85,11 @@ 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___
+78 -61
View File
@@ -44,8 +44,9 @@
#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"
@@ -101,9 +102,7 @@
#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"
@@ -501,8 +500,6 @@ nsContentUtils::Init()
return NS_OK;
}
nsHTMLTags::AddRefTable();
sNameSpaceManager = nsNameSpaceManager::GetInstance();
NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
@@ -593,7 +590,7 @@ nsContentUtils::Init()
"dom.webcomponents.enabled", false);
Preferences::AddBoolVarCache(&sIsCustomElementsEnabled,
"dom.webcomponents.enabled", false);
"dom.webcomponents.customelements.enabled", false);
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
"dom.url.encode_decode_hash", false);
@@ -1929,8 +1926,6 @@ nsContentUtils::Shutdown()
{
sInitialized = false;
nsHTMLTags::ReleaseTable();
NS_IF_RELEASE(sContentPolicyService);
sTriedToGetContentPolicy = false;
uint32_t i;
@@ -2395,9 +2390,6 @@ 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;
@@ -2448,14 +2440,10 @@ 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;
}
@@ -3658,14 +3646,6 @@ nsContentUtils::ReportToConsole(uint32_t aErrorFlags,
aLineNumber, aColumnNumber);
}
/* static */ void
nsContentUtils::ReportEmptyGetElementByIdArg(const nsIDocument* aDoc)
{
ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM"), aDoc,
nsContentUtils::eDOM_PROPERTIES,
"EmptyGetElementByIdParam");
}
/* static */ nsresult
nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
@@ -4963,7 +4943,17 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
return aContent->GetBindingParent() == nullptr;
}
return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent();
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();
}
class AnonymousContentDestroyer : public Runnable {
@@ -7025,11 +7015,25 @@ 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 || !nsDocument::IsWebComponentsEnabled(aContent)) {
if (!aContent) {
return false;
}
@@ -7039,11 +7043,26 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
return true;
}
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();
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();
}
return false;
@@ -9656,6 +9675,35 @@ 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)
{
@@ -9789,24 +9837,6 @@ 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)
{
@@ -9822,16 +9852,3 @@ 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;
}
+18 -26
View File
@@ -339,13 +339,6 @@ 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,
@@ -589,7 +582,7 @@ public:
/**
* Returns true if |aName| is a valid name to be registered via
* customElements.define.
* document.registerElement.
*/
static bool IsCustomElementName(nsIAtom* aName);
@@ -941,8 +934,6 @@ public:
uint32_t aLineNumber = 0,
uint32_t aColumnNumber = 0);
static void ReportEmptyGetElementByIdArg(const nsIDocument* aDoc);
static void LogMessageToConsole(const char* aMsg);
/**
@@ -2416,6 +2407,18 @@ 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.
@@ -2732,17 +2735,12 @@ public:
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
static void GetCustomPrototype(nsIDocument* aDoc,
int32_t aNamespaceID,
nsIAtom* aAtom,
JS::MutableHandle<JSObject*> prototype);
/**
* 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);
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
/**
* Detect whether a string is a (CSS) local-url.
@@ -2754,12 +2752,6 @@ 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; }
Loaded 100 of 3053 files, more files were not shown because too many files have changed in this diff. Show more