Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f23478616c | ||
|
|
adbec0c69b | ||
|
|
b791b67121 | ||
|
|
c15bc7d3dd | ||
|
|
33b7d3e638 | ||
|
|
c05d07a687 | ||
|
|
0fab85e38f | ||
|
|
4e688106c4 | ||
|
|
ad966887a5 | ||
|
|
55c84e4cec | ||
|
|
3dde51910e | ||
|
|
9f2a6d3703 | ||
|
|
d8a29fcafb | ||
|
|
68c72c1234 | ||
|
|
7cc007d9bf | ||
|
|
bbd59105da | ||
|
|
5e7917e2c8 | ||
|
|
43725c7264 | ||
|
|
35754dd1af | ||
|
|
a4c5e74b0b | ||
|
|
59a5adc934 | ||
|
|
927c2fd3ea | ||
|
|
1c97314804 | ||
|
|
94c694d389 | ||
|
|
e97a29a656 | ||
|
|
433c300a37 | ||
|
|
5629e34f80 | ||
|
|
93f74227ba | ||
|
|
1620ec1965 | ||
|
|
fdc11c731c | ||
|
|
ec792e2ac7 | ||
|
|
1ca6039fb8 | ||
|
|
be82b33318 | ||
|
|
a8602cc877 | ||
|
|
0955b34e67 | ||
|
|
8797b20746 | ||
|
|
47db6b4b5e | ||
|
|
907530e866 | ||
|
|
d18faf8193 | ||
|
|
ad6ce890dc | ||
|
|
b0901eb099 | ||
|
|
e8bdf27ac7 | ||
|
|
8f02c2b066 | ||
|
|
cc01b5e2a9 | ||
|
|
e0dc5f3091 | ||
|
|
32c3efa3c2 | ||
|
|
bd971831f0 | ||
|
|
fdb918dea1 | ||
|
|
580cb677dd | ||
|
|
5a64ee34a9 | ||
|
|
da8fbfb4d5 | ||
|
|
760c45dbe1 | ||
|
|
11718bf88e | ||
|
|
fb564353f2 | ||
|
|
d7a6bb2171 | ||
|
|
66b02a8044 | ||
|
|
f828451e5f | ||
|
|
52c4750ab2 | ||
|
|
967ee4fbc7 | ||
|
|
b5be37e0a6 | ||
|
|
e5dd97fee3 | ||
|
|
1cecef624a | ||
|
|
d8eba6991d | ||
|
|
5fcc364e3e | ||
|
|
5d89ac3795 | ||
|
|
725e2b731f | ||
|
|
101c06946e | ||
|
|
be3acde802 | ||
|
|
77cd9147cc | ||
|
|
54329daab7 | ||
|
|
7ce31fc2a4 | ||
|
|
09bdffde5e | ||
|
|
5377605d63 | ||
|
|
4d373c1d36 | ||
|
|
ed8efdfaba | ||
|
|
5d6691e9d0 | ||
|
|
0a19762d3b | ||
|
|
a965486fcb | ||
|
|
14f6f230d7 | ||
|
|
750b4c3a11 | ||
|
|
ffb32138cb | ||
|
|
41757ae2c0 | ||
|
|
b48902c58f | ||
|
|
18c36ffcd4 | ||
|
|
8f57507dd8 | ||
|
|
efa5796d5e | ||
|
|
822f8dad95 | ||
|
|
7db74bdc3a | ||
|
|
3c05cc907d | ||
|
|
539fb0aea2 | ||
|
|
3686a289c1 | ||
|
|
72d77237e9 | ||
|
|
243850386d | ||
|
|
3da22ea943 | ||
|
|
5f86cd25f2 | ||
|
|
5fa34da0b7 | ||
|
|
5966f18f41 | ||
|
|
364e44a4aa | ||
|
|
53e5d63732 | ||
|
|
16d66edc28 | ||
|
|
798f491abe | ||
|
|
922f9b4f52 | ||
|
|
a20f130def | ||
|
|
4cfbcc4989 | ||
|
|
9cdc2b9abb | ||
|
|
a5d2b71303 | ||
|
|
80fc6e92ef | ||
|
|
0754b0bc4a | ||
|
|
1dc5599a7a | ||
|
|
fc73299024 | ||
|
|
9cf4eca9a8 | ||
|
|
a72156b87a | ||
|
|
9cb4884a7e | ||
|
|
16ca000ca9 | ||
|
|
2e986f3144 | ||
|
|
6ca94dc203 | ||
|
|
28c5a08441 | ||
|
|
836aa70536 | ||
|
|
7286d6ecf8 | ||
|
|
3b6fd3b6c0 | ||
|
|
f05391a69f | ||
|
|
052a035958 | ||
|
|
5cfe1d9020 | ||
|
|
088685a828 | ||
|
|
7ce1ea0a41 | ||
|
|
3b1aec2e61 | ||
|
|
fee5da8d11 | ||
|
|
32a4d5c416 | ||
|
|
77544de5d6 | ||
|
|
9679f714f7 | ||
|
|
53662b791d | ||
|
|
574d071b5c | ||
|
|
d032fb8df8 | ||
|
|
4e8c369b22 | ||
|
|
55897f06c0 | ||
|
|
ef3af7ce70 | ||
|
|
24d8c25026 | ||
|
|
ebc0e55033 | ||
|
|
b878a54a2f | ||
|
|
2501df8195 | ||
|
|
79834afa62 | ||
|
|
8055c99af4 | ||
|
|
98620e3c1e | ||
|
|
6b56185c0b | ||
|
|
1a61c518b6 | ||
|
|
a141af108f | ||
|
|
22a4c154bb | ||
|
|
001c416125 | ||
|
|
26178ba977 | ||
|
|
2a6e16fba0 | ||
|
|
a78f517c40 | ||
|
|
4fc1cd5563 | ||
|
|
4e2559d92f | ||
|
|
ec7269ea5c | ||
|
|
402bfbe489 | ||
|
|
89097a9e5c | ||
|
|
a89818f5c1 | ||
|
|
ca50a57545 | ||
|
|
8702b0ffb9 | ||
|
|
d73bfc3733 | ||
|
|
eb67f101a5 | ||
|
|
2f5fb42c21 | ||
|
|
f38ebb5f44 | ||
|
|
97b89ab4b5 | ||
|
|
83b4235d8a | ||
|
|
dfa87279f8 | ||
|
|
d3b19e64a3 | ||
|
|
5b4ba95438 | ||
|
|
0998c39f91 | ||
|
|
39c7fd37d5 | ||
|
|
0f590122c5 | ||
|
|
221627575b | ||
|
|
1659e69dfb | ||
|
|
42c1fcaaed | ||
|
|
f9047ff63d | ||
|
|
bc4dacf690 | ||
|
|
8b41800216 | ||
|
|
64ffe81c55 | ||
|
|
45b20c5e4a | ||
|
|
58219fc214 | ||
|
|
130df5da4f | ||
|
|
f102e7f80d | ||
|
|
823eca65a4 | ||
|
|
7e1f4f430f | ||
|
|
c31fe286b9 | ||
|
|
83ecae9ff7 | ||
|
|
7c779d875b | ||
|
|
3c38a37acd | ||
|
|
cc2f6543bd | ||
|
|
789146fb74 | ||
|
|
c0401ee701 | ||
|
|
f5c2775a69 | ||
|
|
b378ddaace | ||
|
|
518efb215a | ||
|
|
257e62db99 | ||
|
|
e0ddf81221 | ||
|
|
da375ebedd | ||
|
|
f63b86a461 | ||
|
|
6980b80791 | ||
|
|
ca826767f0 | ||
|
|
ea491d0383 | ||
|
|
4ecfad8e53 | ||
|
|
2375e5ebe9 | ||
|
|
0c175b93cf | ||
|
|
18b2328bb6 | ||
|
|
e11620a0f5 | ||
|
|
4aafee310e | ||
|
|
6e8e1b36dd | ||
|
|
ae707c8dbb | ||
|
|
a78a87502d | ||
|
|
192d2e07c3 | ||
|
|
ad0a976f2d | ||
|
|
f1f9fdabf1 | ||
|
|
3b83de9974 | ||
|
|
adbbcd51c3 | ||
|
|
802efaedc7 | ||
|
|
b1c87bea43 | ||
|
|
521f6fb61e | ||
|
|
7a9c933a23 | ||
|
|
756162415b | ||
|
|
b653436669 | ||
|
|
3e63479f37 | ||
|
|
d99fc2ead2 | ||
|
|
e2f88ae0bc | ||
|
|
ea58beb4c9 | ||
|
|
0e27cb13cc | ||
|
|
a6d34b3fc6 | ||
|
|
13eacee0ab | ||
|
|
4b7155deb5 | ||
|
|
553cc9bbb5 | ||
|
|
8a872916bc | ||
|
|
915df34663 | ||
|
|
ea14415e49 | ||
|
|
eb8a6523b8 | ||
|
|
f2e99fecfd | ||
|
|
8225339715 | ||
|
|
bbdf84dd35 | ||
|
|
f7670e6f53 | ||
|
|
484e7e65a7 | ||
|
|
54e4a32da5 | ||
|
|
347f3bae73 | ||
|
|
6f37b2107a | ||
|
|
400e9018fd | ||
|
|
2bfcaa29ac | ||
|
|
b5b62d841c | ||
|
|
c9bde0ff25 | ||
|
|
d95fb4f242 | ||
|
|
ceb7889c50 | ||
|
|
37f2b54dc5 | ||
|
|
bbe0503799 | ||
|
|
fd1e35f8d5 | ||
|
|
f7ee7bf961 | ||
|
|
244539413e | ||
|
|
2def229da3 | ||
|
|
0edde46e19 | ||
|
|
b35bc68877 | ||
|
|
cbef19843f | ||
|
|
62c0cea342 | ||
|
|
df2beb06ef | ||
|
|
baa390fabf | ||
|
|
1169a05684 | ||
|
|
c3a868aa93 | ||
|
|
d003113450 | ||
|
|
a8e22cb6a5 | ||
|
|
7fc868a368 | ||
|
|
006fbfd555 | ||
|
|
1bc8205ee1 | ||
|
|
e43694dedb | ||
|
|
79f126e542 | ||
|
|
cd3935494c | ||
|
|
e8f532de41 | ||
|
|
18ff59c25f | ||
|
|
272ac91cb2 | ||
|
|
f59fb63b1a | ||
|
|
cb55499113 | ||
|
|
a87349027f | ||
|
|
153a427515 | ||
|
|
b8b7c3acfb | ||
|
|
44ed6d09e8 | ||
|
|
bf73b360a5 | ||
|
|
1c6b659b74 | ||
|
|
e8ab6cfbc8 | ||
|
|
9d165d5271 | ||
|
|
9c1defdf1b | ||
|
|
0f7b0f6900 | ||
|
|
b913c9ba83 | ||
|
|
f3206baa80 | ||
|
|
24607dc828 | ||
|
|
735a7eb9f7 | ||
|
|
cecc77ae6f | ||
|
|
480d9a30e2 | ||
|
|
77f879e74a | ||
|
|
c5e4fd8449 | ||
|
|
d34a91958e | ||
|
|
38bb18bc20 | ||
|
|
aab8d83f00 | ||
|
|
4187fbb2e8 | ||
|
|
46e31c3d9f | ||
|
|
565339e035 | ||
|
|
222d316c83 | ||
|
|
38f206cb72 | ||
|
|
d5102d6bea | ||
|
|
f35aa3e15f | ||
|
|
80c0247799 | ||
|
|
6d76ab9b6c | ||
|
|
9e5e58c0f6 | ||
|
|
16dba9a30b | ||
|
|
f6221f440e | ||
|
|
0f5b789157 | ||
|
|
f605c68f13 | ||
|
|
53df3a74f4 | ||
|
|
b93fb57514 | ||
|
|
3508e79b1f | ||
|
|
f164962a3d | ||
|
|
d925bfcc69 | ||
|
|
7e506bd98d | ||
|
|
010f37f47b | ||
|
|
38056aa9c9 | ||
|
|
fd7a325bc0 | ||
|
|
f0b7ba1e2b | ||
|
|
003e537dcb | ||
|
|
a2cdb9f91a | ||
|
|
e5ca4ada99 | ||
|
|
03a898fca7 | ||
|
|
ee4857f209 | ||
|
|
352fe83985 | ||
|
|
14bb98e175 | ||
|
|
e31ed5b074 | ||
|
|
8beb65dd50 | ||
|
|
5524318fe7 | ||
|
|
3a74795a56 | ||
|
|
873abc7bcb | ||
|
|
96dfc63bc5 | ||
|
|
ed7faf3fde | ||
|
|
3758434680 | ||
|
|
55d83ea6f9 | ||
|
|
48f602e65b | ||
|
|
846e0fa4f5 | ||
|
|
5f12940329 | ||
|
|
a72b827325 | ||
|
|
61e46a6d58 | ||
|
|
8114d58fee | ||
|
|
071957f9fa | ||
|
|
e482e335bb | ||
|
|
f4a1d0123c | ||
|
|
675dce9472 | ||
|
|
70c8ff8e5a | ||
|
|
53428ad3f0 | ||
|
|
0c99ad16fb | ||
|
|
2bcd8923f7 | ||
|
|
4d1d777e70 | ||
|
|
32e8155127 | ||
|
|
2e2190a504 | ||
|
|
ea3a2ce279 | ||
|
|
5a379a4b15 | ||
|
|
516fd67d50 | ||
|
|
17f7e1c8c6 | ||
|
|
940d191ef8 | ||
|
|
ef689a705f | ||
|
|
091d06b43b | ||
|
|
0f5dcf963a | ||
|
|
34e2c4054f | ||
|
|
7614fdb51b | ||
|
|
5f297c5f57 | ||
|
|
f07f8aecb8 | ||
|
|
9f6cb6874e | ||
|
|
0d362ca503 | ||
|
|
de45820b64 | ||
|
|
ab05e6f9ad | ||
|
|
2f59167e65 | ||
|
|
4630e4abb5 | ||
|
|
2c4d69359f | ||
|
|
1f5c67934f | ||
|
|
5caf99795a | ||
|
|
32c3ee92b8 | ||
|
|
0d149a4c09 | ||
|
|
4375774c90 | ||
|
|
963fc80796 | ||
|
|
c66ed1275f | ||
|
|
4e2b4b9bc7 | ||
|
|
e215bfbb80 | ||
|
|
b356448d14 | ||
|
|
bebec8fcb8 | ||
|
|
5352b69a92 | ||
|
|
6f6d1f6ff7 | ||
|
|
f1675650ab | ||
|
|
6245e5a8f2 | ||
|
|
e4548d6ad7 | ||
|
|
9f4b2a0e23 | ||
|
|
a2bc0e0ec6 | ||
|
|
552470fb6f | ||
|
|
56103d6756 | ||
|
|
85a97e9a35 | ||
|
|
5545a8983f | ||
|
|
50f1986697 | ||
|
|
eb28b1f32b | ||
|
|
c51c10bf09 | ||
|
|
d0eee8f01d | ||
|
|
2383a02b59 | ||
|
|
33b22f6157 | ||
|
|
d9f17c9f8b | ||
|
|
eadff6165c | ||
|
|
d0cf67573c | ||
|
|
fd5e25ff47 | ||
|
|
a333257d76 | ||
|
|
7630b1c56e |
No files matched your search
+1
-1
@@ -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
|
||||
|
||||
@@ -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 wiki](http://developer.palemoon.org).
|
||||
information will be available on the [Pale Moon developer site](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
@@ -0,0 +1,36 @@
|
||||
# Security Policy
|
||||
|
||||
## What is or is not a vulnerability?
|
||||
|
||||
In general, vulnerabilities are those bugs that can actually be exploited to perform malicious tasks.
|
||||
Most _crashes_ are not security vulnerabilities. Although important to fix, they don't inherently cause a problem for the
|
||||
browser's security.
|
||||
|
||||
What should be considered vulnerabilities or security hazards by default:
|
||||
- Use-after-free crashes, since those can potentially be used for remote code execution;
|
||||
- Spoofing issues in the UI;
|
||||
- File security issues, like out-of-bounds access to arbitrary files or locations;
|
||||
- Type confusion issues;
|
||||
- Bypass of security measures like CSP or the various mechanisms around HTTPS.
|
||||
|
||||
Generally not security vulnerabilities:
|
||||
- Null dereferencing crashes;
|
||||
- Malware extensions (but please do report those on the forum in the extensions board!);
|
||||
- Denial-of-service (AKA "evil trap sites")
|
||||
- Browser hangs
|
||||
- Issues with non-standard manual configuration (either at build time or by manipulating about:config directly)
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find an issue in UXP or the applications it builds on that could impact the security or safety of users please **do not**
|
||||
make an issue on GitHub about it. GitHub does not support restricted viewability for security sensitive bugs.
|
||||
|
||||
If you want to report a security-sensitive issue then please go to the [forum](https://forum.palemoon.org) and report the issue
|
||||
via a **private message** to **Moonchild** (the founder and prime responsible for security issues).
|
||||
The forum's private message system is fully secure since your visits are encrypted and private messages are not available to anyone
|
||||
except the recipient (not even moderators!).
|
||||
|
||||
You will be informed via private message if the vulnerability report is accepted or declined, with reasoning.
|
||||
Security updates occur regularly and are given priority over most other development tasks. In general, they can be solved
|
||||
relatively quickly and will be included in the next point release (third digit if not rolled into a more major one).
|
||||
|
||||
@@ -347,16 +347,6 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
||||
eLandmark,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // marquee
|
||||
&nsGkAtoms::marquee,
|
||||
roles::ANIMATION,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eOffLiveAttr,
|
||||
kGenericAccType,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // math
|
||||
&nsGkAtoms::math,
|
||||
roles::FLAT_EQUATION,
|
||||
|
||||
@@ -732,8 +732,6 @@ 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_)
|
||||
@@ -869,7 +867,6 @@ 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,7 +62,6 @@ 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"});
|
||||
@@ -72,7 +71,6 @@ 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"});
|
||||
@@ -80,13 +78,11 @@ 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"});
|
||||
@@ -230,11 +226,9 @@ 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-2', 'image-3']);
|
||||
['image-1', '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-2', 'image-3',
|
||||
'heading-5', 'image-1', '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,7 +41,6 @@
|
||||
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);
|
||||
@@ -89,9 +88,6 @@
|
||||
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);
|
||||
@@ -219,7 +215,6 @@
|
||||
<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"/>
|
||||
@@ -263,7 +258,6 @@
|
||||
<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_TEXT,
|
||||
children: [ { role: ROLE_TEXT_LEAF } ]
|
||||
role: ROLE_GRAPHIC,
|
||||
children: []
|
||||
};
|
||||
testAccessibleTree("the_img", accTree);
|
||||
SimpleTest.finish();
|
||||
|
||||
Vendored
+8
-5
@@ -381,11 +381,14 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
|
||||
eval $set_cc_for_build
|
||||
SUN_ARCH=i386
|
||||
# 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') | \
|
||||
_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') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
|
||||
@@ -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" -a "$OS_TARGET" != WINNT -a "$MOZ_WIDGET_TOOLKIT" != "android"; then
|
||||
if test -z "$JS_STANDALONE"; then
|
||||
MOZ_ICU_DATA_ARCHIVE=1
|
||||
else
|
||||
MOZ_ICU_DATA_ARCHIVE=
|
||||
|
||||
@@ -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 'browser'
|
||||
return 'application/xulrunner'
|
||||
|
||||
option('--enable-project', nargs=1, default=default_project,
|
||||
help='Project to build')
|
||||
@@ -618,28 +618,22 @@ 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):
|
||||
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:
|
||||
die('Cannot find project %s', build_app)
|
||||
return os.path.join(build_env.topsrcdir, 'toolkit', 'moz.configure')
|
||||
|
||||
@depends('--with-external-source-dir')
|
||||
def external_source_dir(value):
|
||||
@@ -649,12 +643,29 @@ 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)
|
||||
|
||||
@@ -157,6 +157,7 @@ def old_configure_options(*options):
|
||||
'--enable-accessibility',
|
||||
'--enable-address-sanitizer',
|
||||
'--enable-alsa',
|
||||
'--enable-av1',
|
||||
'--enable-b2g-bt',
|
||||
'--enable-b2g-camera',
|
||||
'--enable-b2g-ril',
|
||||
|
||||
@@ -16,11 +16,6 @@ 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"
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/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)
|
||||
@@ -436,23 +436,22 @@ nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
int32_t count = document->GetNumberOfStyleSheets();
|
||||
size_t count = document->SheetCount();
|
||||
|
||||
// Build an array of style sheets we need to reload.
|
||||
nsTArray<RefPtr<StyleSheet>> oldSheets(count);
|
||||
nsTArray<RefPtr<StyleSheet>> newSheets(count);
|
||||
|
||||
// Iterate over the style sheets.
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
// Get the style sheet
|
||||
StyleSheet* styleSheet = document->GetStyleSheetAt(i);
|
||||
oldSheets.AppendElement(styleSheet);
|
||||
oldSheets.AppendElement(document->SheetAt(i));
|
||||
}
|
||||
|
||||
// Iterate over our old sheets and kick off a sync load of the new
|
||||
// sheet if and only if it's a non-inline sheet with a chrome URL.
|
||||
for (StyleSheet* sheet : oldSheets) {
|
||||
MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
|
||||
MOZ_ASSERT(sheet, "SheetAt shouldn't return nullptr for "
|
||||
"in-range sheet indexes");
|
||||
nsIURI* uri = sheet->GetSheetURI();
|
||||
|
||||
|
||||
Vendored
-6
@@ -40,12 +40,6 @@ 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']
|
||||
|
||||
|
||||
Vendored
+3
@@ -112,6 +112,7 @@ CERT_GetCertChainFromCert
|
||||
CERT_GetCertEmailAddress
|
||||
CERT_GetCertificateDer
|
||||
CERT_GetCertificateRequestExtensions
|
||||
CERT_GetCertKeyType
|
||||
CERT_GetCertTimes
|
||||
CERT_GetCertTrust
|
||||
CERT_GetCommonName
|
||||
@@ -270,6 +271,7 @@ NSS_Init
|
||||
NSS_Initialize
|
||||
NSS_InitWithMerge
|
||||
NSS_IsInitialized
|
||||
NSS_OptionGet
|
||||
NSS_OptionSet
|
||||
NSS_NoDB_Init
|
||||
NSS_SecureMemcmp
|
||||
@@ -383,6 +385,7 @@ PK11_GetNextSymKey
|
||||
PK11_GetPadMechanism
|
||||
PK11_GetPrivateKeyNickname
|
||||
PK11_GetPrivateModulusLen
|
||||
PK11_GetSlotFromPrivateKey
|
||||
PK11_GetSlotID
|
||||
PK11_GetSlotInfo
|
||||
PK11_GetSlotName
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
4.5.9
|
||||
4.6.0
|
||||
@@ -33,7 +33,7 @@ function* testTopLeft(inspector, view) {
|
||||
let afterElement = children.nodes[children.nodes.length - 1];
|
||||
yield selectNode(afterElement, inspector);
|
||||
top = getComputedViewPropertyValue(view, "top");
|
||||
is(top, "50%", "The computed view shows the correct top");
|
||||
is(top, "96px", "The computed view shows the correct top");
|
||||
left = getComputedViewPropertyValue(view, "left");
|
||||
is(left, "50%", "The computed view shows the correct left");
|
||||
is(left, "96px", "The computed view shows the correct left");
|
||||
}
|
||||
@@ -91,7 +91,7 @@ const Curl = {
|
||||
if (utils.isUrlEncodedRequest(data) ||
|
||||
["PUT", "POST", "PATCH"].includes(data.method)) {
|
||||
postDataText = data.postDataText;
|
||||
addPostData("--data");
|
||||
addPostData("--data-raw");
|
||||
addPostData(utils.writePostDataTextParams(postDataText));
|
||||
ignoredHeaders.add("content-length");
|
||||
} else if (multipartRequest) {
|
||||
@@ -400,7 +400,12 @@ const CurlUtils = {
|
||||
* Credit: Google DevTools
|
||||
*/
|
||||
escapeStringWin: function (str) {
|
||||
/* Replace quote by double quote (but not by \") because it is
|
||||
/*
|
||||
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
|
||||
recognized by both cmd.exe and MS Crt arguments parser.
|
||||
|
||||
Replace % by "%" because it could be expanded to an environment
|
||||
@@ -414,7 +419,8 @@ const CurlUtils = {
|
||||
Replace new line outside of quotes since cmd.exe doesn't let
|
||||
to do it inside.
|
||||
*/
|
||||
return "\"" + str.replace(/"/g, "\"\"")
|
||||
return "\"" + str.replace(/\$/g, "`$")
|
||||
.replace(/"/g, "\"\"")
|
||||
.replace(/%/g, "\"%\"")
|
||||
.replace(/\\/g, "\\\\")
|
||||
.replace(/[\r\n]+/g, "\"^$&\"") + "\"";
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
a {
|
||||
-moz-user-focus: normal;
|
||||
-moz-user-input: enabled;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -1440,6 +1440,8 @@ exports.CSS_PROPERTIES = {
|
||||
"supports": [],
|
||||
"values": [
|
||||
"auto",
|
||||
"disabled",
|
||||
"enabled",
|
||||
"inherit",
|
||||
"initial",
|
||||
"none",
|
||||
|
||||
@@ -126,7 +126,7 @@ switch (variable) {
|
||||
code_for_1;
|
||||
code_for_1;
|
||||
break;
|
||||
case value2:
|
||||
case value2: // Comment describing 2 (alternative)
|
||||
code_for_2;
|
||||
code_for_2;
|
||||
// fallthrough
|
||||
@@ -273,7 +273,7 @@ Applies to `*.js` and `*.jsm`.
|
||||
}
|
||||
}, false);
|
||||
```
|
||||
- Use a single space between `{` `}` braces in empty js objects.
|
||||
- Don't use a space between `{` `}` braces in empty js objects, `{` `}` braces in empty function scopes, or `[` `]` brackets in empty arrays.
|
||||
|
||||
### 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:
|
||||
case value2: // Comment describing 2 (alternative)
|
||||
code_for_2;
|
||||
code_for_2;
|
||||
// fallthrough
|
||||
@@ -397,8 +397,7 @@ try {
|
||||
|
||||
try {
|
||||
do_something();
|
||||
} catch(e) {
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
try {
|
||||
do_something();
|
||||
@@ -414,11 +413,6 @@ try {
|
||||
// No error processing
|
||||
do_something_else();
|
||||
}
|
||||
|
||||
// No closing brace on its own line
|
||||
try {
|
||||
do_something();
|
||||
} catch(ex) { }
|
||||
```
|
||||
|
||||
### Long line wrapping
|
||||
|
||||
@@ -860,6 +860,12 @@ nsDocShell::~nsDocShell()
|
||||
shPrivate->SetRootDocShell(nullptr);
|
||||
}
|
||||
|
||||
if (mContentViewer) {
|
||||
mContentViewer->Close(nullptr);
|
||||
mContentViewer->Destroy();
|
||||
mContentViewer = nullptr;
|
||||
}
|
||||
|
||||
if (--gDocShellCount == 0) {
|
||||
NS_IF_RELEASE(sURIFixup);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* -*- 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
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- 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
|
||||
@@ -0,0 +1,124 @@
|
||||
/* -*- 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
|
||||
@@ -0,0 +1,76 @@
|
||||
/* -*- 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
|
||||
@@ -4,11 +4,23 @@
|
||||
# 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/.
|
||||
|
||||
Program('updater-xpcshell')
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "DOM")
|
||||
|
||||
updater_rel_path = '../'
|
||||
DIST_INSTALL = False
|
||||
DEFINES['TEST_UPDATER'] = True
|
||||
include('../updater-common.build')
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_BZ2_CFLAGS']
|
||||
EXPORTS.mozilla.dom += [
|
||||
'AbortController.h',
|
||||
'AbortSignal.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AbortController.cpp',
|
||||
'AbortSignal.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../workers',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
@@ -0,0 +1,113 @@
|
||||
<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>
|
||||
@@ -0,0 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
file_abort_controller.html
|
||||
worker_fetch_controller.js
|
||||
|
||||
[test_abort_controller.html]
|
||||
@@ -4,4 +4,5 @@
|
||||
# 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/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<!--
|
||||
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>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
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]();
|
||||
}
|
||||
@@ -7,6 +7,8 @@
|
||||
#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,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsXPIDLString;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#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 {
|
||||
|
||||
@@ -356,24 +356,16 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement,
|
||||
return aElement;
|
||||
}
|
||||
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
if (!primaryFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIFrame* pseudoFrame;
|
||||
if (aPseudoType == CSSPseudoElementType::before) {
|
||||
pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
|
||||
} else if (aPseudoType == CSSPseudoElementType::after) {
|
||||
pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
|
||||
} else {
|
||||
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
|
||||
"other that :before or :after");
|
||||
return nullptr;
|
||||
return nsLayoutUtils::GetBeforePseudo(aElement);
|
||||
}
|
||||
if (!pseudoFrame) {
|
||||
return nullptr;
|
||||
if (aPseudoType == CSSPseudoElementType::after) {
|
||||
return nsLayoutUtils::GetAfterPseudo(aElement);
|
||||
}
|
||||
return pseudoFrame->GetContent()->AsElement();
|
||||
|
||||
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
|
||||
"other that :before or :after");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#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"
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
|
||||
// For UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
#include "mozilla/dom/CSSPseudoElement.h"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -1105,19 +1107,17 @@ KeyframeEffectReadOnly::GetAnimationFrame() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* frame;
|
||||
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
|
||||
frame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
|
||||
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
|
||||
frame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
|
||||
} else {
|
||||
frame = mTarget->mElement->GetPrimaryFrame();
|
||||
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
|
||||
"unknown mTarget->mPseudoType");
|
||||
}
|
||||
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ EXPORTS.mozilla += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'KeyframeEffect.cpp',
|
||||
'KeyframeEffectReadOnly.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'Animation.cpp',
|
||||
'AnimationEffectReadOnly.cpp',
|
||||
'AnimationEffectTiming.cpp',
|
||||
@@ -50,9 +55,7 @@ UNIFIED_SOURCES += [
|
||||
'DocumentTimeline.cpp',
|
||||
'EffectCompositor.cpp',
|
||||
'EffectSet.cpp',
|
||||
'KeyframeEffect.cpp',
|
||||
'KeyframeEffectParams.cpp',
|
||||
'KeyframeEffectReadOnly.cpp',
|
||||
'KeyframeUtils.cpp',
|
||||
'PendingAnimationTracker.cpp',
|
||||
'TimingParams.cpp',
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -69,10 +71,10 @@ ArchiveRequest::~ArchiveRequest()
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ public:
|
||||
ArchiveReader* aReader);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
public:
|
||||
// This is called by the DOMArchiveRequestEvent
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
USING_ARCHIVEREADER_NAMESPACE
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ EXPORTS.mozilla.dom.archivereader += [
|
||||
'ArchiveZipFile.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'ArchiveEvent.cpp',
|
||||
'ArchiveReader.cpp',
|
||||
'ArchiveRequest.cpp',
|
||||
|
||||
@@ -16,14 +16,12 @@ EXPORTS += [
|
||||
'AudioChannelService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'AudioChannelAgent.cpp',
|
||||
'AudioChannelService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base/',
|
||||
]
|
||||
LOCAL_INCLUDES += ['/dom/base/']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "AnonymousContent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/AnonymousContentBinding.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMHTMLCollection.h"
|
||||
@@ -208,5 +209,31 @@ AnonymousContent::WrapObject(JSContext* aCx,
|
||||
return AnonymousContentBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
}
|
||||
|
||||
void
|
||||
AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||
const nsAString& aPropertyName,
|
||||
DOMString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Element* element = GetElementById(aElementId);
|
||||
if (!element) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = element->OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> cs =
|
||||
new nsComputedDOMStyle(element,
|
||||
NS_LITERAL_STRING(""),
|
||||
element->OwnerDoc(),
|
||||
nsComputedDOMStyle::eAll);
|
||||
aRv = cs->GetPropertyValue(aPropertyName, aResult);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -68,6 +68,11 @@ public:
|
||||
const Sequence<OwningNonNull<DOMRect>>& aRects,
|
||||
ErrorResult& aError);
|
||||
|
||||
void GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||
const nsAString& aPropertyName,
|
||||
DOMString& aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~AnonymousContent();
|
||||
nsCOMPtr<Element> mContentNode;
|
||||
|
||||
+1
-1
@@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
}
|
||||
|
||||
nsresult
|
||||
Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
return NS_OK;
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ public:
|
||||
// nsIDOMAttr interface
|
||||
NS_DECL_NSIDOMATTR
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
// nsIAttribute interface
|
||||
void SetMap(nsDOMAttributeMap *aMap) override;
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#define mozilla_dom_BlobSet_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef CORSMode_h_
|
||||
#define CORSMode_h_
|
||||
|
||||
|
||||
+123
-180
@@ -6,61 +6,27 @@
|
||||
|
||||
#include "ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/XBLChildrenElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MatchedNodes {
|
||||
public:
|
||||
explicit MatchedNodes(HTMLContentElement* aInsertionPoint)
|
||||
: mIsContentElement(true), mContentElement(aInsertionPoint) {}
|
||||
|
||||
explicit MatchedNodes(XBLChildrenElement* aInsertionPoint)
|
||||
: mIsContentElement(false), mChildrenElement(aInsertionPoint) {}
|
||||
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes().Length()
|
||||
: mChildrenElement->InsertedChildrenLength();
|
||||
}
|
||||
|
||||
nsIContent* operator[](int32_t aIndex) const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes()[aIndex]
|
||||
: mChildrenElement->InsertedChild(aIndex);
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes().IsEmpty()
|
||||
: !mChildrenElement->HasInsertedChildren();
|
||||
}
|
||||
protected:
|
||||
bool mIsContentElement;
|
||||
union {
|
||||
HTMLContentElement* mContentElement;
|
||||
XBLChildrenElement* mChildrenElement;
|
||||
};
|
||||
};
|
||||
|
||||
static inline MatchedNodes
|
||||
GetMatchedNodesForPoint(nsIContent* aContent)
|
||||
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIsFirst(aStartAtBeginning),
|
||||
mIndexInInserted(0)
|
||||
{
|
||||
if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
|
||||
// XBL case
|
||||
return MatchedNodes(static_cast<XBLChildrenElement*>(aContent));
|
||||
}
|
||||
|
||||
// Web components case
|
||||
MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::content));
|
||||
return MatchedNodes(HTMLContentElement::FromContent(aContent));
|
||||
mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
|
||||
HTMLSlotElement::FromContent(mParent) : nullptr;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
@@ -69,30 +35,29 @@ ExplicitChildIterator::GetNextChild()
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
|
||||
MOZ_ASSERT(!mDefaultChild);
|
||||
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (mIndexInInserted < assignedChildren.Length()) {
|
||||
return assignedChildren[mIndexInInserted++];
|
||||
}
|
||||
mIndexInInserted = 0;
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mShadowIterator) {
|
||||
// If we're inside of a <shadow> element, look through the
|
||||
// explicit children of the projected ShadowRoot via
|
||||
// the mShadowIterator.
|
||||
nsIContent* nextChild = mShadowIterator->GetNextChild();
|
||||
if (nextChild) {
|
||||
return nextChild;
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (mIndexInInserted < assignedNodes.Length()) ?
|
||||
assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
|
||||
return mChild;
|
||||
}
|
||||
|
||||
mShadowIterator = nullptr;
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement =
|
||||
static_cast<XBLChildrenElement*>(mChild);
|
||||
if (mIndexInInserted < childrenElement->InsertedChildrenLength()) {
|
||||
return childrenElement->InsertedChild(mIndexInInserted++);
|
||||
}
|
||||
mIndexInInserted = 0;
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
|
||||
mDefaultChild = mDefaultChild->GetNextSibling();
|
||||
if (mDefaultChild) {
|
||||
@@ -101,6 +66,19 @@ ExplicitChildIterator::GetNextChild()
|
||||
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mIsFirst) { // at the beginning of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = 1;
|
||||
mChild = assignedNodes[0]->AsContent();
|
||||
mIsFirst = false;
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetFirstChild();
|
||||
mIsFirst = false;
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
@@ -110,31 +88,16 @@ ExplicitChildIterator::GetNextChild()
|
||||
// Iterate until we find a non-insertion point, or an insertion point with
|
||||
// content.
|
||||
while (mChild) {
|
||||
// If the current child being iterated is a shadow insertion point then
|
||||
// the iterator needs to go into the projected ShadowRoot.
|
||||
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
|
||||
// Look for the next child in the projected ShadowRoot for the <shadow>
|
||||
// element.
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
|
||||
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
mShadowIterator = new ExplicitChildIterator(projectedShadow);
|
||||
nsIContent* nextChild = mShadowIterator->GetNextChild();
|
||||
if (nextChild) {
|
||||
return nextChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
}
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
|
||||
if (mChild->IsActiveChildrenElement()) {
|
||||
// If the current child being iterated is a content insertion point
|
||||
// then the iterator needs to return the nodes distributed into
|
||||
// the content insertion point.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (!assignedChildren.IsEmpty()) {
|
||||
auto* childrenElement =
|
||||
static_cast<XBLChildrenElement*>(mChild);
|
||||
if (childrenElement->HasInsertedChildren()) {
|
||||
// Iterate through elements projected on insertion point.
|
||||
mIndexInInserted = 1;
|
||||
return assignedChildren[0];
|
||||
return childrenElement->InsertedChild(0);
|
||||
}
|
||||
|
||||
// Insertion points inside fallback/default content
|
||||
@@ -192,19 +155,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
|
||||
}
|
||||
|
||||
bool
|
||||
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
|
||||
ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
|
||||
{
|
||||
if (aChildToFind->GetParent() == mParent &&
|
||||
!aChildToFind->IsRootOfAnonymousSubtree()) {
|
||||
// Fast path: just point ourselves to aChildToFind, which is a
|
||||
// normal DOM child of ours.
|
||||
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
|
||||
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
|
||||
mChild = aChildToFind;
|
||||
mChild = const_cast<nsIContent*>(aChildToFind);
|
||||
mIndexInInserted = 0;
|
||||
mShadowIterator = nullptr;
|
||||
mDefaultChild = nullptr;
|
||||
mIsFirst = false;
|
||||
MOZ_ASSERT(!mChild->IsActiveChildrenElement());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -220,12 +181,18 @@ ExplicitChildIterator::Get() const
|
||||
{
|
||||
MOZ_ASSERT(!mIsFirst);
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
} else if (mShadowIterator) {
|
||||
return mShadowIterator->Get();
|
||||
// When mParentAsSlot is set, mChild is always set to the current child. It
|
||||
// does not matter whether mChild is an assigned node or a fallback content.
|
||||
if (mParentAsSlot) {
|
||||
return mChild;
|
||||
}
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
|
||||
return mDefaultChild ? mDefaultChild : mChild;
|
||||
}
|
||||
|
||||
@@ -234,20 +201,28 @@ ExplicitChildIterator::GetPreviousChild()
|
||||
{
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (--mIndexInInserted) ?
|
||||
assignedNodes[mIndexInInserted - 1]->AsContent() : nullptr;
|
||||
|
||||
if (!mChild) {
|
||||
mIsFirst = true;
|
||||
}
|
||||
return mChild;
|
||||
}
|
||||
|
||||
// NB: mIndexInInserted points one past the last returned child so we need
|
||||
// to look *two* indices back in order to return the previous child.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
if (--mIndexInInserted) {
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (mShadowIterator) {
|
||||
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
|
||||
if (previousChild) {
|
||||
return previousChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
mDefaultChild = mDefaultChild->GetPreviousSibling();
|
||||
@@ -261,35 +236,32 @@ ExplicitChildIterator::GetPreviousChild()
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else { // at the end of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = assignedNodes.Length();
|
||||
mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetLastChild();
|
||||
}
|
||||
|
||||
// Iterate until we find a non-insertion point, or an insertion point with
|
||||
// content.
|
||||
while (mChild) {
|
||||
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
|
||||
// If the current child being iterated is a shadow insertion point then
|
||||
// the iterator needs to go into the projected ShadowRoot.
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
|
||||
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
// Create a ExplicitChildIterator that begins iterating from the end.
|
||||
mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
|
||||
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
|
||||
if (previousChild) {
|
||||
return previousChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
}
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
|
||||
if (mChild->IsActiveChildrenElement()) {
|
||||
// If the current child being iterated is a content insertion point
|
||||
// then the iterator needs to return the nodes distributed into
|
||||
// the content insertion point.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (!assignedChildren.IsEmpty()) {
|
||||
mIndexInInserted = assignedChildren.Length();
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
if (childrenElement->HasInsertedChildren()) {
|
||||
mIndexInInserted = childrenElement->InsertedChildrenLength();
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
|
||||
mDefaultChild = mChild->GetLastChild();
|
||||
@@ -317,11 +289,9 @@ AllChildrenIterator::Get() const
|
||||
{
|
||||
switch (mPhase) {
|
||||
case eAtBeforeKid: {
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
|
||||
return beforeFrame->GetContent();
|
||||
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
|
||||
return before;
|
||||
}
|
||||
|
||||
case eAtExplicitKids:
|
||||
@@ -331,11 +301,9 @@ AllChildrenIterator::Get() const
|
||||
return mAnonKids[mAnonKidsIdx];
|
||||
|
||||
case eAtAfterKid: {
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
|
||||
return afterFrame->GetContent();
|
||||
Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
|
||||
return after;
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -345,19 +313,14 @@ AllChildrenIterator::Get() const
|
||||
|
||||
|
||||
bool
|
||||
AllChildrenIterator::Seek(nsIContent* aChildToFind)
|
||||
AllChildrenIterator::Seek(const nsIContent* aChildToFind)
|
||||
{
|
||||
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
if (beforeFrame->GetContent() == aChildToFind) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforePseudo && beforePseudo == aChildToFind) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,12 +346,10 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
|
||||
|
||||
// The root scroll frame is not the primary frame of the root element.
|
||||
// Detect and handle this case.
|
||||
if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
|
||||
nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
|
||||
nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
|
||||
if (scrollFrame) {
|
||||
AppendNativeAnonymousChildrenFromFrame(scrollFrame);
|
||||
}
|
||||
if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
|
||||
mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
|
||||
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
mOriginalContent->OwnerDoc(), mAnonKids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,13 +367,10 @@ AllChildrenIterator::GetNextChild()
|
||||
{
|
||||
if (mPhase == eAtBegin) {
|
||||
mPhase = eAtExplicitKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeFrame->GetContent();
|
||||
}
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,13 +406,10 @@ AllChildrenIterator::GetNextChild()
|
||||
return mAnonKids[mAnonKidsIdx];
|
||||
}
|
||||
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
if (afterFrame) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterFrame->GetContent();
|
||||
}
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,13 +423,10 @@ AllChildrenIterator::GetPreviousChild()
|
||||
if (mPhase == eAtEnd) {
|
||||
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
|
||||
mPhase = eAtAnonKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
if (afterFrame) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterFrame->GetContent();
|
||||
}
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,13 +455,10 @@ AllChildrenIterator::GetPreviousChild()
|
||||
return kid;
|
||||
}
|
||||
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeFrame->GetContent();
|
||||
}
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,12 +534,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
|
||||
return true;
|
||||
}
|
||||
|
||||
// The root element has a scroll frame that is not the primary frame, so we
|
||||
// need to do special checking for that case.
|
||||
if (aElement == aElement->OwnerDoc()->GetRootElement()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+41
-36
@@ -36,27 +36,20 @@ class ExplicitChildIterator
|
||||
{
|
||||
public:
|
||||
explicit ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIndexInInserted(0),
|
||||
mIsFirst(aStartAtBeginning)
|
||||
{
|
||||
}
|
||||
bool aStartAtBeginning = true);
|
||||
|
||||
ExplicitChildIterator(const ExplicitChildIterator& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mShadowIterator(aOther.mShadowIterator ?
|
||||
new ExplicitChildIterator(*aOther.mShadowIterator) :
|
||||
nullptr),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
ExplicitChildIterator(ExplicitChildIterator&& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mShadowIterator(Move(aOther.mShadowIterator)),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
nsIContent* GetNextChild();
|
||||
@@ -65,13 +58,13 @@ public:
|
||||
// found. This version can take shortcuts that the two-argument version
|
||||
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
|
||||
// cases).
|
||||
bool Seek(nsIContent* aChildToFind);
|
||||
bool Seek(const nsIContent* aChildToFind);
|
||||
|
||||
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
|
||||
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
|
||||
// whether aChildToFind was found as an explicit child prior to encountering
|
||||
// aBound.
|
||||
bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
|
||||
bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
|
||||
{
|
||||
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
||||
// we might not find aChildToFind when called from ContentInserted
|
||||
@@ -102,6 +95,10 @@ protected:
|
||||
// the <xbl:content> element for the binding.
|
||||
const nsIContent* mParent;
|
||||
|
||||
// If parent is a slot element, this points to the parent as HTMLSlotElement,
|
||||
// otherwise, it's null.
|
||||
const HTMLSlotElement* mParentAsSlot;
|
||||
|
||||
// The current child. When we encounter an insertion point,
|
||||
// mChild remains as the insertion point whose content we're iterating (and
|
||||
// our state is controled by mDefaultChild or mIndexInInserted depending on
|
||||
@@ -114,11 +111,6 @@ protected:
|
||||
// to null, we continue iterating at mChild's next sibling.
|
||||
nsIContent* mDefaultChild;
|
||||
|
||||
// If non-null, this points to an iterator of the explicit children of
|
||||
// the ShadowRoot projected by the current shadow element that we're
|
||||
// iterating.
|
||||
nsAutoPtr<ExplicitChildIterator> mShadowIterator;
|
||||
|
||||
// If not zero, we're iterating inserted children for an insertion point. This
|
||||
// is an index into mChild's inserted children array (mChild must be an
|
||||
// nsXBLChildrenElement). The index is one past the "current" child (as
|
||||
@@ -139,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
|
||||
public:
|
||||
explicit FlattenedChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||
, mXBLInvolved(false)
|
||||
, mOriginalContent(aParent)
|
||||
{
|
||||
Init(false);
|
||||
}
|
||||
|
||||
FlattenedChildIterator(FlattenedChildIterator&& aOther)
|
||||
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
|
||||
: ExplicitChildIterator(Move(aOther))
|
||||
, mXBLInvolved(aOther.mXBLInvolved)
|
||||
, mOriginalContent(aOther.mOriginalContent)
|
||||
{}
|
||||
|
||||
FlattenedChildIterator(const FlattenedChildIterator& aOther)
|
||||
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
|
||||
: ExplicitChildIterator(aOther)
|
||||
, mXBLInvolved(aOther.mXBLInvolved)
|
||||
, mOriginalContent(aOther.mOriginalContent)
|
||||
{}
|
||||
|
||||
bool XBLInvolved() { return mXBLInvolved; }
|
||||
|
||||
const nsIContent* Parent() const { return mOriginalContent; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This constructor is a hack to help AllChildrenIterator which sometimes
|
||||
@@ -159,7 +161,9 @@ protected:
|
||||
*/
|
||||
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
|
||||
bool aStartAtBeginning = true)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||
, mXBLInvolved(false)
|
||||
, mOriginalContent(aParent)
|
||||
{
|
||||
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
|
||||
Init(ignoreXBL);
|
||||
@@ -170,6 +174,8 @@ protected:
|
||||
// For certain optimizations, nsCSSFrameConstructor needs to know if the
|
||||
// child list of the element that we're iterating matches its .childNodes.
|
||||
bool mXBLInvolved;
|
||||
|
||||
const nsIContent* mOriginalContent;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -187,12 +193,11 @@ public:
|
||||
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
|
||||
bool aStartAtBeginning = true) :
|
||||
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
|
||||
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
||||
mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
||||
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
|
||||
|
||||
AllChildrenIterator(AllChildrenIterator&& aOther)
|
||||
: FlattenedChildIterator(Move(aOther)),
|
||||
mOriginalContent(aOther.mOriginalContent),
|
||||
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
|
||||
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
|
||||
#ifdef DEBUG
|
||||
@@ -211,11 +216,10 @@ public:
|
||||
// Seeks the given node in children of a parent element, starting from
|
||||
// the current iterator's position, and sets the iterator at the given child
|
||||
// node if it was found.
|
||||
bool Seek(nsIContent* aChildToFind);
|
||||
bool Seek(const nsIContent* aChildToFind);
|
||||
|
||||
nsIContent* GetNextChild();
|
||||
nsIContent* GetPreviousChild();
|
||||
const nsIContent* Parent() const { return mOriginalContent; }
|
||||
|
||||
enum IteratorPhase
|
||||
{
|
||||
@@ -233,8 +237,6 @@ private:
|
||||
void AppendNativeAnonymousChildren();
|
||||
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
|
||||
|
||||
const nsIContent* mOriginalContent;
|
||||
|
||||
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
||||
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
|
||||
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
|
||||
@@ -256,10 +258,11 @@ private:
|
||||
/**
|
||||
* StyleChildrenIterator traverses the children of the element from the
|
||||
* perspective of the style system, particularly the children we need to traverse
|
||||
* during restyle. This is identical to AllChildrenIterator with eAllChildren,
|
||||
* _except_ that we detect and skip any native anonymous children that are used
|
||||
* to implement pseudo-elements (since the style system needs to cascade those
|
||||
* using different algorithms).
|
||||
* during restyle. This is identical to AllChildrenIterator with
|
||||
* (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
|
||||
* detect and skip any native anonymous children that are used to implement
|
||||
* pseudo-elements (since the style system needs to cascade those using
|
||||
* different algorithms).
|
||||
*
|
||||
* Note: it assumes that no mutation of the DOM or frame tree takes place during
|
||||
* iteration, and will break horribly if that is not true.
|
||||
@@ -267,7 +270,9 @@ private:
|
||||
class StyleChildrenIterator : private AllChildrenIterator {
|
||||
public:
|
||||
explicit StyleChildrenIterator(const nsIContent* aContent)
|
||||
: AllChildrenIterator(aContent, nsIContent::eAllChildren)
|
||||
: AllChildrenIterator(aContent,
|
||||
nsIContent::eAllChildren |
|
||||
nsIContent::eSkipDocumentLevelNativeAnonymousContent)
|
||||
{
|
||||
MOZ_COUNT_CTOR(StyleChildrenIterator);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/ChromeNodeList.h"
|
||||
#include "mozilla/dom/ChromeNodeListBinding.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/ChromeUtilsBinding.h"
|
||||
#include "mozilla/dom/ThreadSafeChromeUtilsBinding.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include "mozilla/dom/HTMLElementBinding.h"
|
||||
#include "mozilla/dom/WebComponentsBinding.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -291,7 +293,6 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
|
||||
nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
|
||||
nsWeakPtr* elem = unresolved->AppendElement();
|
||||
*elem = do_GetWeakReference(aElement);
|
||||
aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -414,19 +415,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
||||
reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype)
|
||||
{
|
||||
mozilla::dom::CustomElementDefinition* definition =
|
||||
mCustomDefinitions.GetWeak(aAtom);
|
||||
if (definition) {
|
||||
aPrototype.set(definition->mPrototype);
|
||||
} else {
|
||||
aPrototype.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey,
|
||||
CustomElementDefinition* aDefinition,
|
||||
@@ -466,6 +454,12 @@ nsISupports* CustomElementRegistry::GetParentObject() const
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
DocGroup*
|
||||
CustomElementRegistry::GetDocGroup() const
|
||||
{
|
||||
return mWindow ? mWindow->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
||||
static const char* kLifeCycleCallbackNames[] = {
|
||||
"connectedCallback",
|
||||
"disconnectedCallback",
|
||||
@@ -588,14 +582,8 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
return;
|
||||
}
|
||||
|
||||
nsIParserService* ps = nsContentUtils::GetParserService();
|
||||
if (!ps) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// bgsound and multicol are unknown html element.
|
||||
int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
|
||||
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
|
||||
if (tag == eHTMLTag_userdefined ||
|
||||
tag == eHTMLTag_bgsound ||
|
||||
tag == eHTMLTag_multicol) {
|
||||
@@ -630,9 +618,9 @@ CustomElementRegistry::Define(const nsAString& aName,
|
||||
*/
|
||||
JSAutoCompartment ac(cx, constructor);
|
||||
JS::Rooted<JS::Value> prototypev(cx);
|
||||
// The .prototype on the constructor passed from document.registerElement
|
||||
// is the "expando" of a wrapper. So we should get it from wrapper instead
|
||||
// instead of underlying object.
|
||||
// The .prototype on the constructor passed could be an "expando" of a
|
||||
// wrapper. So we should get it from wrapper instead of the underlying
|
||||
// object.
|
||||
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
@@ -878,8 +866,6 @@ CustomElementRegistry::Upgrade(Element* aElement,
|
||||
CustomElementDefinition* aDefinition,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
|
||||
MOZ_ASSERT(data, "CustomElementData should exist");
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ struct CustomElementData;
|
||||
struct ElementDefinitionOptions;
|
||||
class CallbackFunction;
|
||||
class CustomElementReaction;
|
||||
class DocGroup;
|
||||
class Function;
|
||||
class Promise;
|
||||
|
||||
@@ -423,9 +424,6 @@ public:
|
||||
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||
CustomElementDefinition* aDefinition);
|
||||
|
||||
void GetCustomPrototype(nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype);
|
||||
|
||||
/**
|
||||
* Upgrade an element.
|
||||
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
|
||||
@@ -434,8 +432,7 @@ public:
|
||||
|
||||
/**
|
||||
* Registers an unresolved custom element that is a candidate for
|
||||
* upgrade when the definition is registered via registerElement.
|
||||
* |aTypeName| is the name of the custom element type, if it is not
|
||||
* upgrade. |aTypeName| is the name of the custom element type, if it is not
|
||||
* provided, then element name is used. |aTypeName| should be provided
|
||||
* when registering a custom element that extends an existing
|
||||
* element. e.g. <button is="x-button">.
|
||||
@@ -472,8 +469,8 @@ private:
|
||||
js::SystemAllocPolicy> ConstructorMap;
|
||||
|
||||
// Hashtable for custom element definitions in web components.
|
||||
// Custom prototypes are stored in the compartment where
|
||||
// registerElement was called.
|
||||
// Custom prototypes are stored in the compartment where definition was
|
||||
// defined.
|
||||
DefinitionMap mCustomDefinitions;
|
||||
|
||||
// Hashtable for looking up definitions by using constructor as key.
|
||||
@@ -517,6 +514,8 @@ private:
|
||||
public:
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void Define(const nsAString& aName, Function& aFunctionConstructor,
|
||||
|
||||
@@ -728,7 +728,7 @@ WalkDescendantsResetAutoDirection(Element* aElement)
|
||||
{
|
||||
nsIContent* child = aElement->GetFirstChild();
|
||||
while (child) {
|
||||
if (child->HasDirAuto()) {
|
||||
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
|
||||
child = child->GetNextNonChildNode(aElement);
|
||||
continue;
|
||||
}
|
||||
@@ -791,7 +791,7 @@ WalkDescendantsClearAncestorDirAuto(Element* aElement)
|
||||
{
|
||||
nsIContent* child = aElement->GetFirstChild();
|
||||
while (child) {
|
||||
if (child->HasDirAuto()) {
|
||||
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
|
||||
child = child->GetNextNonChildNode(aElement);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
@@ -6,10 +10,14 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
|
||||
|
||||
/* static */ void
|
||||
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
|
||||
{
|
||||
@@ -54,5 +62,23 @@ DocGroup::~DocGroup()
|
||||
|
||||
NS_IMPL_ISUPPORTS(DocGroup, nsISupports)
|
||||
|
||||
void
|
||||
DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
|
||||
{
|
||||
if (mSignalSlotList.Contains(aSlot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
|
||||
|
||||
if (!sPendingDocGroups) {
|
||||
// Queue a mutation observer compound microtask.
|
||||
nsDOMMutationObserver::QueueMutationObserverMicroTask();
|
||||
sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
|
||||
}
|
||||
|
||||
sPendingDocGroups->AppendElement(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -73,6 +74,23 @@ public:
|
||||
return mDocuments.end();
|
||||
}
|
||||
|
||||
// Append aSlot to the list of signal slot list, if it's not in it already
|
||||
// list, and queue a mutation observer microtask.
|
||||
void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
|
||||
|
||||
const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
|
||||
{
|
||||
return mSignalSlotList;
|
||||
}
|
||||
|
||||
void ClearSignalSlotList()
|
||||
{
|
||||
mSignalSlotList.Clear();
|
||||
}
|
||||
|
||||
// List of DocGroups that has non-empty signal slot list.
|
||||
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
|
||||
|
||||
private:
|
||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||
~DocGroup();
|
||||
@@ -81,6 +99,7 @@ private:
|
||||
RefPtr<TabGroup> mTabGroup;
|
||||
nsTArray<nsIDocument*> mDocuments;
|
||||
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
||||
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -125,6 +125,8 @@ DocumentFragment::Constructor(const GlobalObject& aGlobal,
|
||||
return window->GetDoc()->CreateDocumentFragment();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
|
||||
|
||||
// QueryInterface implementation for DocumentFragment
|
||||
NS_INTERFACE_MAP_BEGIN(DocumentFragment)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
|
||||
|
||||
// interface nsIDOMNode
|
||||
NS_FORWARD_NSIDOMNODE_TO_NSINODE
|
||||
@@ -121,15 +122,9 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* GetHost() const
|
||||
{
|
||||
return mHost;
|
||||
}
|
||||
Element* GetHost() const { return mHost; }
|
||||
|
||||
void SetHost(nsIContent* aHost)
|
||||
{
|
||||
mHost = aHost;
|
||||
}
|
||||
void SetHost(Element* aHost) { mHost = aHost; }
|
||||
|
||||
static already_AddRefed<DocumentFragment>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
@@ -145,7 +140,7 @@ protected:
|
||||
}
|
||||
|
||||
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
nsIContent* mHost; // Weak
|
||||
nsCOMPtr<Element> mHost;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/* -*- 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
|
||||
+314
-250
@@ -166,8 +166,7 @@ nsIContent::DoGetID() const
|
||||
const nsAttrValue*
|
||||
Element::DoGetClasses() const
|
||||
{
|
||||
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
|
||||
|
||||
MOZ_ASSERT(MayHaveClass(), "Unexpected call");
|
||||
if (IsSVGElement()) {
|
||||
const nsAttrValue* animClass =
|
||||
static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
|
||||
@@ -470,50 +469,11 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
|
||||
JSObject*
|
||||
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
|
||||
JS::Rooted<JSObject*> customProto(aCx);
|
||||
|
||||
if (!givenProto) {
|
||||
// Custom element prototype swizzling.
|
||||
CustomElementData* data = GetCustomElementData();
|
||||
if (data) {
|
||||
// If this is a registered custom element then fix the prototype.
|
||||
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
||||
data->GetCustomElementType(), &customProto);
|
||||
if (customProto &&
|
||||
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
|
||||
// The custom element prototype could be in different compartment.
|
||||
if (!JS_WrapObject(aCx, &customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
// Just go ahead and create with the right proto up front. Set
|
||||
// customProto to null to flag that we don't need to do any post-facto
|
||||
// proto fixups here.
|
||||
givenProto = customProto;
|
||||
customProto = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (customProto) {
|
||||
// We want to set the custom prototype in the compartment where it was
|
||||
// registered. In the case that |obj| and |prototype| are in different
|
||||
// compartments, this will set the prototype on the |obj|'s wrapper and
|
||||
// thus only visible in the wrapper's compartment, since we know obj's
|
||||
// principal does not subsume customProto's in this case.
|
||||
JSAutoCompartment ac(aCx, customProto);
|
||||
JS::Rooted<JSObject*> wrappedObj(aCx, obj);
|
||||
if (!JS_WrapObject(aCx, &wrappedObj) ||
|
||||
!JS_SetPrototype(aCx, wrappedObj, customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* doc;
|
||||
if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
doc = OwnerDoc();
|
||||
@@ -1093,9 +1053,102 @@ Element::RemoveFromIdTable()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Element::SetSlot(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
|
||||
}
|
||||
|
||||
void
|
||||
Element::GetSlot(nsAString& aName)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-element-shadowroot
|
||||
ShadowRoot*
|
||||
Element::GetShadowRootByMode() const
|
||||
{
|
||||
/**
|
||||
* 1. Let shadow be context 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;
|
||||
@@ -1113,12 +1166,9 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
nsIContent* destroyedFramesFor = nullptr;
|
||||
if (doc) {
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (shell) {
|
||||
shell->DestroyFramesFor(this, &destroyedFramesFor);
|
||||
if (nsIDocument* doc = GetComposedDoc()) {
|
||||
if (nsIPresShell* shell = doc->GetShell()) {
|
||||
shell->DestroyFramesForAndRestyle(this);
|
||||
MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
|
||||
}
|
||||
}
|
||||
@@ -1130,29 +1180,20 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
||||
// Calling SetPrototypeBinding takes ownership of protoBinding.
|
||||
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
|
||||
|
||||
RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
|
||||
protoBinding);
|
||||
/**
|
||||
* 4. Let shadow be a new shadow root whose node document is
|
||||
* context object’s node document, host is context object,
|
||||
* and mode is init’s mode.
|
||||
*/
|
||||
RefPtr<ShadowRoot> shadowRoot =
|
||||
new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
|
||||
|
||||
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
|
||||
// Replace the old ShadowRoot with the new one and let the old
|
||||
// ShadowRoot know about the younger ShadowRoot because the old
|
||||
// ShadowRoot is projected into the younger ShadowRoot's shadow
|
||||
// insertion point (if it exists).
|
||||
ShadowRoot* olderShadow = GetShadowRoot();
|
||||
/**
|
||||
* 5. Set context object’s shadow root to shadow.
|
||||
*/
|
||||
SetShadowRoot(shadowRoot);
|
||||
if (olderShadow) {
|
||||
olderShadow->SetYoungerShadow(shadowRoot);
|
||||
|
||||
// Unbind children of older shadow root because they
|
||||
// are no longer in the composed tree.
|
||||
for (nsIContent* child = olderShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
olderShadow->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
|
||||
// xblBinding takes ownership of docInfo.
|
||||
RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
|
||||
@@ -1161,96 +1202,12 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
||||
|
||||
SetXBLBinding(xblBinding);
|
||||
|
||||
// Recreate the frame for the bound content because binding a ShadowRoot
|
||||
// changes how things are rendered.
|
||||
if (doc) {
|
||||
MOZ_ASSERT(doc == GetComposedDoc());
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (shell) {
|
||||
shell->CreateFramesFor(destroyedFramesFor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. Return shadow.
|
||||
*/
|
||||
return shadowRoot.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DestinationInsertionPointList, mParent,
|
||||
mDestinationPoints)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(DestinationInsertionPointList)
|
||||
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
|
||||
NS_INTERFACE_TABLE(DestinationInsertionPointList, nsINodeList, nsIDOMNodeList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DestinationInsertionPointList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DestinationInsertionPointList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DestinationInsertionPointList)
|
||||
|
||||
DestinationInsertionPointList::DestinationInsertionPointList(Element* aElement)
|
||||
: mParent(aElement)
|
||||
{
|
||||
nsTArray<nsIContent*>* destPoints = aElement->GetExistingDestInsertionPoints();
|
||||
if (destPoints) {
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
mDestinationPoints.AppendElement(destPoints->ElementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DestinationInsertionPointList::~DestinationInsertionPointList()
|
||||
{
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
DestinationInsertionPointList::Item(uint32_t aIndex)
|
||||
{
|
||||
return mDestinationPoints.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DestinationInsertionPointList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsIContent* item = Item(aIndex);
|
||||
if (!item) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return CallQueryInterface(item, aReturn);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DestinationInsertionPointList::Length() const
|
||||
{
|
||||
return mDestinationPoints.Length();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DestinationInsertionPointList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
*aLength = Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
DestinationInsertionPointList::IndexOf(nsIContent* aContent)
|
||||
{
|
||||
return mDestinationPoints.IndexOf(aContent);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DestinationInsertionPointList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<DestinationInsertionPointList>
|
||||
Element::GetDestinationInsertionPoints()
|
||||
{
|
||||
RefPtr<DestinationInsertionPointList> list =
|
||||
new DestinationInsertionPointList(this);
|
||||
return list.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
|
||||
{
|
||||
@@ -2383,7 +2340,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
||||
bool aNotify,
|
||||
nsAttrValue& aOldValue,
|
||||
uint8_t* aModType,
|
||||
bool* aHasListeners)
|
||||
bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
bool modification = false;
|
||||
*aHasListeners = aNotify &&
|
||||
@@ -2391,6 +2349,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
||||
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
||||
this);
|
||||
|
||||
*aOldValueSet = false;
|
||||
|
||||
// If we have no listeners and aNotify is false, we are almost certainly
|
||||
// coming from the content sink and will almost certainly have no previous
|
||||
// value. Even if we do, setting the value is cheap when we have no
|
||||
@@ -2414,6 +2374,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
||||
// We have to serialize the value anyway in order to create the
|
||||
// mutation event so there's no cost in doing it now.
|
||||
aOldValue.SetToSerialized(*info.mValue);
|
||||
*aOldValueSet = true;
|
||||
}
|
||||
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
|
||||
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
|
||||
@@ -2433,10 +2394,12 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners)
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
|
||||
aOldValue, aModType, aHasListeners)) {
|
||||
aOldValue, aModType, aHasListeners,
|
||||
aOldValueSet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2445,12 +2408,45 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
|
||||
{
|
||||
// Keep this in sync with SetAttr and SetParsedAttr below.
|
||||
|
||||
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAttrValue value(aSingleClassName);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
|
||||
|
||||
// In principle, BeforeSetAttr should be called here if a node type
|
||||
// existed that wanted to do something special for class, but there
|
||||
// is no such node type, so calling SetMayHaveClass() directly.
|
||||
SetMayHaveClass();
|
||||
|
||||
return SetAttrAndNotify(kNameSpaceID_None,
|
||||
nsGkAtoms::_class,
|
||||
nullptr, // prefix
|
||||
nullptr, // old value
|
||||
value,
|
||||
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
|
||||
false, // hasListeners
|
||||
false, // notify
|
||||
kCallAfterSetAttr,
|
||||
document,
|
||||
updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetParsedAttr below
|
||||
// Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
|
||||
// above.
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
@@ -2462,17 +2458,27 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
|
||||
uint8_t modType;
|
||||
bool hasListeners;
|
||||
// We don't want to spend time preparsing class attributes if the value is not
|
||||
// changing, so just init our nsAttrValueOrString with aValue for the
|
||||
// OnlyNotifySameValueSet call.
|
||||
nsAttrValueOrString value(aValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
|
||||
nsAttrValue attrValue;
|
||||
nsAttrValue* preparsedAttrValue;
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
|
||||
attrValue.ParseAtomArray(aValue);
|
||||
value.ResetToAttrValue(attrValue);
|
||||
preparsedAttrValue = &attrValue;
|
||||
} else {
|
||||
preparsedAttrValue = nullptr;
|
||||
}
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
@@ -2481,21 +2487,23 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
|
||||
// Hold a script blocker while calling ParseAttribute since that can call
|
||||
// out to id-observers
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
nsAttrValue attrValue;
|
||||
if (preparsedAttrValue) {
|
||||
attrValue.SwapValueWith(*preparsedAttrValue);
|
||||
}
|
||||
// Even the value was pre-parsed in BeforeSetAttr, we still need to call
|
||||
// ParseAttribute because it can have side effects.
|
||||
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!preparsedAttrValue &&
|
||||
!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
||||
attrValue.SetTo(aValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
PreIdMaybeChange(aNamespaceID, aName, &value);
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
attrValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr);
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -2503,7 +2511,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetAttr above
|
||||
// Keep this in sync with SetAttr and SetSingleClassFromParser above
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
@@ -2518,41 +2526,46 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
bool hasListeners;
|
||||
nsAttrValueOrString value(aParsedValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
&aParsedValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PreIdMaybeChange(aNamespaceID, aName, &value);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
aParsedValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr);
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
bool aNotify,
|
||||
bool aCallAfterSetAttr)
|
||||
bool aCallAfterSetAttr,
|
||||
nsIDocument* aComposedDocument,
|
||||
const mozAutoDocUpdate&)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
nsMutationGuard::DidMutate();
|
||||
|
||||
// Copy aParsedValue for later use since it will be lost when we call
|
||||
@@ -2564,6 +2577,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
|
||||
bool hadValidDir = false;
|
||||
bool hadDirAuto = false;
|
||||
bool oldValueSet;
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::dir) {
|
||||
@@ -2574,8 +2588,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
// XXXbz Perhaps we should push up the attribute mapping function
|
||||
// stuff to Element?
|
||||
if (!IsAttributeMapped(aName) ||
|
||||
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
|
||||
!SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2584,24 +2598,34 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
aNamespaceID,
|
||||
nsIDOMNode::ATTRIBUTE_NODE);
|
||||
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
|
||||
}
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
const nsAttrValue* oldValue =
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
// oldValue will be null if there was no previously set value
|
||||
const nsAttrValue* oldValue;
|
||||
if (aParsedValue.StoresOwnData()) {
|
||||
if (oldValueSet) {
|
||||
oldValue = &aParsedValue;
|
||||
} else {
|
||||
oldValue = nullptr;
|
||||
}
|
||||
} else {
|
||||
// No need to conditionally assign null here. If there was no previously
|
||||
// set value for the attribute, aOldValue will already be null.
|
||||
oldValue = aOldValue;
|
||||
}
|
||||
|
||||
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
RefPtr<nsXBLBinding> binding = GetXBLBinding();
|
||||
if (binding) {
|
||||
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
@@ -2611,7 +2635,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
|
||||
"AttributeChanged callback should fire only if "
|
||||
"custom element state is custom");
|
||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
} else {
|
||||
// If there is no old value, get the value of the uninitialized attribute
|
||||
// that was swapped with aParsedValue.
|
||||
oldValueAtom = aParsedValue.GetAsAtom();
|
||||
}
|
||||
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
@@ -2631,7 +2662,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
}
|
||||
|
||||
if (aCallAfterSetAttr) {
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
|
||||
aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
@@ -2640,12 +2672,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (aNotify) {
|
||||
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
|
||||
// Callers only compute aOldValue under certain conditions which may not
|
||||
// be triggered by all nsIMutationObservers.
|
||||
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
|
||||
oldValue == &aParsedValue ? &aParsedValue : nullptr);
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
|
||||
}
|
||||
|
||||
if (aFireMutation) {
|
||||
@@ -2663,7 +2697,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
if (!newValue.IsEmpty()) {
|
||||
mutation.mNewAttrValue = NS_Atomize(newValue);
|
||||
}
|
||||
if (!oldValue->IsEmptyString()) {
|
||||
if (oldValue && !oldValue->IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = oldValue->GetAsAtom();
|
||||
}
|
||||
mutation.mAttrChange = aModType;
|
||||
@@ -2675,25 +2709,6 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::_class) {
|
||||
// aValue->GetAttrValue will only be non-null here when this is called
|
||||
// via Element::SetParsedAttr. This shouldn't happen for "class", but
|
||||
// this will handle it.
|
||||
if (aValue && !aValue->GetAttrValue()) {
|
||||
nsAttrValue attr;
|
||||
attr.ParseAtomArray(aValue->String());
|
||||
aValue->TakeParsedValue(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Element::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
@@ -2701,22 +2716,16 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::_class) {
|
||||
SetFlags(NODE_MAY_HAVE_CLASS);
|
||||
// Result should have been preparsed above.
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
|
||||
"The class attribute should be preparsed and therefore should "
|
||||
"never be passed to Element::ParseAttribute");
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
// Store id as an atom. id="" means that the element has no id,
|
||||
// not that it has an emptystring as the id.
|
||||
RemoveFromIdTable();
|
||||
if (aValue.IsEmpty()) {
|
||||
ClearHasID();
|
||||
return false;
|
||||
}
|
||||
aResult.ParseAtom(aValue);
|
||||
SetHasID();
|
||||
AddToIdTable(aResult.GetAtomValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2725,15 +2734,71 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
||||
}
|
||||
|
||||
bool
|
||||
Element::SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval)
|
||||
Element::SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval)
|
||||
{
|
||||
*aRetval = NS_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::_class) {
|
||||
if (aValue) {
|
||||
// Note: This flag is asymmetrical. It is never unset and isn't exact.
|
||||
// If it is ever made to be exact, we probably need to handle this
|
||||
// similarly to how ids are handled in PreIdMaybeChange and
|
||||
// PostIdMaybeChange.
|
||||
// Note that SetSingleClassFromParser inlines BeforeSetAttr and
|
||||
// calls SetMayHaveClass directly. Making a subclass take action
|
||||
// on the class attribute in a BeforeSetAttr override would
|
||||
// require revising SetSingleClassFromParser.
|
||||
SetMayHaveClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue)
|
||||
{
|
||||
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
|
||||
return;
|
||||
}
|
||||
RemoveFromIdTable();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue)
|
||||
{
|
||||
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// id="" means that the element has no id, not that it has an empty
|
||||
// string as the id.
|
||||
if (aValue && !aValue->IsEmptyString()) {
|
||||
SetHasID();
|
||||
AddToIdTable(aValue->GetAtomValue());
|
||||
} else {
|
||||
ClearHasID();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EventListenerManager*
|
||||
Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
|
||||
bool* aDefer)
|
||||
@@ -2810,9 +2875,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIDocument *document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
@@ -2822,11 +2884,16 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasMutationListeners = aNotify &&
|
||||
nsContentUtils::HasMutationListeners(this,
|
||||
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
||||
this);
|
||||
|
||||
PreIdMaybeChange(aNameSpaceID, aName, nullptr);
|
||||
|
||||
// Grab the attr node if needed before we remove it from the attr map
|
||||
RefPtr<Attr> attrNode;
|
||||
if (hasMutationListeners) {
|
||||
@@ -2845,12 +2912,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
// react to unexpected attribute changes.
|
||||
nsMutationGuard::DidMutate();
|
||||
|
||||
if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
|
||||
// Have to do this before clearing flag. See RemoveFromIdTable
|
||||
RemoveFromIdTable();
|
||||
ClearHasID();
|
||||
}
|
||||
|
||||
bool hadValidDir = false;
|
||||
bool hadDirAuto = false;
|
||||
|
||||
@@ -2863,6 +2924,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PostIdMaybeChange(aNameSpaceID, aName, nullptr);
|
||||
|
||||
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
RefPtr<nsXBLBinding> binding = GetXBLBinding();
|
||||
if (binding) {
|
||||
@@ -2870,8 +2933,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
@@ -2898,6 +2959,11 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (aNotify) {
|
||||
// We can always pass oldValue here since there is no new value which could
|
||||
// have corrupted it.
|
||||
@@ -2905,9 +2971,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIDOMMutationEvent::REMOVAL, &oldValue);
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
|
||||
}
|
||||
@@ -3129,7 +3192,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
||||
Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Optimisation: return early if this event doesn't interest us.
|
||||
// IMPORTANT: this switch and the switch below it must be kept in sync!
|
||||
@@ -3151,8 +3214,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// We do the status bar updates in PreHandleEvent so that the status bar gets
|
||||
// updated even if the event is consumed before we have a chance to set it.
|
||||
// We do the status bar updates in GetEventTargetParent so that the status bar
|
||||
// gets updated even if the event is consumed before we have a chance to set
|
||||
// it.
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
// Set the status bar similarly for mouseover and focus
|
||||
case eMouseOver:
|
||||
|
||||
+192
-61
@@ -41,6 +41,7 @@
|
||||
#include "Units.h"
|
||||
#include "DOMIntersectionObserver.h"
|
||||
|
||||
class mozAutoDocUpdate;
|
||||
class nsIFrame;
|
||||
class nsIDOMMozNamedAttrMap;
|
||||
class nsIURI;
|
||||
@@ -138,12 +139,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
|
||||
@@ -254,6 +255,23 @@ public:
|
||||
*/
|
||||
void ClearStyleStateLocks();
|
||||
|
||||
/**
|
||||
* Accessors for the state of our dir attribute.
|
||||
*/
|
||||
bool HasDirAuto() const
|
||||
{
|
||||
return State().HasState(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Elements with dir="rtl" or dir="ltr".
|
||||
*/
|
||||
bool HasFixedDir() const
|
||||
{
|
||||
return State().HasAtLeastOneOfStates(NS_EVENT_STATE_DIR_ATTR_LTR |
|
||||
NS_EVENT_STATE_DIR_ATTR_RTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the inline style declaration, if any, for this element.
|
||||
*/
|
||||
@@ -379,17 +397,10 @@ public:
|
||||
|
||||
bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
|
||||
|
||||
// The bdi element defaults to dir=auto if it has no dir attribute set.
|
||||
// Other elements will only have dir=auto if they have an explicit dir=auto,
|
||||
// which will mean that HasValidDir() returns true but HasFixedDir() returns
|
||||
// false
|
||||
inline bool HasDirAuto() const {
|
||||
return (!HasFixedDir() &&
|
||||
(HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
|
||||
}
|
||||
|
||||
Directionality GetComputedDirectionality() const;
|
||||
|
||||
inline Element* GetFlattenedTreeParentElementForStyle() const;
|
||||
|
||||
/**
|
||||
* Gets the custom element data used by web components custom element.
|
||||
* Custom element data is created at the first attempt to enqueue a callback.
|
||||
@@ -460,6 +471,9 @@ protected:
|
||||
mState &= ~aStates;
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowRoot> AttachShadowInternal(bool aClosed,
|
||||
ErrorResult& aError);
|
||||
|
||||
private:
|
||||
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
|
||||
// set our state
|
||||
@@ -498,6 +512,16 @@ protected:
|
||||
RemoveStatesSilently(aStates);
|
||||
NotifyStateChange(aStates);
|
||||
}
|
||||
virtual void ToggleStates(EventStates aStates, bool aNotify)
|
||||
{
|
||||
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
|
||||
"Should only be removing externally-managed states here");
|
||||
mState ^= aStates;
|
||||
if (aNotify) {
|
||||
NotifyStateChange(aStates);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void UpdateEditableState(bool aNotify) override;
|
||||
|
||||
@@ -520,6 +544,7 @@ public:
|
||||
already_AddRefed<mozilla::dom::NodeInfo>
|
||||
GetExistingAttrNameFromQName(const nsAString& aStr) const;
|
||||
|
||||
MOZ_ALWAYS_INLINE // Avoid a crashy hook from Avast 10 Beta (Bug 1058131)
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
@@ -534,25 +559,57 @@ public:
|
||||
* values will not actually be compared if we aren't notifying and we don't
|
||||
* have mutation listeners (in which case it's cheap to just return false
|
||||
* and let the caller go ahead and set the value).
|
||||
* @param aOldValue Set to the old value of the attribute, but only if there
|
||||
* are event listeners. If set, the type of aOldValue will be either
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners Set to true if there are mutation event listeners
|
||||
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Notifies mutation listeners if aNotify is true, there are mutation
|
||||
* listeners, and the attribute value is changing.
|
||||
*
|
||||
* @param aNamespaceID The namespace of the attribute
|
||||
* @param aName The local name of the attribute
|
||||
* @param aPrefix The prefix of the attribute
|
||||
* @param aValue The value that the attribute is being changed to
|
||||
* @param aNotify If true, mutation listeners will be notified if they exist
|
||||
* and the attribute value is changing
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
|
||||
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Sets the class attribute to a value that contains no whitespace.
|
||||
* Assumes that we are not notifying and that the attribute hasn't been
|
||||
* set previously.
|
||||
*/
|
||||
nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify) override;
|
||||
@@ -589,7 +646,7 @@ public:
|
||||
* guaranteed (e.g. we could have class="").
|
||||
*/
|
||||
const nsAttrValue* GetClasses() const {
|
||||
if (HasFlag(NODE_MAY_HAVE_CLASS)) {
|
||||
if (MayHaveClass()) {
|
||||
return DoGetClasses();
|
||||
}
|
||||
return nullptr;
|
||||
@@ -761,6 +818,25 @@ public:
|
||||
already_AddRefed<nsIHTMLCollection>
|
||||
GetElementsByClassName(const nsAString& aClassNames);
|
||||
|
||||
CSSPseudoElementType GetPseudoElementType() const {
|
||||
if (!HasProperties()) {
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
nsresult rv = NS_OK;
|
||||
auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
|
||||
if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
|
||||
}
|
||||
|
||||
void SetPseudoElementType(CSSPseudoElementType aPseudo) {
|
||||
static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
|
||||
"Need to be able to store this in a void*");
|
||||
MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
|
||||
SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Implement the algorithm specified at
|
||||
@@ -848,8 +924,15 @@ public:
|
||||
already_AddRefed<DOMRectList> GetClientRects();
|
||||
already_AddRefed<DOMRect> GetBoundingClientRect();
|
||||
|
||||
// Shadow DOM v1
|
||||
already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
|
||||
ErrorResult& aError);
|
||||
ShadowRoot* GetShadowRootByMode() const;
|
||||
void SetSlot(const nsAString& aName, ErrorResult& aError);
|
||||
void GetSlot(nsAString& aName);
|
||||
|
||||
// [deprecated] Shadow DOM v0
|
||||
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
|
||||
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
|
||||
|
||||
ShadowRoot *FastGetShadowRoot() const
|
||||
{
|
||||
@@ -1239,7 +1322,10 @@ protected:
|
||||
* its current value) is !StoresOwnData() --- in which
|
||||
* case the current value is probably already useless.
|
||||
* If the current value is StoresOwnData() (or absent),
|
||||
* aOldValue will not be used.
|
||||
* aOldValue will not be used. aOldValue will only be set
|
||||
* in certain circumstances (there are mutation
|
||||
* listeners, element is a custom element, attribute was
|
||||
* not previously unset). Otherwise it will be null.
|
||||
* @param aParsedValue parsed new value of attribute. Replaced by the
|
||||
* old value of the attribute. This old value is only
|
||||
* useful if either it or the new value is StoresOwnData.
|
||||
@@ -1248,16 +1334,19 @@ protected:
|
||||
* @param aFireMutation should mutation-events be fired?
|
||||
* @param aNotify should we notify document-observers?
|
||||
* @param aCallAfterSetAttr should we call AfterSetAttr?
|
||||
* @param aComposedDocument The current composed document of the element.
|
||||
*/
|
||||
nsresult SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
bool aNotify,
|
||||
bool aCallAfterSetAttr);
|
||||
bool aCallAfterSetAttr,
|
||||
nsIDocument* aComposedDocument,
|
||||
const mozAutoDocUpdate& aGuard);
|
||||
|
||||
/**
|
||||
* Scroll to a new position using behavior evaluated from CSS and
|
||||
@@ -1295,14 +1384,21 @@ protected:
|
||||
*
|
||||
* @param aDocument the current document of this node (an optimization)
|
||||
* @param aName the name of the attribute
|
||||
* @param aValue the nsAttrValue to set
|
||||
* @param aValue the nsAttrValue to set. Will be swapped with the existing
|
||||
* value of the attribute if the attribute already exists.
|
||||
* @param [out] aValueWasSet If the attribute was not set previously,
|
||||
* aValue will be swapped with an empty attribute
|
||||
* and aValueWasSet will be set to false. Otherwise,
|
||||
* aValueWasSet will be set to true and aValue will
|
||||
* contain the previous value set.
|
||||
* @param [out] aRetval the nsresult status of the operation, if any.
|
||||
* @return true if the setting was attempted, false otherwise.
|
||||
*/
|
||||
virtual bool SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval);
|
||||
virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
@@ -1315,33 +1411,92 @@ protected:
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue. Alternatively, if the attr is being removed it
|
||||
* will be null. BeforeSetAttr is allowed to modify aValue by parsing
|
||||
* the string to an nsAttrValue (to avoid having to reparse it in
|
||||
* ParseAttribute).
|
||||
* will be null.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
* deal with attribute sets. This will only be called after we have called
|
||||
* SetAndTakeAttr and AttributeChanged (that is, after we have actually set
|
||||
* the attr). It will always be called under a scriptblocker.
|
||||
* SetAndSwapAttr (that is, after we have actually set the attr). It will
|
||||
* always be called under a scriptblocker.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to. If null, the attr is being
|
||||
* removed.
|
||||
* @param aOldValue the value that the attribute had previously. If null,
|
||||
* the attr was not previously set. This argument may not have the
|
||||
* correct value for SVG elements, or other cases in which the
|
||||
* attribute value doesn't store its own data
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue, bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function shall be called just before the id attribute changes. It will
|
||||
* be called after BeforeSetAttr. If the attribute being changed is not the id
|
||||
* attribute, this function does nothing. Otherwise, it will remove the old id
|
||||
* from the document's id cache.
|
||||
*
|
||||
* This must happen after BeforeSetAttr (rather than during) because the
|
||||
* the subclasses' calls to BeforeSetAttr may notify on state changes. If they
|
||||
* incorrectly determine whether the element had an id, the element may not be
|
||||
* restyled properly.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the new id value. Will be null if the id is being unset.
|
||||
*/
|
||||
void PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue);
|
||||
|
||||
/**
|
||||
* This function shall be called just after the id attribute changes. It will
|
||||
* be called before AfterSetAttr. If the attribute being changed is not the id
|
||||
* attribute, this function does nothing. Otherwise, it will add the new id to
|
||||
* the document's id cache and properly set the ElementHasID flag.
|
||||
*
|
||||
* This must happen before AfterSetAttr (rather than during) because the
|
||||
* the subclasses' calls to AfterSetAttr may notify on state changes. If they
|
||||
* incorrectly determine whether the element now has an id, the element may
|
||||
* not be restyled properly.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the new id value. Will be null if the id is being unset.
|
||||
*/
|
||||
void PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue);
|
||||
|
||||
/**
|
||||
* Usually, setting an attribute to the value that it already has results in
|
||||
* no action. However, in some cases, setting an attribute to its current
|
||||
* value should have the effect of, for example, forcing a reload of
|
||||
* network data. To address that, this function will be called in this
|
||||
* situation to allow the handling of such a case.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1400,7 +1555,7 @@ protected:
|
||||
/**
|
||||
* Handle status bar updates before they can be cancelled.
|
||||
*/
|
||||
nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
|
||||
nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* Handle default actions for link event if the event isn't consumed yet.
|
||||
@@ -1460,30 +1615,6 @@ private:
|
||||
nsCOMPtr<nsIDocument> mDoc;
|
||||
};
|
||||
|
||||
class DestinationInsertionPointList : public nsINodeList
|
||||
{
|
||||
public:
|
||||
explicit DestinationInsertionPointList(Element* aElement);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DestinationInsertionPointList)
|
||||
|
||||
// nsIDOMNodeList
|
||||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList
|
||||
virtual nsIContent* Item(uint32_t aIndex) override;
|
||||
virtual int32_t IndexOf(nsIContent* aContent) override;
|
||||
virtual nsINode* GetParentObject() override { return mParent; }
|
||||
virtual uint32_t Length() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
protected:
|
||||
virtual ~DestinationInsertionPointList();
|
||||
|
||||
RefPtr<Element> mParent;
|
||||
nsCOMArray<nsIContent> mDestinationPoints;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
|
||||
|
||||
inline bool
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_ElementInlines_h
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -25,6 +26,17 @@ Element::UnregisterActivityObserver()
|
||||
OwnerDoc()->UnregisterActivityObserver(this);
|
||||
}
|
||||
|
||||
inline Element*
|
||||
Element::GetFlattenedTreeParentElementForStyle() const
|
||||
{
|
||||
nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
|
||||
if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
|
||||
return parentNode->AsElement();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
+133
-83
@@ -123,6 +123,7 @@
|
||||
#include "mozilla/CORSMode.h"
|
||||
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
|
||||
#include "nsStyledElement.h"
|
||||
@@ -151,8 +152,56 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
|
||||
HTMLSlotElement*
|
||||
nsIContent::GetAssignedSlotByMode() const
|
||||
{
|
||||
/**
|
||||
* Get slotable's assigned slot for the result of
|
||||
* find a slot with open flag UNSET [1].
|
||||
*
|
||||
* [1] https://dom.spec.whatwg.org/#assign-a-slot
|
||||
*/
|
||||
HTMLSlotElement* slot = GetAssignedSlot();
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(GetParent());
|
||||
MOZ_ASSERT(GetParent()->GetShadowRoot());
|
||||
|
||||
/**
|
||||
* Additional check for open flag SET:
|
||||
* If slotable’s parent’s shadow root's mode is not "open",
|
||||
* then return null.
|
||||
*/
|
||||
if (GetParent()->GetShadowRoot()->IsClosed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentNodeInternal() const
|
||||
nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const
|
||||
{
|
||||
if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) {
|
||||
return assignedSlot;
|
||||
}
|
||||
|
||||
HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent());
|
||||
if (!parentSlot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this is not an unassigned node, then it must be a fallback content.
|
||||
MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty());
|
||||
|
||||
return parentSlot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
|
||||
{
|
||||
nsINode* parentNode = GetParentNode();
|
||||
if (!parentNode || !parentNode->IsContent()) {
|
||||
@@ -161,18 +210,51 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const
|
||||
}
|
||||
nsIContent* parent = parentNode->AsContent();
|
||||
|
||||
if (aType == eForStyle &&
|
||||
IsRootOfNativeAnonymousSubtree() &&
|
||||
OwnerDoc()->GetRootElement() == parent) {
|
||||
// When getting the flattened tree parent for style, we return null
|
||||
// for any "document level" native anonymous content subtree root.
|
||||
// This is NAC generated by an ancestor frame of the document element's
|
||||
// primary frame, and includes scrollbar elements created by the root
|
||||
// scroll frame, and the "custom content container" and accessible caret
|
||||
// generated by the nsCanvasFrame. We distinguish document level NAC
|
||||
// from NAC generated by the root element's primary frame below.
|
||||
nsIFrame* parentFrame = parent->GetPrimaryFrame();
|
||||
if (!parentFrame) {
|
||||
// If the root element has no primary frame, it means it can't have
|
||||
// generated any NAC itself. Thus any NAC we have here must have
|
||||
// been generated by an ancestor frame.
|
||||
//
|
||||
// If we are in here, then either the root element is display:none, or
|
||||
// we are in the middle of constructing the root of the frame tree and
|
||||
// we are trying to eagerly restyle document level NAC in
|
||||
// nsCSSFrameConstructor::GetAnonymousContent before the root
|
||||
// element's frame has been constructed.
|
||||
return nullptr;
|
||||
}
|
||||
nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
|
||||
if (!creator) {
|
||||
// If the root element does have a frame, but does not implement
|
||||
// nsIAnonymousContentCreator, then this must be document level NAC.
|
||||
return nullptr;
|
||||
}
|
||||
AutoTArray<nsIContent*, 8> elements;
|
||||
creator->AppendAnonymousContentTo(elements, 0);
|
||||
if (!elements.Contains(this)) {
|
||||
// If the root element does have a frame, and also does implement
|
||||
// nsIAnonymousContentCreator, but didn't create this node, then
|
||||
// it must be document level NAC.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
|
||||
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
|
||||
// This node is distributed to insertion points, thus we
|
||||
// need to consult the destination insertion points list to
|
||||
// figure out where this node was inserted in the flattened tree.
|
||||
// It may be the case that |parent| distributes its children
|
||||
// but the child does not match any insertion points, thus
|
||||
// the flattened tree parent is nullptr.
|
||||
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
|
||||
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
|
||||
destInsertionPoints->LastElement()->GetParent() : nullptr;
|
||||
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
return GetFlattenedTreeParentForMaybeAssignedNode();
|
||||
}
|
||||
|
||||
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
nsIContent* insertionParent = GetXBLInsertionParent();
|
||||
if (insertionParent) {
|
||||
parent = insertionParent;
|
||||
@@ -575,6 +657,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get()));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding");
|
||||
cb.NoteNativeChild(mExtendedSlots->mXBLBinding,
|
||||
NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
|
||||
@@ -618,6 +703,7 @@ FragmentOrElement::nsDOMSlots::Unlink()
|
||||
mExtendedSlots->mLabelsList = nullptr;
|
||||
mExtendedSlots->mShadowRoot = nullptr;
|
||||
mExtendedSlots->mContainingShadow = nullptr;
|
||||
mExtendedSlots->mAssignedSlot = nullptr;
|
||||
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
|
||||
mExtendedSlots->mXBLInsertionParent = nullptr;
|
||||
if (mExtendedSlots->mCustomElementData) {
|
||||
@@ -718,7 +804,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
//FIXME! Document how this event retargeting works, Bug 329124.
|
||||
aVisitor.mCanHandle = true;
|
||||
@@ -727,6 +813,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
// Don't propagate mouseover and mouseout events when mouse is moving
|
||||
// inside chrome access only content.
|
||||
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
|
||||
aVisitor.mRootOfClosedTree = isAnonForEvents;
|
||||
if ((aVisitor.mEvent->mMessage == eMouseOver ||
|
||||
aVisitor.mEvent->mMessage == eMouseOut ||
|
||||
aVisitor.mEvent->mMessage == ePointerOver ||
|
||||
@@ -738,7 +825,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
((this == aVisitor.mEvent->mOriginalTarget &&
|
||||
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
|
||||
nsCOMPtr<nsIContent> relatedTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
|
||||
if (relatedTarget &&
|
||||
relatedTarget->OwnerDoc() == OwnerDoc()) {
|
||||
|
||||
@@ -748,7 +835,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsIContent* adjustedTarget =
|
||||
Event::GetShadowRelatedTarget(this, relatedTarget);
|
||||
if (this == adjustedTarget) {
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
aVisitor.mCanHandle = false;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -805,7 +892,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
originalTarget->FindFirstNonChromeOnlyAccessContent())
|
||||
? "" : "Wrong event propagation!?!\n");
|
||||
#endif
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
// Event should not propagate to non-anon content.
|
||||
aVisitor.mCanHandle = isAnonForEvents;
|
||||
return NS_OK;
|
||||
@@ -816,58 +903,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* parent = GetParent();
|
||||
|
||||
// Web components have a special event chain that need to account
|
||||
// for destination insertion points where nodes have been distributed.
|
||||
nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
|
||||
if (destPoints && !destPoints->IsEmpty()) {
|
||||
// Push destination insertion points to aVisitor.mDestInsertionPoints
|
||||
// excluding shadow insertion points.
|
||||
bool didPushNonShadowInsertionPoint = false;
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
nsIContent* point = destPoints->ElementAt(i);
|
||||
if (!ShadowRoot::IsShadowInsertionPoint(point)) {
|
||||
aVisitor.mDestInsertionPoints.AppendElement(point);
|
||||
didPushNonShadowInsertionPoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Next node in the event path is the final destination
|
||||
// (non-shadow) insertion point that was pushed.
|
||||
if (didPushNonShadowInsertionPoint) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
|
||||
if (thisShadowRoot) {
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
// If we do stop propagation, we still want to propagate
|
||||
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
|
||||
// The load event is special in that we don't ever propagate it
|
||||
// to chrome.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
aVisitor.mParentTarget = parentTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
} else {
|
||||
// The pool host for the youngest shadow root is shadow DOM host,
|
||||
// for older shadow roots, it is the shadow insertion point
|
||||
// where the shadow root is projected, nullptr if none exists.
|
||||
parent = thisShadowRoot->GetPoolHost();
|
||||
}
|
||||
}
|
||||
// Event parent is the assigned slot, if node is assigned, or node's parent
|
||||
// otherwise.
|
||||
HTMLSlotElement* slot = GetAssignedSlot();
|
||||
nsIContent* parent = slot ? slot : GetParent();
|
||||
|
||||
// Event may need to be retargeted if this is the root of a native
|
||||
// anonymous content subtree or event is dispatched somewhere inside XBL.
|
||||
@@ -905,11 +944,17 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
|
||||
IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
|
||||
OwnerDoc()->GetWindow()) {
|
||||
aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
|
||||
aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
|
||||
} else if (parent) {
|
||||
aVisitor.mParentTarget = parent;
|
||||
aVisitor.SetParentTarget(parent, false);
|
||||
if (slot) {
|
||||
ShadowRoot* root = slot->GetContainingShadow();
|
||||
if (root && root->IsClosed()) {
|
||||
aVisitor.mParentIsSlotInClosedTree = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aVisitor.mParentTarget = GetComposedDoc();
|
||||
aVisitor.SetParentTarget(GetComposedDoc(), false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1086,23 +1131,29 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
|
||||
slots->mShadowRoot = aShadowRoot;
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>&
|
||||
FragmentOrElement::DestInsertionPoints()
|
||||
{
|
||||
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||
return slots->mDestInsertionPoints;
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>*
|
||||
FragmentOrElement::GetExistingDestInsertionPoints() const
|
||||
HTMLSlotElement*
|
||||
FragmentOrElement::GetAssignedSlot() const
|
||||
{
|
||||
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||
if (slots) {
|
||||
return &slots->mDestInsertionPoints;
|
||||
return 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)
|
||||
{
|
||||
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||
slots->mAssignedSlot = aSlot;
|
||||
}
|
||||
|
||||
void
|
||||
FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
|
||||
{
|
||||
@@ -2368,9 +2419,8 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
|
||||
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
|
||||
"on a non-Element is useless");
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
while (shadowRoot) {
|
||||
if (shadowRoot) {
|
||||
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
|
||||
shadowRoot = shadowRoot->GetOlderShadowRoot();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
// nsIWeakReference
|
||||
NS_DECL_NSIWEAKREFERENCE
|
||||
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
virtual bool IsAlive() const override { return mNode != nullptr; }
|
||||
|
||||
void NoticeNodeDestruction()
|
||||
{
|
||||
@@ -154,9 +155,9 @@ public:
|
||||
virtual void SetXBLBinding(nsXBLBinding* aBinding,
|
||||
nsBindingManager* aOldBindingManager = nullptr) override;
|
||||
virtual ShadowRoot *GetContainingShadow() const override;
|
||||
virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
|
||||
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
|
||||
virtual void SetShadowRoot(ShadowRoot* aBinding) override;
|
||||
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
|
||||
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
|
||||
virtual nsIContent *GetXBLInsertionParent() const override;
|
||||
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
@@ -294,10 +295,9 @@ public:
|
||||
RefPtr<ShadowRoot> mContainingShadow;
|
||||
|
||||
/**
|
||||
* An array of web component insertion points to which this element
|
||||
* is distributed.
|
||||
* The assigned slot associated with this element.
|
||||
*/
|
||||
nsTArray<nsIContent*> mDestInsertionPoints;
|
||||
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
|
||||
|
||||
/**
|
||||
* XBL binding installed on the element.
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef GroupedSHistory_h
|
||||
#define GroupedSHistory_h
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
||||
#include "nsIFrameLoader.h"
|
||||
#include "nsIGroupedSHistory.h"
|
||||
#include "nsIPartialSHistory.h"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* animating */
|
||||
|
||||
#include "ImageTracker.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsAppRunner.h" // for XRE_IsContentProcess
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef mozilla_dom_ImageTracker
|
||||
#define mozilla_dom_ImageTracker
|
||||
|
||||
#include "imgIRequest.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#ifndef mozilla_dom_MutableBlobStorage_h
|
||||
#define mozilla_dom_MutableBlobStorage_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "prio.h"
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "MutableBlobStreamListener.h"
|
||||
#include "MutableBlobStorage.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_Pose_h
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
+339
-476
@@ -14,9 +14,11 @@
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/StyleSheetList.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
||||
@@ -27,10 +29,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
|
||||
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
@@ -38,18 +37,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
if (tmp->mPoolHost) {
|
||||
tmp->mPoolHost->RemoveMutationObserver(tmp);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
|
||||
if (tmp->GetHost()) {
|
||||
tmp->GetHost()->RemoveMutationObserver(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
|
||||
tmp->mIdentifierMap.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||
@@ -59,14 +54,17 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
|
||||
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
|
||||
|
||||
ShadowRoot::ShadowRoot(nsIContent* aContent,
|
||||
ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding)
|
||||
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
|
||||
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
|
||||
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
|
||||
: DocumentFragment(aNodeInfo)
|
||||
, DocumentOrShadowRoot(this)
|
||||
, mProtoBinding(aProtoBinding)
|
||||
, mInsertionPointChanged(false)
|
||||
, mIsComposedDocParticipant(false)
|
||||
{
|
||||
SetHost(aContent);
|
||||
SetHost(aElement);
|
||||
mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
|
||||
|
||||
// Nodes in a shadow tree should never store a value
|
||||
// in the subtree root pointer, nodes in the shadow tree
|
||||
@@ -75,29 +73,27 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
|
||||
|
||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
ExtendedDOMSlots()->mBindingParent = aContent;
|
||||
ExtendedDOMSlots()->mBindingParent = aElement;
|
||||
ExtendedDOMSlots()->mContainingShadow = this;
|
||||
|
||||
// Add the ShadowRoot as a mutation observer on the host to watch
|
||||
// for mutations because the insertion points in this ShadowRoot
|
||||
// may need to be updated when the host children are modified.
|
||||
mPoolHost->AddMutationObserver(this);
|
||||
GetHost()->AddMutationObserver(this);
|
||||
}
|
||||
|
||||
ShadowRoot::~ShadowRoot()
|
||||
{
|
||||
if (mPoolHost) {
|
||||
// mPoolHost may have been unlinked or a new ShadowRoot may have been
|
||||
// creating, making this one obsolete.
|
||||
mPoolHost->RemoveMutationObserver(this);
|
||||
if (auto* host = GetHost()) {
|
||||
// mHost may have been unlinked or a new ShadowRoot may have been
|
||||
// created, making this one obsolete.
|
||||
host->RemoveMutationObserver(this);
|
||||
}
|
||||
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// nsINode destructor expects mSubtreeRoot == this.
|
||||
SetSubtreeRootPointer(this);
|
||||
|
||||
SetHost(nullptr);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@@ -118,13 +114,116 @@ ShadowRoot::FromNode(nsINode* aNode)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
// Note that if name attribute missing, the slot is a default slot.
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
|
||||
MOZ_ASSERT(currentSlots);
|
||||
|
||||
HTMLSlotElement* oldSlot = currentSlots->IsEmpty() ?
|
||||
nullptr : currentSlots->ElementAt(0);
|
||||
|
||||
TreeOrderComparator comparator;
|
||||
currentSlots->InsertElementSorted(aSlot, comparator);
|
||||
|
||||
HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
|
||||
if (currentSlot != aSlot) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool doEnqueueSlotChange = false;
|
||||
if (oldSlot && oldSlot != currentSlot) {
|
||||
// Move assigned nodes from old slot to new slot.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
oldSlot->RemoveAssignedNode(assignedNode);
|
||||
currentSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
// Otherwise add appropriate nodes to this slot from the host.
|
||||
for (nsIContent* child = GetHost()->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsAutoString slotName;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (child->IsSlotable() && slotName.Equals(name)) {
|
||||
currentSlot->AppendAssignedNode(child);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.Get(name);
|
||||
|
||||
if (currentSlots) {
|
||||
if (currentSlots->Length() == 1) {
|
||||
MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
|
||||
mSlotMap.Remove(name);
|
||||
|
||||
if (aSlot->AssignedNodes().Length() > 0) {
|
||||
aSlot->ClearAssignedNodes();
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
bool doEnqueueSlotChange = false;
|
||||
bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
|
||||
currentSlots->RemoveElement(aSlot);
|
||||
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
||||
|
||||
// Move assigned nodes from removed slot to the next slot in
|
||||
// tree order with the same name.
|
||||
if (doReplaceSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
aSlot->RemoveAssignedNode(assignedNode);
|
||||
replacementSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
replacementSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::StyleSheetChanged()
|
||||
{
|
||||
mProtoBinding->FlushSkinSheets();
|
||||
|
||||
nsIPresShell* shell = OwnerDoc()->GetShell();
|
||||
if (shell) {
|
||||
if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
|
||||
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
|
||||
shell->RecordShadowStyleChange(this);
|
||||
OwnerDoc()->EndUpdate(UPDATE_STYLE);
|
||||
@@ -142,16 +241,30 @@ 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 <= mProtoBinding->SheetCount(); i++) {
|
||||
if (i == mProtoBinding->SheetCount()) {
|
||||
for (size_t i = 0; i <= SheetCount(); i++) {
|
||||
if (i == SheetCount()) {
|
||||
AppendStyleSheet(*aSheet);
|
||||
mProtoBinding->AppendStyleSheet(aSheet);
|
||||
break;
|
||||
}
|
||||
|
||||
nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
|
||||
nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
|
||||
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
|
||||
InsertSheetAt(i, *aSheet);
|
||||
mProtoBinding->InsertStyleSheetAt(i, aSheet);
|
||||
break;
|
||||
}
|
||||
@@ -166,48 +279,17 @@ 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(nsDependentAtomString(aId));
|
||||
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
|
||||
if (entry) {
|
||||
entry->AddIdElement(aElement);
|
||||
}
|
||||
@@ -216,8 +298,7 @@ ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
|
||||
void
|
||||
ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
|
||||
{
|
||||
nsIdentifierMapEntry *entry =
|
||||
mIdentifierMap.GetEntry(nsDependentAtomString(aId));
|
||||
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
|
||||
if (entry) {
|
||||
entry->RemoveIdElement(aElement);
|
||||
if (entry->IsEmpty()) {
|
||||
@@ -226,244 +307,164 @@ ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsContentList>
|
||||
ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
|
||||
nsresult
|
||||
ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
return nsContentUtils::GetElementsByClassName(this, aClasses);
|
||||
}
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mRootOfClosedTree = IsClosed();
|
||||
|
||||
void
|
||||
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
|
||||
{
|
||||
TreeOrderComparator comparator;
|
||||
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
|
||||
}
|
||||
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
nsCOMPtr<nsIContent> originalTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
|
||||
if (originalTarget->GetContainingShadow() == this) {
|
||||
// If we do stop propagation, we still want to propagate
|
||||
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
|
||||
// The load event is special in that we don't ever propagate it
|
||||
// to chrome.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
void
|
||||
ShadowRoot::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);
|
||||
aVisitor.SetParentTarget(parentTarget, true);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* shadowHost = GetHost();
|
||||
aVisitor.SetParentTarget(shadowHost, false);
|
||||
|
||||
if (aVisitor.mOriginalTargetIsInAnon) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
|
||||
if (content && content->GetBindingParent() == shadowHost) {
|
||||
aVisitor.mEventTargetAtParent = shadowHost;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributeSingleNode(nsIContent* aContent)
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::AssignSlotFor(nsIContent* aContent)
|
||||
{
|
||||
// Find the insertion point to which the content belongs.
|
||||
HTMLContentElement* insertionPoint = nullptr;
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
if (mInsertionPoints[i]->Match(aContent)) {
|
||||
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
|
||||
// Node is already matched into the insertion point. We are done.
|
||||
return;
|
||||
nsAutoString slotName;
|
||||
// Note that if slot attribute is missing, assign it to the first default
|
||||
// slot, if exists.
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
// Find the appropriate position in the assigned node list for the
|
||||
// newly assigned content.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||
nsIContent* currentContent = GetHost()->GetFirstChild();
|
||||
bool indexFound = false;
|
||||
uint32_t insertionIndex;
|
||||
for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the
|
||||
// assigned content is found.
|
||||
while (currentContent && currentContent != assignedNodes[i]) {
|
||||
if (currentContent == aContent) {
|
||||
indexFound = true;
|
||||
insertionIndex = i;
|
||||
}
|
||||
|
||||
// Matching may cause the insertion point to drop fallback content.
|
||||
if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
|
||||
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
|
||||
// This match will cause the insertion point to drop all fallback
|
||||
// content and used matched nodes instead. Give up on the optimization
|
||||
// and just distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
return;
|
||||
}
|
||||
insertionPoint = mInsertionPoints[i];
|
||||
currentContent = currentContent->GetNextSibling();
|
||||
}
|
||||
|
||||
if (indexFound) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the index into the insertion point.
|
||||
if (insertionPoint) {
|
||||
nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
|
||||
// Find the appropriate position in the matched node list for the
|
||||
// newly distributed content.
|
||||
bool isIndexFound = false;
|
||||
MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
|
||||
ExplicitChildIterator childIterator(mPoolHost);
|
||||
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the inserted content
|
||||
// is found or when the current matched node is reached.
|
||||
if (childIterator.Seek(aContent, matchedNodes[i])) {
|
||||
// aContent was found before the current matched node.
|
||||
insertionPoint->InsertMatchedNode(i, aContent);
|
||||
isIndexFound = true;
|
||||
break;
|
||||
if (indexFound) {
|
||||
slot->InsertAssignedNode(insertionIndex, aContent);
|
||||
} else {
|
||||
slot->AppendAssignedNode(aContent);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::UnassignSlotFor(nsIContent* aNode, const nsAString& aSlotName)
|
||||
{
|
||||
// Find the insertion point to which the content belongs. Note that if slot
|
||||
// attribute is missing, unassign it from the first default slot, if exists.
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
if (!slot->AssignedNodes().Contains(aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slot->RemoveAssignedNode(aNode);
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::MaybeReassignElement(Element* aElement,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
nsIContent* parent = aElement->GetParent();
|
||||
if (parent && parent == GetHost()) {
|
||||
const HTMLSlotElement* oldSlot = UnassignSlotFor(aElement,
|
||||
aOldValue ? aOldValue->GetStringValue() : EmptyString());
|
||||
const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
|
||||
|
||||
if (oldSlot != newSlot) {
|
||||
if (oldSlot) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isIndexFound) {
|
||||
// We have still not found an index in the insertion point,
|
||||
// thus it must be at the end.
|
||||
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
|
||||
"Trying to match a node that is not a candidate to be matched");
|
||||
insertionPoint->AppendMatchedNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is a ShadowRoot
|
||||
// that is projected into the younger ShadowRoot's shadow insertion point.
|
||||
// The node distributed into the insertion point must be reprojected
|
||||
// to the shadow insertion point.
|
||||
if (insertionPoint->GetParent() == this &&
|
||||
mYoungerShadow && mYoungerShadow->GetShadowElement()) {
|
||||
mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The node distributed into the insertion point must be reprojected to the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
|
||||
if (parentShadow) {
|
||||
parentShadow->DistributeSingleNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is the <shadow>
|
||||
// element. The node distributed into the insertion point must be reprojected
|
||||
// into the older ShadowRoot's insertion points.
|
||||
if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
|
||||
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
|
||||
if (olderShadow) {
|
||||
olderShadow->DistributeSingleNode(aContent);
|
||||
if (newSlot) {
|
||||
newSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
|
||||
ShadowRoot::DistributionChanged()
|
||||
{
|
||||
// Find insertion point containing the content and remove the node.
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
|
||||
// Removing the matched node may cause the insertion point to use
|
||||
// fallback content.
|
||||
if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
|
||||
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
|
||||
// Removing the matched node will cause fallback content to be
|
||||
// used instead. Give up optimization and distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
return;
|
||||
}
|
||||
|
||||
mInsertionPoints[i]->RemoveMatchedNode(aContent);
|
||||
|
||||
// Handle the case where the parent of the insertion point is a ShadowRoot
|
||||
// that is projected into the younger ShadowRoot's shadow insertion point.
|
||||
// The removed node needs to be removed from the shadow insertion point.
|
||||
if (mInsertionPoints[i]->GetParent() == this) {
|
||||
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
|
||||
mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The removed node needs to be removed from the insertion points of the
|
||||
// parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
|
||||
if (parentShadow) {
|
||||
parentShadow->RemoveDistributedNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is the <shadow>
|
||||
// element. The removed node must be removed from the older ShadowRoot's
|
||||
// insertion points.
|
||||
if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
|
||||
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
|
||||
if (olderShadow) {
|
||||
olderShadow->RemoveDistributedNode(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// FIXME(emilio): We could be more granular in a bunch of cases.
|
||||
auto* host = GetHost();
|
||||
if (!host || !host->IsInComposedDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* shell = OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
shell->DestroyFramesForAndRestyle(host);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributeAllNodes()
|
||||
{
|
||||
// Create node pool.
|
||||
nsTArray<nsIContent*> nodePool;
|
||||
//XXX Handle <slot>.
|
||||
|
||||
// Make sure there is a pool host, an older shadow may not have
|
||||
// one if the younger shadow does not have a <shadow> element.
|
||||
if (mPoolHost) {
|
||||
ExplicitChildIterator childIterator(mPoolHost);
|
||||
for (nsIContent* content = childIterator.GetNextChild();
|
||||
content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
nodePool.AppendElement(content);
|
||||
}
|
||||
}
|
||||
DistributionChanged();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
Element*
|
||||
ShadowRoot::GetActiveElement()
|
||||
{
|
||||
return GetRetargetedFocusedElement();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -507,105 +508,6 @@ ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
|
||||
}
|
||||
}
|
||||
|
||||
StyleSheetList*
|
||||
ShadowRoot::StyleSheets()
|
||||
{
|
||||
if (!mStyleSheetList) {
|
||||
mStyleSheetList = new ShadowRootStyleSheetList(this);
|
||||
}
|
||||
|
||||
return mStyleSheetList;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
|
||||
{
|
||||
// If there is already a shadow element point, remove
|
||||
// the projected shadow because it is no longer an insertion
|
||||
// point.
|
||||
if (mShadowElement) {
|
||||
mShadowElement->SetProjectedShadow(nullptr);
|
||||
}
|
||||
|
||||
if (mOlderShadow) {
|
||||
// Nodes for distribution will come from the new shadow element.
|
||||
mOlderShadow->ChangePoolHost(aShadowElement);
|
||||
}
|
||||
|
||||
// Set the new shadow element to project the older ShadowRoot because
|
||||
// it is the current shadow insertion point.
|
||||
mShadowElement = aShadowElement;
|
||||
if (mShadowElement) {
|
||||
mShadowElement->SetProjectedShadow(mOlderShadow);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
|
||||
{
|
||||
if (mPoolHost) {
|
||||
mPoolHost->RemoveMutationObserver(this);
|
||||
}
|
||||
|
||||
// Clear the nodes matched to content insertion points
|
||||
// because it is no longer relevant.
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
mInsertionPoints[i]->ClearMatchedNodes();
|
||||
}
|
||||
|
||||
mPoolHost = aNewHost;
|
||||
if (mPoolHost) {
|
||||
mPoolHost->AddMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
|
||||
{
|
||||
if (!aContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
|
||||
return shadowElem && shadowElem->IsInsertionPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the web components pool population algorithm
|
||||
* on the host would contain |aContent|. This function ignores
|
||||
* insertion points in the pool, thus should only be used to
|
||||
* test nodes that have not yet been distributed.
|
||||
*/
|
||||
bool
|
||||
ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
|
||||
nsIContent* aHost)
|
||||
{
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContent) ||
|
||||
IsShadowInsertionPoint(aContent)) {
|
||||
// Insertion points never end up in the pool.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aContainer == aHost &&
|
||||
nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
|
||||
// Children of the host will end up in the pool. We check to ensure
|
||||
// that the content is in the same anonymous tree as the container
|
||||
// because anonymous content may report its container as the host
|
||||
// but it may not be in the host's child list.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aContainer) {
|
||||
// Fallback content will end up in pool if its parent is a child of the host.
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
return content && content->IsInsertionPoint() &&
|
||||
content->MatchedNodes().IsEmpty() &&
|
||||
aContainer->GetParentNode() == aHost;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
||||
Element* aElement,
|
||||
@@ -614,13 +516,26 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
|
||||
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attributes may change insertion point matching, find its new distribution.
|
||||
RemoveDistributedNode(aElement);
|
||||
DistributeSingleNode(aElement);
|
||||
if (!MaybeReassignElement(aElement, aOldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* shell = OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
//XXX optimize this!
|
||||
shell->DestroyFramesForAndRestyle(aElement);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -629,29 +544,10 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for new nodes added to the pool because the node
|
||||
// may need to be added to an insertion point.
|
||||
nsIContent* currentChild = aFirstNewContent;
|
||||
while (currentChild) {
|
||||
// Add insertion point to destination insertion points of fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
currentChild->DestInsertionPoints().AppendElement(aContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
|
||||
DistributeSingleNode(currentChild);
|
||||
}
|
||||
|
||||
currentChild = currentChild->GetNextSibling();
|
||||
for (nsIContent* content = aFirstNewContent;
|
||||
content;
|
||||
content = content->GetNextSibling()) {
|
||||
ContentInserted(aDocument, aContainer, aFirstNewContent, aNewIndexInContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,24 +557,30 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
|
||||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for new nodes added to the pool because the node
|
||||
// may need to be added to an insertion point.
|
||||
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
|
||||
// Add insertion point to destination insertion points of fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().AppendElement(aContainer);
|
||||
}
|
||||
}
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DistributeSingleNode(aChild);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,25 +591,32 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
||||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear destination insertion points for removed
|
||||
// fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().Clear();
|
||||
}
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for node that is removed from the pool because
|
||||
// it may need to be removed from an insertion point.
|
||||
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
|
||||
RemoveDistributedNode(aChild);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
nsAutoString slotName;
|
||||
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,49 +626,3 @@ ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
*aResult = nullptr;
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DestroyContent()
|
||||
{
|
||||
if (mOlderShadow) {
|
||||
mOlderShadow->DestroyContent();
|
||||
}
|
||||
DocumentFragment::DestroyContent();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
|
||||
mShadowRoot)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
|
||||
NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
|
||||
ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
|
||||
: mShadowRoot(aShadowRoot)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ShadowRootStyleSheetList::Length()
|
||||
{
|
||||
return mShadowRoot->mProtoBinding->SheetCount();
|
||||
}
|
||||
|
||||
+70
-115
@@ -8,30 +8,30 @@
|
||||
#define mozilla_dom_shadowroot_h__
|
||||
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/StyleSheetList.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/dom/DocumentOrShadowRoot.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsIdentifierMapEntry.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsXBLBinding.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,46 +42,30 @@ public:
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
ShadowRoot(nsIContent* aContent, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
ShadowRoot(Element* aElement, bool aClosed,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding);
|
||||
|
||||
void AddToIdTable(Element* aElement, nsIAtom* aId);
|
||||
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
|
||||
// Shadow DOM v1
|
||||
Element* Host();
|
||||
ShadowRootMode Mode() const
|
||||
{
|
||||
return mMode;
|
||||
}
|
||||
bool IsClosed() const
|
||||
{
|
||||
return mMode == ShadowRootMode::Closed;
|
||||
}
|
||||
|
||||
// [deprecated] Shadow DOM v0
|
||||
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
|
||||
void RemoveSheet(StyleSheet* aSheet);
|
||||
bool ApplyAuthorStyles();
|
||||
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
|
||||
StyleSheetList* StyleSheets();
|
||||
HTMLShadowElement* GetShadowElement() { return mShadowElement; }
|
||||
|
||||
/**
|
||||
* Sets the current shadow insertion point where the older
|
||||
* ShadowRoot will be projected.
|
||||
*/
|
||||
void SetShadowElement(HTMLShadowElement* aShadowElement);
|
||||
|
||||
/**
|
||||
* Change the node that populates the distribution pool with
|
||||
* its children. This is distinct from the ShadowRoot host described
|
||||
* in the specifications. The ShadowRoot host is the element
|
||||
* which created this ShadowRoot and does not change. The pool host
|
||||
* is the same as the ShadowRoot host if this is the youngest
|
||||
* ShadowRoot. If this is an older ShadowRoot, the pool host is
|
||||
* the <shadow> element in the younger ShadowRoot (if it exists).
|
||||
*/
|
||||
void ChangePoolHost(nsIContent* aNewHost);
|
||||
|
||||
/**
|
||||
* Distributes a single explicit child of the pool host to the content
|
||||
* insertion points in this ShadowRoot.
|
||||
*/
|
||||
void DistributeSingleNode(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Removes a single explicit child of the pool host from the content
|
||||
* insertion points in this ShadowRoot.
|
||||
*/
|
||||
void RemoveDistributedNode(nsIContent* aContent);
|
||||
StyleSheetList* StyleSheets()
|
||||
{
|
||||
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Distributes all the explicit children of the pool host to the content
|
||||
@@ -89,43 +73,57 @@ public:
|
||||
*/
|
||||
void DistributeAllNodes();
|
||||
|
||||
void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
|
||||
void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
|
||||
private:
|
||||
/**
|
||||
* Try to reassign an element to a slot and returns whether the assignment
|
||||
* changed.
|
||||
*/
|
||||
bool MaybeReassignElement(Element* aElement, const nsAttrValue* aOldValue);
|
||||
|
||||
/**
|
||||
* Try to assign aContent to a slot in the shadow tree, returns the assigned
|
||||
* slot if found.
|
||||
*/
|
||||
const HTMLSlotElement* AssignSlotFor(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Unassign aContent from the assigned slot in the shadow tree, returns the
|
||||
* assigned slot if found.
|
||||
*
|
||||
* Note: slot attribute of aContent may have changed already, so pass slot
|
||||
* name explicity here.
|
||||
*/
|
||||
const HTMLSlotElement* UnassignSlotFor(nsIContent* aContent,
|
||||
const nsAString& aSlotName);
|
||||
|
||||
/**
|
||||
* Called when we redistribute content after insertion points have changed.
|
||||
*/
|
||||
void DistributionChanged();
|
||||
|
||||
bool IsPooledNode(nsIContent* aChild) const;
|
||||
|
||||
public:
|
||||
void AddSlot(HTMLSlotElement* aSlot);
|
||||
void RemoveSlot(HTMLSlotElement* aSlot);
|
||||
|
||||
void SetYoungerShadow(ShadowRoot* aYoungerShadow);
|
||||
ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
|
||||
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
|
||||
|
||||
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
|
||||
|
||||
nsISupports* GetParentObject() const { return mPoolHost; }
|
||||
|
||||
nsIContent* GetPoolHost() { return mPoolHost; }
|
||||
nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
|
||||
nsIContent* aHost);
|
||||
static ShadowRoot* FromNode(nsINode* aNode);
|
||||
static bool IsShadowInsertionPoint(nsIContent* aContent);
|
||||
|
||||
static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
|
||||
nsTArray<nsIContent*>& aDestInsertionPoints);
|
||||
void AddToIdTable(Element* aElement, nsIAtom* aId);
|
||||
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
|
||||
|
||||
// WebIDL methods.
|
||||
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);
|
||||
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
|
||||
|
||||
Element* GetActiveElement();
|
||||
void GetInnerHTML(nsAString& aInnerHTML);
|
||||
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
|
||||
Element* Host();
|
||||
ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
|
||||
void StyleSheetChanged();
|
||||
|
||||
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
|
||||
@@ -134,26 +132,18 @@ public:
|
||||
mIsComposedDocParticipant = aIsComposedDocParticipant;
|
||||
}
|
||||
|
||||
virtual void DestroyContent() override;
|
||||
nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
protected:
|
||||
virtual ~ShadowRoot();
|
||||
|
||||
// The pool host is the parent of the nodes that will be distributed
|
||||
// into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
|
||||
nsCOMPtr<nsIContent> mPoolHost;
|
||||
ShadowRootMode mMode;
|
||||
|
||||
// An array of content insertion points that are a descendant of the ShadowRoot
|
||||
// sorted in tree order. Insertion points are responsible for notifying
|
||||
// the ShadowRoot when they are removed or added as a descendant. The insertion
|
||||
// points are kept alive by the parent node, thus weak references are held
|
||||
// by the array.
|
||||
nsTArray<HTMLContentElement*> mInsertionPoints;
|
||||
// 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 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
|
||||
@@ -161,19 +151,6 @@ protected:
|
||||
// owns |mProtoBinding|.
|
||||
RefPtr<nsXBLBinding> mAssociatedBinding;
|
||||
|
||||
RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
|
||||
|
||||
// The current shadow insertion point of this ShadowRoot.
|
||||
HTMLShadowElement* mShadowElement;
|
||||
|
||||
// The ShadowRoot that was created by the host element before
|
||||
// this ShadowRoot was created.
|
||||
RefPtr<ShadowRoot> mOlderShadow;
|
||||
|
||||
// The ShadowRoot that was created by the host element after
|
||||
// this ShadowRoot was created.
|
||||
RefPtr<ShadowRoot> mYoungerShadow;
|
||||
|
||||
// A boolean that indicates that an insertion point was added or removed
|
||||
// from this ShadowRoot and that the nodes need to be redistributed into
|
||||
// the insertion points. After this flag is set, nodes will be distributed
|
||||
@@ -189,28 +166,6 @@ protected:
|
||||
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
};
|
||||
|
||||
class ShadowRootStyleSheetList : public StyleSheetList
|
||||
{
|
||||
public:
|
||||
explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
|
||||
virtual nsINode* GetParentObject() const override
|
||||
{
|
||||
return mShadowRoot;
|
||||
}
|
||||
|
||||
uint32_t Length() override;
|
||||
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
|
||||
|
||||
protected:
|
||||
virtual ~ShadowRootStyleSheetList();
|
||||
|
||||
RefPtr<ShadowRoot> mShadowRoot;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/CSSStyleSheet.h"
|
||||
#include "mozilla/dom/StyleSheetListBinding.h"
|
||||
#include "nsStubDocumentObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -17,7 +18,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
|
||||
@@ -43,5 +45,24 @@ StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
|
||||
{
|
||||
mDocumentOrShadowRoot = nullptr;
|
||||
}
|
||||
|
||||
StyleSheetList::StyleSheetList(DocumentOrShadowRoot& aScope)
|
||||
: mDocumentOrShadowRoot(&aScope)
|
||||
{
|
||||
mDocumentOrShadowRoot->AsNode().AddMutationObserver(this);
|
||||
}
|
||||
|
||||
StyleSheetList::~StyleSheetList()
|
||||
{
|
||||
if (mDocumentOrShadowRoot) {
|
||||
mDocumentOrShadowRoot->AsNode().RemoveMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -7,8 +7,10 @@
|
||||
#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;
|
||||
|
||||
@@ -17,28 +19,54 @@ class StyleSheet;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class StyleSheetList : public nsIDOMStyleSheetList
|
||||
, public nsWrapperCache
|
||||
class StyleSheetList final : public nsIDOMStyleSheetList
|
||||
, public nsWrapperCache
|
||||
, public nsStubDocumentObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
|
||||
|
||||
NS_DECL_NSIDOMSTYLESHEETLIST
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
|
||||
|
||||
explicit StyleSheetList(DocumentOrShadowRoot& aScope);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
|
||||
|
||||
virtual nsINode* GetParentObject() const = 0;
|
||||
nsINode* GetParentObject() const
|
||||
{
|
||||
return mDocumentOrShadowRoot ? &mDocumentOrShadowRoot->AsNode() : nullptr;
|
||||
}
|
||||
|
||||
virtual uint32_t Length() = 0;
|
||||
virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
|
||||
StyleSheet* Item(uint32_t aIndex)
|
||||
uint32_t Length() const
|
||||
{
|
||||
return 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
|
||||
{
|
||||
bool dummy = false;
|
||||
return IndexedGetter(aIndex, dummy);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~StyleSheetList() {}
|
||||
virtual ~StyleSheetList();
|
||||
|
||||
DocumentOrShadowRoot* mDocumentOrShadowRoot; // Weak, cleared on "NodeWillBeDestroyed".
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
#ifndef TabGroup_h
|
||||
#define TabGroup_h
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TimeoutHandler.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
#ifndef mozilla_dom_timeout_handler_h
|
||||
#define mozilla_dom_timeout_handler_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsITimeoutHandler.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef TimerClamping_h___
|
||||
#define TimerClamping_h___
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TimerClamping
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<!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>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
try { o1 = document.createElement('textarea') } catch(e) { }
|
||||
try { o2 = document.createElement('div') } catch(e) { }
|
||||
try { o3 = document.createElement('map') } catch(e) { }
|
||||
try { document.documentElement.appendChild(o2) } catch(e) { }
|
||||
try { o2.appendChild(o1) } catch(e) { }
|
||||
try { document.documentElement.getClientRects() } catch(e) { }
|
||||
try { o4 = o2.attachShadow({ mode: "open" }); } catch(e) { }
|
||||
try { o1.appendChild(o3) } catch(e) { }
|
||||
try { o5 = o3.parentElement } catch(e) { }
|
||||
try { o3.outerHTML = "\n" } catch(e) { }
|
||||
try { o4.prepend("", o5, "") } catch(e) { }
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
|
||||
<slot><div></div></slot>
|
||||
</html>
|
||||
@@ -1,24 +0,0 @@
|
||||
<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>
|
||||
@@ -1,28 +0,0 @@
|
||||
<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>
|
||||
@@ -193,7 +193,7 @@ load 930250.html
|
||||
load 942979.html
|
||||
load 973401.html
|
||||
load 978646.html
|
||||
pref(dom.webcomponents.enabled,true) load 1024428-1.html
|
||||
pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1340009
|
||||
load 1026714.html
|
||||
pref(dom.webcomponents.enabled,true) load 1027461-1.html
|
||||
pref(dom.webcomponents.enabled,true) load 1029710.html
|
||||
@@ -209,4 +209,6 @@ load 1230422.html
|
||||
load 1251361.html
|
||||
load 1304437.html
|
||||
pref(clipboard.autocopy,true) load 1385272-1.html
|
||||
pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
|
||||
pref(dom.webcomponents.enabled,true) load 1341693.html
|
||||
pref(dom.webcomponents.enabled,true) load 1419799.html
|
||||
pref(dom.webcomponents.enabled,false) load 1422931.html
|
||||
+5
-2
@@ -86,6 +86,7 @@ EXPORTS += [
|
||||
'nsIContentInlines.h',
|
||||
'nsIContentIterator.h',
|
||||
'nsIContentSerializer.h',
|
||||
'nsIdentifierMapEntry.h',
|
||||
'nsIDocument.h',
|
||||
'nsIDocumentInlines.h',
|
||||
'nsIDocumentObserver.h',
|
||||
@@ -163,6 +164,7 @@ EXPORTS.mozilla.dom += [
|
||||
'DirectionalityUtils.h',
|
||||
'DocGroup.h',
|
||||
'DocumentFragment.h',
|
||||
'DocumentOrShadowRoot.h',
|
||||
'DocumentType.h',
|
||||
'DOMCursor.h',
|
||||
'DOMError.h',
|
||||
@@ -225,7 +227,7 @@ EXPORTS.mozilla.dom += [
|
||||
'WindowOrientationObserver.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'AnonymousContent.cpp',
|
||||
'Attr.cpp',
|
||||
'BarProps.cpp',
|
||||
@@ -241,6 +243,7 @@ UNIFIED_SOURCES += [
|
||||
'DirectionalityUtils.cpp',
|
||||
'DocGroup.cpp',
|
||||
'DocumentFragment.cpp',
|
||||
'DocumentOrShadowRoot.cpp',
|
||||
'DocumentType.cpp',
|
||||
'DOMCursor.cpp',
|
||||
'DOMError.cpp',
|
||||
@@ -376,7 +379,7 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'nsDOMDataChannel.cpp',
|
||||
]
|
||||
|
||||
|
||||
@@ -382,12 +382,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue)
|
||||
{
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@@ -407,21 +410,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
|
||||
nsAttrValue& aValue, bool* aHadValue)
|
||||
{
|
||||
int32_t namespaceID = aName->NamespaceID();
|
||||
nsIAtom* localName = aName->NameAtom();
|
||||
if (namespaceID == kNameSpaceID_None) {
|
||||
return SetAndSwapAttr(localName, aValue);
|
||||
return SetAndSwapAttr(localName, aValue, aHadValue);
|
||||
}
|
||||
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
|
||||
ATTRS(mImpl)[i].mName.SetTo(aName);
|
||||
ATTRS(mImpl)[i].mValue.Reset();
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@@ -576,10 +580,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet)
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue)
|
||||
{
|
||||
bool willAdd = true;
|
||||
if (mImpl && mImpl->mMappedAttrs) {
|
||||
@@ -589,7 +594,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
||||
RefPtr<nsMappedAttributes> mapped =
|
||||
GetModifiableMapped(aContent, aSheet, willAdd);
|
||||
|
||||
mapped->SetAndTakeAttr(aLocalName, aValue);
|
||||
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
|
||||
|
||||
return MakeMappedUnique(mapped);
|
||||
}
|
||||
@@ -714,10 +719,19 @@ nsAttrAndChildArray::MappedAttrCount() const
|
||||
return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
|
||||
{
|
||||
nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
|
||||
RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
|
||||
return MakeMappedUnique(mapped);
|
||||
}
|
||||
|
||||
nsMappedAttributes*
|
||||
nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool aWillAddAttr)
|
||||
bool aWillAddAttr,
|
||||
int32_t aAttrCount)
|
||||
{
|
||||
if (mImpl && mImpl->mMappedAttrs) {
|
||||
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
|
||||
@@ -727,7 +741,7 @@ nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
|
||||
|
||||
nsMapRuleToAttributesFunc mapRuleFunc =
|
||||
aContent->GetAttributeMappingFunction();
|
||||
return new nsMappedAttributes(aSheet, mapRuleFunc);
|
||||
return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
||||
@@ -91,8 +91,13 @@ public:
|
||||
nsCaseTreatment aCaseSensitive) const;
|
||||
const nsAttrValue* AttrAt(uint32_t aPos) const;
|
||||
// SetAndSwapAttr swaps the current attribute value with aValue.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
|
||||
// Remove the attr at position aPos. The value of the attr is placed in
|
||||
// aValue; any value that was already in aValue is destroyed.
|
||||
@@ -110,9 +115,14 @@ public:
|
||||
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
|
||||
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
|
||||
|
||||
nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
// SetAndSwapMappedAttr swaps the current attribute value with aValue.
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet);
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue);
|
||||
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
|
||||
if (!mImpl || !mImpl->mMappedAttrs) {
|
||||
return NS_OK;
|
||||
@@ -135,6 +145,9 @@ public:
|
||||
return MappedAttrCount();
|
||||
}
|
||||
|
||||
// Force this to have mapped attributes, even if those attributes are empty.
|
||||
nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
|
||||
|
||||
private:
|
||||
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
|
||||
nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
|
||||
@@ -148,7 +161,8 @@ private:
|
||||
nsMappedAttributes*
|
||||
GetModifiableMapped(nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool aWillAddAttr);
|
||||
bool aWillAddAttr,
|
||||
int32_t aAttrCount = 1);
|
||||
nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
|
||||
|
||||
uint32_t AttrSlotsSize() const
|
||||
|
||||
@@ -49,20 +49,13 @@ public:
|
||||
, mCheapString(nullptr)
|
||||
{ }
|
||||
|
||||
void TakeParsedValue(nsAttrValue& aValue)
|
||||
void ResetToAttrValue(const nsAttrValue& aValue)
|
||||
{
|
||||
mStoredAttrValue.SwapValueWith(aValue);
|
||||
mAttrValue = &mStoredAttrValue;
|
||||
mAttrValue = &aValue;
|
||||
mStringPtr = nullptr;
|
||||
// No need to touch mCheapString here. If we need to use it, we will reset
|
||||
// it to the rigthe value anyway.
|
||||
}
|
||||
/**
|
||||
* If TakeParsedValue has been called, returns the value that it set.
|
||||
*/
|
||||
nsAttrValue* GetStoredAttrValue()
|
||||
{
|
||||
return mAttrValue == &mStoredAttrValue ? &mStoredAttrValue : nullptr;
|
||||
}
|
||||
const nsAttrValue* GetAttrValue() { return mAttrValue; }
|
||||
|
||||
/**
|
||||
* Returns a reference to the string value of the contents of this object.
|
||||
@@ -85,11 +78,24 @@ public:
|
||||
return aOther.EqualsAsStrings(*mAttrValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the value stored is empty
|
||||
*/
|
||||
bool IsEmpty() const
|
||||
{
|
||||
if (mStringPtr) {
|
||||
return mStringPtr->IsEmpty();
|
||||
}
|
||||
if (mAttrValue) {
|
||||
return mAttrValue->IsEmptyString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const nsAttrValue* mAttrValue;
|
||||
mutable const nsAString* mStringPtr;
|
||||
mutable nsCheapString mCheapString;
|
||||
nsAttrValue mStoredAttrValue;
|
||||
};
|
||||
|
||||
#endif // nsAttrValueOrString_h___
|
||||
Loaded 100 of 3037 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user