layout update for the further update

This commit is contained in:
Fedor 2024-01-07 10:34:56 +02:00
parent af8ad28b05
commit b179cc258f
7557 changed files with 69788 additions and 39420 deletions

View File

@ -168,7 +168,9 @@ void SelectionManager::ProcessSelectionChanged(SelData* aSelData) {
const nsRange* range = selection->GetAnchorFocusRange();
nsINode* cntrNode = nullptr;
if (range) cntrNode = range->GetCommonAncestor();
if (range) {
cntrNode = range->GetClosestCommonInclusiveAncestor();
}
if (!cntrNode) {
cntrNode = selection->GetFrameSelection()->GetAncestorLimiter();

View File

@ -35,7 +35,7 @@ void StyleInfo::TextIndent(nsAString& aValue) {
const auto& textIndent = mComputedStyle->StyleText()->mTextIndent;
if (textIndent.ConvertsToLength()) {
aValue.AppendFloat(textIndent.LengthInCSSPixels());
aValue.AppendFloat(textIndent.ToLengthInCSSPixels());
aValue.AppendLiteral("px");
return;
}
@ -44,7 +44,8 @@ void StyleInfo::TextIndent(nsAString& aValue) {
aValue.AppendLiteral("%");
return;
}
// FIXME: This doesn't handle calc in any meaningful way?
// FIXME: This doesn't handle calc in any meaningful way? Probably should just
// use the Servo serialization code...
aValue.AppendLiteral("0px");
}

View File

@ -623,7 +623,7 @@ bool nsAccessiblePivot::IsDescendantOf(Accessible* aAccessible,
bool nsAccessiblePivot::MovePivotInternal(Accessible* aPosition,
PivotMoveReason aReason,
bool aIsFromUserInput) {
RefPtr<Accessible> oldPosition = mPosition.forget();
RefPtr<Accessible> oldPosition = std::move(mPosition);
mPosition = aPosition;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
mStartOffset = mEndOffset = -1;

View File

@ -17,6 +17,7 @@
#include "nsCaret.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsFocusManager.h"
#include "nsIEditingSession.h"
#include "nsContainerFrame.h"
@ -28,6 +29,7 @@
#include "nsIMathMLFrame.h"
#include "nsRange.h"
#include "nsTextFragment.h"
#include "mozilla/Assertions.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/EventStates.h"
#include "mozilla/MathAlgorithms.h"
@ -1510,9 +1512,15 @@ bool HyperTextAccessible::SelectionBoundsAt(int32_t aSelectionNum,
// Make sure start is before end, by swapping DOM points. This occurs when
// the user selects backwards in the text.
int32_t rangeCompare =
const Maybe<int32_t> order =
nsContentUtils::ComparePoints(endNode, endOffset, startNode, startOffset);
if (rangeCompare < 0) {
if (!order) {
MOZ_ASSERT_UNREACHABLE();
return false;
}
if (*order < 0) {
nsINode* tempNode = startNode;
startNode = endNode;
endNode = tempNode;
@ -2002,9 +2010,15 @@ void HyperTextAccessible::GetSpellTextAttr(
// case there is another range after this one.
nsINode* endNode = range->GetEndContainer();
int32_t endNodeOffset = range->EndOffset();
if (nsContentUtils::ComparePoints(aNode, aNodeOffset, endNode,
endNodeOffset) >= 0)
Maybe<int32_t> order = nsContentUtils::ComparePoints(
aNode, aNodeOffset, endNode, endNodeOffset);
if (NS_WARN_IF(!order)) {
continue;
}
if (*order >= 0) {
continue;
}
// At this point our point is either in this range or before it but after
// the previous range. So we check to see if the range starts before the
@ -2012,8 +2026,17 @@ void HyperTextAccessible::GetSpellTextAttr(
// must be before the range and after the previous one if any.
nsINode* startNode = range->GetStartContainer();
int32_t startNodeOffset = range->StartOffset();
if (nsContentUtils::ComparePoints(startNode, startNodeOffset, aNode,
aNodeOffset) <= 0) {
order = nsContentUtils::ComparePoints(startNode, startNodeOffset, aNode,
aNodeOffset);
if (!order) {
// As (`aNode`, `aNodeOffset`) is comparable to the end of the range, it
// should also be comparable to the range's start. Returning here
// prevents crashes in release builds.
MOZ_ASSERT_UNREACHABLE();
return;
}
if (*order <= 0) {
startOffset = DOMPointToOffset(startNode, startNodeOffset);
endOffset = DOMPointToOffset(endNode, endNodeOffset);

View File

@ -65,9 +65,7 @@ bool TableAccessible::IsProbablyLayoutTable() {
}
// Check for legitimate data table attributes.
nsAutoString summary;
if (el->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
!summary.IsEmpty()) {
if (el->Element::HasNonEmptyAttr(nsGkAtoms::summary)) {
RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
}

View File

@ -638,8 +638,6 @@ class NetErrorChild extends ActorChild {
clockErrTitle.textContent;
let desc = doc.getElementById("errorShortDescText");
doc.getElementById("errorShortDesc").style.display = "block";
doc.getElementById("certificateErrorReporting").style.display =
"none";
if (desc) {
// eslint-disable-next-line no-unsanitized/property
desc.innerHTML = clockErrDesc.innerHTML;

View File

@ -372,6 +372,12 @@ pref("permissions.postPrompt.animate", true);
pref("permissions.eventTelemetry.enabled", false);
#endif
#ifdef NIGHTLY_BUILD
pref("permissions.delegation.enable", true);
#else
pref("permissions.delegation.enable", false);
#endif
// handle links targeting new windows
// 1=current window/tab, 2=new window, 3=new tab in most recent window
pref("browser.link.open_newwindow", 3);

View File

@ -60,11 +60,6 @@ function toggleDisplay(node) {
return (node.style.display = toggle[node.style.display]);
}
function showCertificateErrorReporting() {
// Display error reporting UI
document.getElementById("certificateErrorReporting").style.display = "block";
}
function showPrefChangeContainer() {
const panel = document.getElementById("prefChangeContainer");
panel.style.display = "block";
@ -270,23 +265,6 @@ function initPage() {
let shortDesc = document.getElementById("errorShortDescText")
.textContent;
document.getElementById("learnMoreContainer").style.display = "block";
var options = JSON.parse(evt.detail);
if (options && options.enabled) {
var checkbox = document.getElementById("automaticallyReportInFuture");
showCertificateErrorReporting();
if (options.automatic) {
// set the checkbox
checkbox.checked = true;
}
checkbox.addEventListener("change", function(changeEvt) {
var event = new CustomEvent("AboutNetErrorSetAutomatic", {
bubbles: true,
detail: changeEvt.target.checked,
});
document.dispatchEvent(event);
});
}
const hasPrefStyleError = [
"interrupted", // This happens with subresources that are above the max tls
"SSL_ERROR_PROTOCOL_VERSION_ALERT",
@ -379,28 +357,10 @@ function initPageCertError() {
document.getElementById("learnMoreContainer").style.display = "block";
let checkbox = document.getElementById("automaticallyReportInFuture");
checkbox.addEventListener("change", function({ target: { checked } }) {
document.dispatchEvent(
new CustomEvent("AboutNetErrorSetAutomatic", {
detail: checked,
bubbles: true,
})
);
});
addEventListener(
"AboutNetErrorOptions",
function(event) {
var options = JSON.parse(event.detail);
if (options && options.enabled) {
// Display error reporting UI
document.getElementById("certificateErrorReporting").style.display =
"block";
// set the checkbox
checkbox.checked = !!options.automatic;
}
if (options && options.hideAddExceptionButton) {
document.querySelector(".exceptionDialogButtonContainer").hidden = true;
}

View File

@ -210,13 +210,6 @@
</div>
</div>
<div id="certificateErrorReporting">
<p class="toggle-container-with-text">
<input type="checkbox" id="automaticallyReportInFuture" role="checkbox" data-telemetry-id="auto_report_cb"/>
<label for="automaticallyReportInFuture">&errorReporting.automatic2;</label>
</p>
</div>
<div id="certificateErrorDebugInformation">
<button id="copyToClipboard" data-telemetry-id="clipboard_button_top">&certerror.copyToClipboard.label;</button>
<div id="certificateErrorText"/>

View File

@ -49,7 +49,6 @@ add_task(async function checkTelemetryClickEvents() {
let recordedObjects = [
"advanced_button",
"learn_more_link",
"auto_report_cb",
"error_code_link",
"clipboard_button_top",
"clipboard_button_bot",

View File

@ -29,14 +29,10 @@ async function testBody(testRoot) {
// Now add a stylesheet on the fly and make sure we see it.
let doc = content.document;
doc.styleSheetChangeEventsEnabled = true;
doc.addEventListener("StyleSheetAdded", unexpectedContentEvent);
doc.addEventListener("StyleSheetRemoved", unexpectedContentEvent);
doc.addEventListener(
"StyleSheetApplicableStateChanged",
unexpectedContentEvent
);
doc.defaultView.addEventListener("StyleSheetAdded", unexpectedContentEvent);
doc.defaultView.addEventListener("StyleSheetRemoved", unexpectedContentEvent);
doc.defaultView.addEventListener(
"StyleSheetApplicableStateChanged",
unexpectedContentEvent
@ -47,7 +43,6 @@ async function testBody(testRoot) {
link.setAttribute("type", "text/css");
link.setAttribute("href", testRoot + gStyleSheet);
let sheetAdded = ContentTaskUtils.waitForEvent(this, "StyleSheetAdded", true);
let stateChanged = ContentTaskUtils.waitForEvent(
this,
"StyleSheetApplicableStateChanged",
@ -55,18 +50,8 @@ async function testBody(testRoot) {
);
doc.body.appendChild(link);
let evt = await sheetAdded;
info("received dynamic style sheet event");
is(evt.type, "StyleSheetAdded", "evt.type has expected value");
is(evt.target, doc, "event targets correct document");
ok(evt.stylesheet, "evt.stylesheet is defined");
ok(
evt.stylesheet.toString().includes("CSSStyleSheet"),
"evt.stylesheet is a stylesheet"
);
ok(evt.documentSheet, "style sheet is a document sheet");
evt = await stateChanged;
info("waiting for applicable state change event");
let evt = await stateChanged;
info("received dynamic style sheet applicable state change event");
is(
evt.type,
@ -97,84 +82,5 @@ async function testBody(testRoot) {
is(evt.stylesheet, link.sheet, "evt.stylesheet has the right value");
is(evt.applicable, false, "evt.applicable has the right value");
let sheetRemoved = ContentTaskUtils.waitForEvent(
this,
"StyleSheetRemoved",
true
);
doc.body.removeChild(link);
evt = await sheetRemoved;
info("received dynamic style sheet removal");
is(evt.type, "StyleSheetRemoved", "evt.type has expected value");
is(evt.target, doc, "event targets correct document");
ok(evt.stylesheet, "evt.stylesheet is defined");
ok(
evt.stylesheet.toString().includes("CSSStyleSheet"),
"evt.stylesheet is a stylesheet"
);
ok(
evt.stylesheet.href.includes(gStyleSheet),
"evt.stylesheet is the removed stylesheet"
);
let ruleAdded = ContentTaskUtils.waitForEvent(this, "StyleRuleAdded", true);
doc.querySelector("style").sheet.insertRule("*{color:black}", 0);
evt = await ruleAdded;
info("received style rule added event");
is(evt.type, "StyleRuleAdded", "evt.type has expected value");
is(evt.target, doc, "event targets correct document");
ok(evt.stylesheet, "evt.stylesheet is defined");
ok(
evt.stylesheet.toString().includes("CSSStyleSheet"),
"evt.stylesheet is a stylesheet"
);
ok(evt.rule, "evt.rule is defined");
is(
evt.rule.cssText,
"* { color: black; }",
"evt.rule.cssText has expected value"
);
let ruleChanged = ContentTaskUtils.waitForEvent(
this,
"StyleRuleChanged",
true
);
evt.rule.style.cssText = "color:green";
evt = await ruleChanged;
ok(true, "received style rule changed event");
is(evt.type, "StyleRuleChanged", "evt.type has expected value");
is(evt.target, doc, "event targets correct document");
ok(evt.stylesheet, "evt.stylesheet is defined");
ok(
evt.stylesheet.toString().includes("CSSStyleSheet"),
"evt.stylesheet is a stylesheet"
);
ok(evt.rule, "evt.rule is defined");
is(
evt.rule.cssText,
"* { color: green; }",
"evt.rule.cssText has expected value"
);
let ruleRemoved = ContentTaskUtils.waitForEvent(
this,
"StyleRuleRemoved",
true
);
evt.stylesheet.deleteRule(0);
evt = await ruleRemoved;
info("received style rule removed event");
is(evt.type, "StyleRuleRemoved", "evt.type has expected value");
is(evt.target, doc, "event targets correct document");
ok(evt.stylesheet, "evt.stylesheet is defined");
ok(
evt.stylesheet.toString().includes("CSSStyleSheet"),
"evt.stylesheet is a stylesheet"
);
ok(evt.rule, "evt.rule is defined");
}

View File

@ -114,22 +114,6 @@ if (
});
}
if (!Services.prefs.getBoolPref("full-screen-api.unprefix.enabled")) {
whitelist.push(
{
sourceName: /(?:res|gre-resources)\/(ua|html)\.css$/i,
errorMessage: /Unknown pseudo-class .*\bfullscreen\b/i,
isFromDevTools: false,
},
{
// PDFjs is futureproofing its pseudoselectors, and those rules are dropped.
sourceName: /web\/viewer\.css$/i,
errorMessage: /Unknown pseudo-class .*\bfullscreen\b/i,
isFromDevTools: false,
}
);
}
if (!Services.prefs.getBoolPref("layout.css.scrollbar-width.enabled")) {
whitelist.push({
sourceName: /(?:res|gre-resources)\/forms\.css$/i,

View File

@ -104,11 +104,6 @@ body:not(.neterror) #advancedButton {
display: block;
}
#certificateErrorReporting {
display: none;
padding-bottom: 10px;
}
#advancedPanelContainer {
width: 100%;
left: 0;
@ -139,13 +134,6 @@ body:not(.neterror) #advancedButton {
font-weight: bold;
}
#automaticallyReportInFuture {
cursor: pointer;
/* Prevent the checkbox from looking super
* squeezed on small viewports */
flex-shrink: 0;
}
#errorCode:not([href]) {
color: var(--in-content-page-color);
cursor: text;
@ -166,10 +154,6 @@ body:not(.neterror) #advancedButton {
white-space: pre-wrap;
}
#certificateErrorReporting {
display: none;
}
#certificateErrorDebugInformation {
display: none;
background-color: var(--in-content-box-background-hover) !important;

View File

@ -82,11 +82,7 @@ AC_DEFUN([MOZ_COMPILER_OPTS],
MOZ_DEBUGGING_OPTS
MOZ_RTTI
if test "$CLANG_CXX"; then
## We disable return-type-c-linkage because jsval is defined as a C++ type but is
## returned by C functions. This is possible because we use knowledge about the ABI
## to typedef it to a C type with the same layout when the headers are included
## from C.
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option"
fi
if test "$GNU_CC"; then

View File

@ -13,7 +13,7 @@ option(env='CBINDGEN', nargs=1, when=cbindgen_is_needed,
def check_cbindgen_version(cbindgen, fatal=False):
log.debug("trying cbindgen: %s" % cbindgen)
cbindgen_min_version = Version('0.11.1')
cbindgen_min_version = Version('0.12.0')
# cbindgen x.y.z
version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1])

View File

@ -6462,7 +6462,6 @@ NS_CycleCollectorSuspectUsingNursery
?AddRef@nsXBLWindowKeyHandler@@UAGKXZ
?InstallKeyboardEventListenersTo@nsXBLWindowKeyHandler@@QAEXPAVEventListenerManager@mozilla@@@Z
?AddEventListenerByType@EventListenerManager@mozilla@@QAEXPAVnsIDOMEventListener@@ABV?$nsTSubstring@_S@@ABUEventListenerFlags@2@@Z
?IsUniversalXPConnectEnabled@xpc@@YA_NPAUJSContext@@@Z
?EventListenerAdded@EventTarget@dom@mozilla@@UAEXPAVnsAtom@@@Z
?Release@nsXBLWindowKeyHandler@@UAGKXZ
??$NewRunnableMethod@PAVnsGlobalWindowOuter@@P81@AEXXZ@mozilla@@YA?AU?$already_AddRefed@V?$nsRunnableMethod@VnsGlobalWindowOuter@@X$00$0A@@@@@PBD$$QAPAVnsGlobalWindowOuter@@P82@AEXXZ@Z

View File

@ -6419,7 +6419,6 @@ NS_CycleCollectorSuspectUsingNursery
?AddRef@nsXBLWindowKeyHandler@@UEAAKXZ
?InstallKeyboardEventListenersTo@nsXBLWindowKeyHandler@@QEAAXPEAVEventListenerManager@mozilla@@@Z
?AddEventListenerByType@EventListenerManager@mozilla@@QEAAXPEAVnsIDOMEventListener@@AEBV?$nsTSubstring@_S@@AEBUEventListenerFlags@2@@Z
?IsUniversalXPConnectEnabled@xpc@@YA_NPEAUJSContext@@@Z
?EventListenerAdded@EventTarget@dom@mozilla@@UEAAXPEAVnsAtom@@@Z
?Release@nsXBLWindowKeyHandler@@UEAAKXZ
??$NewRunnableMethod@PEAVnsGlobalWindowOuter@@P81@EAAXXZ@mozilla@@YA?AU?$already_AddRefed@V?$nsRunnableMethod@VnsGlobalWindowOuter@@X$00$0A@@@@@PEBD$$QEAPEAVnsGlobalWindowOuter@@P82@EAAXXZ@Z

View File

@ -202,6 +202,17 @@ BasePrincipal::GetIsExpandedPrincipal(bool* aResult) {
return NS_OK;
}
NS_IMETHODIMP
BasePrincipal::GetAsciiSpec(nsACString& aSpec) {
aSpec.Truncate();
nsCOMPtr<nsIURI> prinURI;
nsresult rv = GetURI(getter_AddRefs(prinURI));
if (NS_FAILED(rv) || !prinURI) {
return NS_OK;
}
return prinURI->GetAsciiSpec(aSpec);
}
NS_IMETHODIMP
BasePrincipal::GetIsSystemPrincipal(bool* aResult) {
*aResult = IsSystemPrincipal();
@ -226,6 +237,18 @@ BasePrincipal::SchemeIs(const char* aScheme, bool* aResult) {
return NS_OK;
}
NS_IMETHODIMP
BasePrincipal::IsURIInPrefList(const char* aPref, bool* aResult) {
*aResult = false;
nsCOMPtr<nsIURI> prinURI;
nsresult rv = GetURI(getter_AddRefs(prinURI));
if (NS_FAILED(rv) || !prinURI) {
return NS_OK;
}
*aResult = nsContentUtils::IsURIInPrefList(prinURI, aPref);
return NS_OK;
}
NS_IMETHODIMP
BasePrincipal::GetAboutModuleFlags(uint32_t* flags) {
*flags = 0;

View File

@ -109,10 +109,12 @@ class BasePrincipal : public nsJSPrincipals {
NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
NS_IMETHOD SchemeIs(const char* aScheme, bool* aResult) override;
NS_IMETHOD IsURIInPrefList(const char* aPref, bool* aResult) override;
NS_IMETHOD GetAboutModuleFlags(uint32_t* flags) override;
NS_IMETHOD GetIsAddonOrExpandedAddonPrincipal(bool* aResult) override;
NS_IMETHOD GetOriginAttributes(JSContext* aCx,
JS::MutableHandle<JS::Value> aVal) final;
NS_IMETHOD GetAsciiSpec(nsACString& aSpec) override;
NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
NS_IMETHOD GetIsInIsolatedMozBrowserElement(
bool* aIsInIsolatedMozBrowserElement) final;

View File

@ -197,6 +197,16 @@ interface nsIPrincipal : nsISerializable
*/
readonly attribute ACString origin;
/**
* Returns the ASCII Spec from the Principals URI.
* Might return the empty string, e.g. for the case of
* a SystemPrincipal or an EpxandedPrincipal.
*
* WARNING: DO NOT USE FOR SECURITY CHECKS.
* just for logging purposes!
*/
readonly attribute ACString AsciiSpec;
/**
* Checks if the Principal's URI Scheme matches with the parameter
*
@ -213,6 +223,12 @@ interface nsIPrincipal : nsISerializable
}
%}
/*
* Checks if the Principal's URI is contained in the given Pref
* @param pref The pref to be checked
*/
bool IsURIInPrefList(in string pref);
/**
* Returns the Flags of the Principals
* associated AboutModule, in case there is one.

View File

@ -117,6 +117,8 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"overflow-wrap",
"overflow-x",
"overflow-y",
"overscroll-behavior-inline",
"overscroll-behavior-block",
"overscroll-behavior-x",
"overscroll-behavior-y",
"break-after",

View File

@ -2039,6 +2039,9 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
return;
}
const origFlag = rawDoc.dontWarnAboutMutationEventsAndAllowSlowDOMMutations;
rawDoc.dontWarnAboutMutationEventsAndAllowSlowDOMMutations = true;
if (docMutationBreakpoints.counts.subtree > 0) {
eventListenerService.addSystemEventListener(
rawDoc,
@ -2089,6 +2092,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
true /* capture */
);
}
rawDoc.dontWarnAboutMutationEventsAndAllowSlowDOMMutations = origFlag;
},
_breakOnMutation: function(bpType) {

View File

@ -688,191 +688,6 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"-moz-column-count": {
"isInherited": false,
"subproperties": [
"column-count"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"-moz-column-fill": {
"isInherited": false,
"subproperties": [
"column-fill"
],
"supports": [],
"values": [
"auto",
"balance",
"inherit",
"initial",
"revert",
"unset"
]
},
"-moz-column-gap": {
"isInherited": false,
"subproperties": [
"column-gap"
],
"supports": [],
"values": [
"inherit",
"initial",
"normal",
"revert",
"unset"
]
},
"-moz-column-rule": {
"isInherited": false,
"subproperties": [
"column-rule-width",
"column-rule-style",
"column-rule-color"
],
"supports": [
"color"
],
"values": [
"COLOR",
"currentColor",
"dashed",
"dotted",
"double",
"groove",
"hidden",
"hsl",
"hsla",
"inherit",
"initial",
"inset",
"medium",
"none",
"outset",
"revert",
"rgb",
"rgba",
"ridge",
"solid",
"thick",
"thin",
"transparent",
"unset"
]
},
"-moz-column-rule-color": {
"isInherited": false,
"subproperties": [
"column-rule-color"
],
"supports": [
"color"
],
"values": [
"COLOR",
"currentColor",
"hsl",
"hsla",
"inherit",
"initial",
"revert",
"rgb",
"rgba",
"transparent",
"unset"
]
},
"-moz-column-rule-style": {
"isInherited": false,
"subproperties": [
"column-rule-style"
],
"supports": [],
"values": [
"dashed",
"dotted",
"double",
"groove",
"hidden",
"inherit",
"initial",
"inset",
"none",
"outset",
"revert",
"ridge",
"solid",
"unset"
]
},
"-moz-column-rule-width": {
"isInherited": false,
"subproperties": [
"column-rule-width"
],
"supports": [],
"values": [
"inherit",
"initial",
"medium",
"revert",
"thick",
"thin",
"unset"
]
},
"-moz-column-span": {
"isInherited": false,
"subproperties": [
"column-span"
],
"supports": [],
"values": [
"all",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"-moz-column-width": {
"isInherited": false,
"subproperties": [
"column-width"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"-moz-columns": {
"isInherited": false,
"subproperties": [
"column-width",
"column-count"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"-moz-context-properties": {
"isInherited": true,
"subproperties": [
@ -3020,6 +2835,8 @@ exports.CSS_PROPERTIES = {
"border-end-end-radius",
"overflow-inline",
"overflow-block",
"overscroll-behavior-inline",
"overscroll-behavior-block",
"margin-block-start",
"margin-block-end",
"margin-inline-start",
@ -8677,6 +8494,38 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"overscroll-behavior-block": {
"isInherited": false,
"subproperties": [
"overscroll-behavior-block"
],
"supports": [],
"values": [
"auto",
"contain",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"overscroll-behavior-inline": {
"isInherited": false,
"subproperties": [
"overscroll-behavior-inline"
],
"supports": [],
"values": [
"auto",
"contain",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"overscroll-behavior-x": {
"isInherited": false,
"subproperties": [
@ -10335,7 +10184,6 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"auto",
"from-font",
"inherit",
"initial",
"revert",
@ -10350,6 +10198,7 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"auto",
"from-font",
"inherit",
"initial",
"left",
@ -10870,10 +10719,6 @@ exports.PSEUDO_ELEMENTS = [
* exposed for testing purposes.
*/
exports.PREFERENCES = [
[
"column-span",
"layout.css.column-span.enabled"
],
[
"contain",
"layout.css.contain.enabled"
@ -10934,14 +10779,6 @@ exports.PREFERENCES = [
"overflow-clip-box-inline",
"layout.css.overflow-clip-box.enabled"
],
[
"overscroll-behavior-x",
"layout.css.overscroll-behavior.enabled"
],
[
"overscroll-behavior-y",
"layout.css.overscroll-behavior.enabled"
],
[
"overflow-block",
"layout.css.overflow-logical.enabled"
@ -10950,6 +10787,22 @@ exports.PREFERENCES = [
"overflow-inline",
"layout.css.overflow-logical.enabled"
],
[
"overscroll-behavior-block",
"layout.css.overscroll-behavior.enabled"
],
[
"overscroll-behavior-inline",
"layout.css.overscroll-behavior.enabled"
],
[
"overscroll-behavior-x",
"layout.css.overscroll-behavior.enabled"
],
[
"overscroll-behavior-y",
"layout.css.overscroll-behavior.enabled"
],
[
"backdrop-filter",
"layout.css.backdrop-filter.enabled"
@ -10978,13 +10831,17 @@ exports.PREFERENCES = [
"scrollbar-color",
"layout.css.scrollbar-color.enabled"
],
[
"text-decoration-thickness",
"layout.css.text-decoration-thickness.enabled"
],
[
"translate",
"layout.css.individual-transform.enabled"
],
[
"text-decoration-thickness",
"layout.css.text-decoration-thickness.enabled"
"offset-distance",
"layout.css.motion-path.enabled"
],
[
"text-underline-offset",
@ -10994,10 +10851,6 @@ exports.PREFERENCES = [
"-moz-binding",
"layout.css.moz-binding.content.enabled"
],
[
"offset-distance",
"layout.css.motion-path.enabled"
],
[
"overflow-clip-box",
"layout.css.overflow-clip-box.enabled"
@ -11090,9 +10943,33 @@ exports.PREFERENCES = [
"-webkit-appearance",
"layout.css.webkit-appearance.enabled"
],
[
"-moz-column-width",
"layout.css.prefixes.columns"
],
[
"-moz-column-count",
"layout.css.prefixes.columns"
],
[
"-moz-column-fill",
"layout.css.prefixes.columns"
],
[
"-moz-column-rule-width",
"layout.css.prefixes.columns"
],
[
"-moz-column-rule-color",
"layout.css.prefixes.columns"
],
[
"-moz-column-span",
"layout.css.column-span.enabled"
"layout.css.prefixes.columns"
],
[
"-moz-column-rule-style",
"layout.css.prefixes.columns"
],
[
"-moz-font-feature-settings",
@ -11122,6 +10999,10 @@ exports.PREFERENCES = [
"-moz-box-sizing",
"layout.css.prefixes.box-sizing"
],
[
"-moz-column-gap",
"layout.css.prefixes.columns"
],
[
"-moz-border-image",
"layout.css.prefixes.border-image"
@ -11133,5 +11014,13 @@ exports.PREFERENCES = [
[
"-moz-animation",
"layout.css.prefixes.animations"
],
[
"-moz-columns",
"layout.css.prefixes.columns"
],
[
"-moz-column-rule",
"layout.css.prefixes.columns"
]
];

View File

@ -160,6 +160,8 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
bool IsContent() const { return mType == Type::Content; }
bool IsTopContent() const { return IsContent() && !GetParent(); }
uint64_t Id() const { return mBrowsingContextId; }
BrowsingContext* GetParent() const { return mParent; }

View File

@ -24,7 +24,7 @@ nsDocShellEditorData::~nsDocShellEditorData() { TearDownEditor(); }
void nsDocShellEditorData::TearDownEditor() {
if (mHTMLEditor) {
RefPtr<HTMLEditor> htmlEditor = mHTMLEditor.forget();
RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
htmlEditor->PreDestroy(false);
}
mEditingSession = nullptr;
@ -41,7 +41,7 @@ nsresult nsDocShellEditorData::MakeEditable(bool aInWaitForUriLoad) {
if (mHTMLEditor) {
NS_WARNING("Destroying existing editor on frame");
RefPtr<HTMLEditor> htmlEditor = mHTMLEditor.forget();
RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
htmlEditor->PreDestroy(false);
}
@ -70,7 +70,7 @@ nsresult nsDocShellEditorData::SetHTMLEditor(HTMLEditor* aHTMLEditor) {
}
if (mHTMLEditor) {
RefPtr<HTMLEditor> htmlEditor = mHTMLEditor.forget();
RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
htmlEditor->PreDestroy(false);
MOZ_ASSERT(!mHTMLEditor,
"Nested call of nsDocShellEditorData::SetHTMLEditor() detected");

View File

@ -1724,7 +1724,7 @@ void Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag) {
} else if (!mFinishNotificationTask) {
RefPtr<MicroTaskRunnable> runnable = new AsyncFinishNotification(this);
context->DispatchToMicroTask(do_AddRef(runnable));
mFinishNotificationTask = runnable.forget();
mFinishNotificationTask = std::move(runnable);
}
}

View File

@ -221,7 +221,7 @@ void KeyframeEffect::SetKeyframes(JSContext* aContext,
JS::Handle<JSObject*> aKeyframes,
ErrorResult& aRv) {
nsTArray<Keyframe> keyframes = KeyframeUtils::GetKeyframesFromObject(
aContext, mDocument, aKeyframes, aRv);
aContext, mDocument, aKeyframes, "KeyframeEffect.setKeyframes: ", aRv);
if (aRv.Failed()) {
return;
}
@ -1488,7 +1488,7 @@ bool KeyframeEffect::CanAnimateTransformOnCompositor(
// this function via HasOpacity(). See bug 779598.
if (primaryFrame->Combines3DTransformWithAncestors() ||
primaryFrame->StyleDisplay()->mTransformStyle ==
NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
StyleTransformStyle::Preserve3d) {
aPerformanceWarning =
AnimationPerformanceWarning::Type::TransformPreserve3D;
return false;

View File

@ -132,14 +132,13 @@ class ComputedOffsetComparator {
//
// ------------------------------------------------------------------
static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
dom::Document* aDocument,
JS::ForOfIterator& aIterator,
nsTArray<Keyframe>& aResult,
ErrorResult& aRv);
static void GetKeyframeListFromKeyframeSequence(
JSContext* aCx, dom::Document* aDocument, JS::ForOfIterator& aIterator,
nsTArray<Keyframe>& aResult, const char* aContext, ErrorResult& aRv);
static bool ConvertKeyframeSequence(JSContext* aCx, dom::Document* aDocument,
JS::ForOfIterator& aIterator,
const char* aContext,
nsTArray<Keyframe>& aResult);
static bool GetPropertyValuesPairs(JSContext* aCx,
@ -192,7 +191,7 @@ static void DistributeRange(const Range<Keyframe>& aRange);
/* static */
nsTArray<Keyframe> KeyframeUtils::GetKeyframesFromObject(
JSContext* aCx, dom::Document* aDocument, JS::Handle<JSObject*> aFrames,
ErrorResult& aRv) {
const char* aContext, ErrorResult& aRv) {
MOZ_ASSERT(!aRv.Failed());
nsTArray<Keyframe> keyframes;
@ -213,7 +212,8 @@ nsTArray<Keyframe> KeyframeUtils::GetKeyframesFromObject(
}
if (iter.valueIsIterable()) {
GetKeyframeListFromKeyframeSequence(aCx, aDocument, iter, keyframes, aRv);
GetKeyframeListFromKeyframeSequence(aCx, aDocument, iter, keyframes,
aContext, aRv);
} else {
GetKeyframeListFromPropertyIndexedKeyframe(aCx, aDocument, objectValue,
keyframes, aRv);
@ -338,21 +338,20 @@ bool KeyframeUtils::IsAnimatableProperty(nsCSSPropertyID aProperty) {
* object to iterate over as a sequence.
* @param aResult The array into which the resulting Keyframe objects will be
* appended.
* @param aContext The context string to prepend to thrown exceptions.
* @param aRv Out param to store any errors thrown by this function.
*/
static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
dom::Document* aDocument,
JS::ForOfIterator& aIterator,
nsTArray<Keyframe>& aResult,
ErrorResult& aRv) {
static void GetKeyframeListFromKeyframeSequence(
JSContext* aCx, dom::Document* aDocument, JS::ForOfIterator& aIterator,
nsTArray<Keyframe>& aResult, const char* aContext, ErrorResult& aRv) {
MOZ_ASSERT(!aRv.Failed());
MOZ_ASSERT(aResult.IsEmpty());
// Convert the object in aIterator to a sequence of keyframes producing
// an array of Keyframe objects.
if (!ConvertKeyframeSequence(aCx, aDocument, aIterator, aResult)) {
if (!ConvertKeyframeSequence(aCx, aDocument, aIterator, aContext, aResult)) {
aResult.Clear();
aRv.Throw(NS_ERROR_FAILURE);
aRv.NoteJSContextException(aCx);
return;
}
@ -378,6 +377,7 @@ static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
*/
static bool ConvertKeyframeSequence(JSContext* aCx, dom::Document* aDocument,
JS::ForOfIterator& aIterator,
const char* aContext,
nsTArray<Keyframe>& aResult) {
JS::Rooted<JS::Value> value(aCx);
ErrorResult parseEasingResult;
@ -394,8 +394,10 @@ static bool ConvertKeyframeSequence(JSContext* aCx, dom::Document* aDocument,
// or null/undefined (which gets treated as a default {} dictionary
// value).
if (!value.isObject() && !value.isNullOrUndefined()) {
dom::ThrowErrorMessage(aCx, dom::MSG_NOT_OBJECT,
"Element of sequence<Keyframe> argument");
dom::ThrowErrorMessage<dom::MSG_NOT_OBJECT>(
aCx,
nsPrintfCString("%sElement of sequence<Keyframe> argument", aContext)
.get());
return false;
}

View File

@ -47,6 +47,9 @@ class KeyframeUtils {
* @param aDocument The document to use when parsing CSS properties.
* @param aFrames The JS value, provided as an optional IDL |object?| value,
* that is the keyframe list specification.
* @param aContext Information about who is trying to get keyframes from the
* object, for use in error reporting. This must be be a non-null
* pointer representing a null-terminated ASCII string.
* @param aRv (out) Out-param to hold any error returned by this function.
* Must be initially empty.
* @return The set of processed keyframes. If an error occurs, aRv will be
@ -55,7 +58,7 @@ class KeyframeUtils {
*/
static nsTArray<Keyframe> GetKeyframesFromObject(
JSContext* aCx, dom::Document* aDocument, JS::Handle<JSObject*> aFrames,
ErrorResult& aRv);
const char* aContext, ErrorResult& aRv);
/**
* Calculate the computed offset of keyframes by evenly distributing keyframes

View File

@ -5,6 +5,8 @@
#include "mozilla/dom/AbstractRange.h"
#include "mozilla/dom/AbstractRangeBinding.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/RangeUtils.h"
#include "mozilla/dom/StaticRange.h"
#include "nsContentUtils.h"
@ -72,9 +74,9 @@ AbstractRange::AbstractRange(nsINode* aNode)
mOwner = aNode->OwnerDoc();
}
nsINode* AbstractRange::GetCommonAncestor() const {
return mIsPositioned ? nsContentUtils::GetCommonAncestor(mStart.Container(),
mEnd.Container())
nsINode* AbstractRange::GetClosestCommonInclusiveAncestor() const {
return mIsPositioned ? nsContentUtils::GetClosestCommonInclusiveAncestor(
mStart.Container(), mEnd.Container())
: nullptr;
}
@ -105,7 +107,10 @@ nsresult AbstractRange::SetStartAndEndInternal(
// XXX: Offsets - handle this more efficiently.
// If the end offset is less than the start offset, this should be
// collapsed at the end offset.
if (aStartBoundary.Offset() > aEndBoundary.Offset()) {
if (*aStartBoundary.Offset(
RangeBoundaryBase<SPT, SRT>::OffsetFilter::kValidOffsets) >
*aEndBoundary.Offset(
RangeBoundaryBase<EPT, ERT>::OffsetFilter::kValidOffsets)) {
aRange->DoSetRange(aEndBoundary, aEndBoundary, newStartRoot);
} else {
aRange->DoSetRange(aStartBoundary, aEndBoundary, newStartRoot);
@ -127,9 +132,17 @@ nsresult AbstractRange::SetStartAndEndInternal(
return NS_OK;
}
const Maybe<int32_t> pointOrder =
nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary);
if (!pointOrder) {
// Safely return a value but also detected this in debug builds.
MOZ_ASSERT_UNREACHABLE();
return NS_ERROR_INVALID_ARG;
}
// If the end point is before the start point, this should be collapsed at
// the end point.
if (nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary) == 1) {
if (*pointOrder == 1) {
aRange->DoSetRange(aEndBoundary, aEndBoundary, newEndRoot);
return NS_OK;
}

View File

@ -34,7 +34,10 @@ class AbstractRange : public nsISupports, public nsWrapperCache {
}
nsIContent* GetChildAtEndOffset() const { return mEnd.GetChildAtOffset(); }
bool IsPositioned() const { return mIsPositioned; }
nsINode* GetCommonAncestor() const;
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
nsINode* GetClosestCommonInclusiveAncestor() const;
// WebIDL
@ -48,23 +51,31 @@ class AbstractRange : public nsISupports, public nsWrapperCache {
nsINode* GetStartContainer() const { return mStart.Container(); }
nsINode* GetEndContainer() const { return mEnd.Container(); }
// FYI: Returns 0 if it's not positioned.
uint32_t StartOffset() const {
// FYI: Returns 0 if it's not positioned.
return static_cast<uint32_t>(mStart.Offset());
return static_cast<uint32_t>(
*mStart.Offset(RangeBoundary::OffsetFilter::kValidOrInvalidOffsets));
}
// FYI: Returns 0 if it's not positioned.
uint32_t EndOffset() const {
// FYI: Returns 0 if it's not positioned.
return static_cast<uint32_t>(mEnd.Offset());
return static_cast<uint32_t>(
*mEnd.Offset(RangeBoundary::OffsetFilter::kValidOrInvalidOffsets));
}
bool Collapsed() const {
return !mIsPositioned || (mStart.Container() == mEnd.Container() &&
mStart.Offset() == mEnd.Offset());
StartOffset() == EndOffset());
}
nsINode* GetParentObject() const { return mOwner; }
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
bool HasEqualBoundaries(const AbstractRange& aOther) const {
return (mStart == aOther.mStart) && (mEnd == aOther.mEnd);
}
protected:
template <typename SPT, typename SRT, typename EPT, typename ERT,
typename RangeType>
@ -75,6 +86,8 @@ class AbstractRange : public nsISupports, public nsWrapperCache {
RefPtr<Document> mOwner;
RangeBoundary mStart;
RangeBoundary mEnd;
// `true` if `mStart` and `mEnd` are set for StaticRange or set and valid
// for nsRange.
bool mIsPositioned;
// Used by nsRange, but this should have this for minimizing the size.

View File

@ -214,7 +214,7 @@ void AnonymousContent::SetStyle(const nsACString& aProperty,
nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(mContentNode);
nsCOMPtr<nsICSSDeclaration> declaration = element->Style();
declaration->SetProperty(aProperty, aValue, EmptyString());
declaration->SetProperty(aProperty, aValue, EmptyString(), IgnoreErrors());
}
} // namespace dom

View File

@ -640,7 +640,7 @@ void BodyConsumer::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength,
mBodyConsumed = true;
MOZ_ASSERT(mConsumePromise);
RefPtr<Promise> localPromise = mConsumePromise.forget();
RefPtr<Promise> localPromise = std::move(mConsumePromise);
RefPtr<BodyConsumer> self = this;
auto autoReleaseObject =
@ -750,7 +750,7 @@ void BodyConsumer::ContinueConsumeBlobBody(BlobImpl* aBlobImpl,
mBodyConsumed = true;
MOZ_ASSERT(mConsumePromise);
RefPtr<Promise> localPromise = mConsumePromise.forget();
RefPtr<Promise> localPromise = std::move(mConsumePromise);
if (!aShuttingDown) {
RefPtr<dom::Blob> blob = dom::Blob::Create(mGlobal, aBlobImpl);

View File

@ -122,7 +122,7 @@ void BodyStream::Create(JSContext* aCx, BodyStreamHolder* aStreamHolder,
// Note, this will create a ref-cycle between the holder and the stream.
// The cycle is broken when the stream is closed or the worker begins
// shutting down.
stream->mWorkerRef = workerRef.forget();
stream->mWorkerRef = std::move(workerRef);
}
aRv.MightThrowJSException();

View File

@ -329,7 +329,7 @@ class IdleDispatchRunnable final : public IdleRunnable,
RefPtr<IdleDeadline> idleDeadline =
new IdleDeadline(mParent, mTimedOut, deadline.ToMilliseconds());
RefPtr<IdleRequestCallback> callback(mCallback.forget());
RefPtr<IdleRequestCallback> callback(std::move(mCallback));
MOZ_ASSERT(!mCallback);
callback->Call(*idleDeadline, "ChromeUtils::IdleDispatch handler");
mParent = nullptr;

View File

@ -15,6 +15,64 @@
namespace mozilla {
static bool ComparePostMode(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd, nsINode& aNode) {
nsINode* parent = aNode.GetParentNode();
if (!parent) {
return false;
}
// aNode should always be content, as we have a parent, but let's just be
// extra careful and check.
nsIContent* content =
NS_WARN_IF(!aNode.IsContent()) ? nullptr : aNode.AsContent();
// Post mode: start < node <= end.
RawRangeBoundary afterNode(parent, content);
const auto isStartLessThanAfterNode = [&]() {
const Maybe<int32_t> startComparedToAfterNode =
nsContentUtils::ComparePoints(aStart, afterNode);
return !NS_WARN_IF(!startComparedToAfterNode) &&
(*startComparedToAfterNode < 0);
};
const auto isAfterNodeLessOrEqualToEnd = [&]() {
const Maybe<int32_t> afterNodeComparedToEnd =
nsContentUtils::ComparePoints(afterNode, aEnd);
return !NS_WARN_IF(!afterNodeComparedToEnd) &&
(*afterNodeComparedToEnd <= 0);
};
return isStartLessThanAfterNode() && isAfterNodeLessOrEqualToEnd();
}
static bool ComparePreMode(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd, nsINode& aNode) {
nsINode* parent = aNode.GetParentNode();
if (!parent) {
return false;
}
// Pre mode: start <= node < end.
RawRangeBoundary beforeNode(parent, aNode.GetPreviousSibling());
const auto isStartLessOrEqualToBeforeNode = [&]() {
const Maybe<int32_t> startComparedToBeforeNode =
nsContentUtils::ComparePoints(aStart, beforeNode);
return !NS_WARN_IF(!startComparedToBeforeNode) &&
(*startComparedToBeforeNode <= 0);
};
const auto isBeforeNodeLessThanEndNode = [&]() {
const Maybe<int32_t> beforeNodeComparedToEnd =
nsContentUtils::ComparePoints(beforeNode, aEnd);
return !NS_WARN_IF(!beforeNodeComparedToEnd) &&
(*beforeNodeComparedToEnd < 0);
};
return isStartLessOrEqualToBeforeNode() && isBeforeNodeLessThanEndNode();
}
///////////////////////////////////////////////////////////////////////////
// NodeIsInTraversalRange: returns true if content is visited during
// the traversal of the range in the specified mode.
@ -45,26 +103,11 @@ static bool NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
}
}
nsINode* parent = aNode->GetParentNode();
if (!parent) {
return false;
if (aIsPreMode) {
return ComparePreMode(aStart, aEnd, *aNode);
}
if (!aIsPreMode) {
// aNode should always be content, as we have a parent, but let's just be
// extra careful and check.
nsIContent* content =
NS_WARN_IF(!aNode->IsContent()) ? nullptr : aNode->AsContent();
// Post mode: start < node <= end.
RawRangeBoundary afterNode(parent, content);
return nsContentUtils::ComparePoints(aStart, afterNode) < 0 &&
nsContentUtils::ComparePoints(aEnd, afterNode) >= 0;
}
// Pre mode: start <= node < end.
RawRangeBoundary beforeNode(parent, aNode->GetPreviousSibling());
return nsContentUtils::ComparePoints(aStart, beforeNode) <= 0 &&
nsContentUtils::ComparePoints(aEnd, beforeNode) > 0;
return ComparePostMode(aStart, aEnd, *aNode);
}
ContentIteratorBase::ContentIteratorBase(bool aPre)
@ -139,8 +182,8 @@ nsresult ContentIteratorBase::Init(const RawRangeBoundary& aStart,
nsresult ContentIteratorBase::InitInternal(const RawRangeBoundary& aStart,
const RawRangeBoundary& aEnd) {
// get common content parent
mCommonParent =
nsContentUtils::GetCommonAncestor(aStart.Container(), aEnd.Container());
mCommonParent = nsContentUtils::GetClosestCommonInclusiveAncestor(
aStart.Container(), aEnd.Container());
if (NS_WARN_IF(!mCommonParent)) {
return NS_ERROR_FAILURE;
}
@ -665,7 +708,7 @@ nsresult ContentSubtreeIterator::InitWithRange() {
MOZ_ASSERT(mRange->IsPositioned());
// get the start node and offset, convert to nsINode
mCommonParent = mRange->GetCommonAncestor();
mCommonParent = mRange->GetClosestCommonInclusiveAncestor();
nsINode* startContainer = mRange->GetStartContainer();
int32_t startOffset = mRange->StartOffset();
nsINode* endContainer = mRange->GetEndContainer();

View File

@ -29,7 +29,13 @@ class ContentIteratorBase {
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentIteratorBase)
/**
* Allows to iterate over the inclusive descendants
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant) of
* aRoot.
*/
virtual nsresult Init(nsINode* aRoot);
virtual nsresult Init(nsRange* aRange);
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset);
@ -172,7 +178,11 @@ class ContentSubtreeIterator final : public ContentIteratorBase {
ContentSubtreeIterator& operator=(const ContentSubtreeIterator&) = delete;
virtual ~ContentSubtreeIterator() = default;
/**
* Not supported.
*/
virtual nsresult Init(nsINode* aRoot) override;
virtual nsresult Init(nsRange* aRange) override;
virtual nsresult Init(nsINode* aStartContainer, uint32_t aStartOffset,
nsINode* aEndContainer, uint32_t aEndOffset) override;

View File

@ -165,9 +165,11 @@ CustomElementData::CustomElementData(nsAtom* aType, State aState)
void CustomElementData::SetCustomElementDefinition(
CustomElementDefinition* aDefinition) {
MOZ_ASSERT(mState == State::eCustom);
MOZ_ASSERT(!mCustomElementDefinition);
MOZ_ASSERT(aDefinition->mType == mType);
// Only allow reset definition to nullptr if the custom element state is
// "failed".
MOZ_ASSERT(aDefinition ? !mCustomElementDefinition
: mState == State::eFailed);
MOZ_ASSERT_IF(aDefinition, aDefinition->mType == mType);
mCustomElementDefinition = aDefinition;
}
@ -178,9 +180,10 @@ void CustomElementData::AttachedInternals() {
mIsAttachedInternals = true;
}
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() {
MOZ_ASSERT(mCustomElementDefinition ? mState == State::eCustom
: mState != State::eCustom);
CustomElementDefinition* CustomElementData::GetCustomElementDefinition() const {
// Per spec, if there is a definition, the custom element state should be
// either "failed" (during upgrade) or "customized".
MOZ_ASSERT_IF(mCustomElementDefinition, mState != State::eUndefined);
return mCustomElementDefinition;
}
@ -312,7 +315,7 @@ CustomElementRegistry::RunCustomElementCreationCallback::Run() {
MOZ_ASSERT(!mRegistry->mElementCreationCallbacks.GetWeak(mAtom),
"Callback should be removed.");
nsAutoPtr<nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>> elements;
mozilla::UniquePtr<nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>> elements;
mRegistry->mElementCreationCallbacksUpgradeCandidatesMap.Remove(mAtom,
&elements);
MOZ_ASSERT(elements, "There should be a list");
@ -487,6 +490,7 @@ CustomElementRegistry::CreateCustomElementCallback(
return callback;
}
// https://html.spec.whatwg.org/commit-snapshots/65f39c6fc0efa92b0b2b23b93197016af6ac0de6/#enqueue-a-custom-element-callback-reaction
/* static */
void CustomElementRegistry::EnqueueLifecycleCallback(
Document::ElementCallbackType aType, Element* aCustomElement,
@ -599,7 +603,7 @@ void CustomElementRegistry::UpgradeCandidates(
return;
}
nsAutoPtr<nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>> candidates;
mozilla::UniquePtr<nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>> candidates;
if (mCandidatesMap.Remove(aKey, &candidates)) {
MOZ_ASSERT(candidates);
CustomElementReactionsStack* reactionsStack =
@ -641,18 +645,19 @@ int32_t CustomElementRegistry::InferNamespace(
}
bool CustomElementRegistry::JSObjectToAtomArray(
JSContext* aCx, JS::Handle<JSObject*> aConstructor, const char16_t* aName,
JSContext* aCx, JS::Handle<JSObject*> aConstructor, const nsString& aName,
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv) {
JS::RootedValue iterable(aCx, JS::UndefinedValue());
if (!JS_GetUCProperty(aCx, aConstructor, aName,
std::char_traits<char16_t>::length(aName), &iterable)) {
if (!JS_GetUCProperty(aCx, aConstructor, aName.get(), aName.Length(),
&iterable)) {
aRv.NoteJSContextException(aCx);
return false;
}
if (!iterable.isUndefined()) {
if (!iterable.isObject()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("CustomElementRegistry.define: ") + aName);
return false;
}
@ -663,7 +668,8 @@ bool CustomElementRegistry::JSObjectToAtomArray(
}
if (!iter.valueIsIterable()) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(nsDependentString(aName));
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("CustomElementRegistry.define: ") + aName);
return false;
}
@ -736,8 +742,7 @@ void CustomElementRegistry::Define(
Document* doc = mWindow->GetExtantDoc();
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
aRv.ThrowDOMException(
NS_ERROR_DOM_SYNTAX_ERR,
aRv.ThrowSyntaxError(
nsPrintfCString("'%s' is not a valid custom element name",
NS_ConvertUTF16toUTF8(aName).get()));
return;
@ -748,8 +753,7 @@ void CustomElementRegistry::Define(
* throw a "NotSupportedError" DOMException and abort these steps.
*/
if (mCustomDefinitions.GetWeak(nameAtom)) {
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
aRv.ThrowNotSupportedError(
nsPrintfCString("'%s' has already been defined as a custom element",
NS_ConvertUTF16toUTF8(aName).get()));
return;
@ -766,8 +770,7 @@ void CustomElementRegistry::Define(
"Definition must be found in mCustomDefinitions");
nsAutoCString name;
ptr->value()->ToUTF8String(name);
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
aRv.ThrowNotSupportedError(
nsPrintfCString("'%s' and '%s' have the same constructor",
NS_ConvertUTF16toUTF8(aName).get(), name.get()));
return;
@ -801,8 +804,7 @@ void CustomElementRegistry::Define(
if (aOptions.mExtends.WasPassed()) {
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
if (nsContentUtils::IsCustomElementName(extendsAtom, kNameSpaceID_XHTML)) {
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
aRv.ThrowNotSupportedError(
nsPrintfCString("'%s' cannot extend a custom element",
NS_ConvertUTF16toUTF8(aName).get()));
return;
@ -833,8 +835,7 @@ void CustomElementRegistry::Define(
* set, then throw a "NotSupportedError" DOMException and abort these steps.
*/
if (mIsCustomDefinitionRunning) {
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
aRv.ThrowNotSupportedError(
"Cannot define a custom element while defining another custom element");
return;
}
@ -867,8 +868,8 @@ void CustomElementRegistry::Define(
* 14.2. If Type(prototype) is not Object, then throw a TypeError exception.
*/
if (!prototype.isObject()) {
aRv.ThrowTypeError<MSG_NOT_OBJECT>(
NS_LITERAL_STRING("constructor.prototype"));
aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING(
"CustomElementRegistry.define: constructor.prototype"));
return;
}
@ -902,7 +903,8 @@ void CustomElementRegistry::Define(
* any exceptions from the conversion.
*/
if (callbacksHolder->mAttributeChangedCallback.WasPassed()) {
if (!JSObjectToAtomArray(aCx, constructor, u"observedAttributes",
if (!JSObjectToAtomArray(aCx, constructor,
NS_LITERAL_STRING("observedAttributes"),
observedAttributes, aRv)) {
return;
}
@ -918,7 +920,8 @@ void CustomElementRegistry::Define(
* Rethrow any exceptions from the conversion.
*/
if (StaticPrefs::dom_webcomponents_elementInternals_enabled()) {
if (!JSObjectToAtomArray(aCx, constructor, u"disabledFeatures",
if (!JSObjectToAtomArray(aCx, constructor,
NS_LITERAL_STRING("disabledFeatures"),
disabledFeatures, aRv)) {
return;
}
@ -1018,7 +1021,6 @@ void CustomElementRegistry::SetElementCreationCallback(
RefPtr<CustomElementCreationCallback> callback = &aCallback;
mElementCreationCallbacks.Put(nameAtom, callback.forget());
return;
}
void CustomElementRegistry::Upgrade(nsINode& aRoot) {
@ -1096,12 +1098,10 @@ static void DoUpgrade(Element* aElement, CustomElementDefinition* aDefinition,
CustomElementConstructor* aConstructor,
ErrorResult& aRv) {
if (aDefinition->mDisableShadow && aElement->GetShadowRoot()) {
aRv.ThrowDOMException(
NS_ERROR_DOM_NOT_SUPPORTED_ERR,
nsPrintfCString(
"Custom element upgrade to '%s' is disabled due to shadow root "
"already exists",
NS_ConvertUTF16toUTF8(aDefinition->mType->GetUTF16String()).get()));
aRv.ThrowNotSupportedError(nsPrintfCString(
"Custom element upgrade to '%s' is disabled because a shadow root "
"already exists",
NS_ConvertUTF16toUTF8(aDefinition->mType->GetUTF16String()).get()));
return;
}
@ -1119,14 +1119,14 @@ static void DoUpgrade(Element* aElement, CustomElementDefinition* aDefinition,
// always forms the return value from a JSObject.
if (NS_FAILED(UNWRAP_OBJECT(Element, &constructResult, element)) ||
element != aElement) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
aRv.ThrowTypeError(u"Custom element constructor returned a wrong element");
return;
}
}
} // anonymous namespace
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades
// https://html.spec.whatwg.org/commit-snapshots/2793ee4a461c6c39896395f1a45c269ea820c47e/#upgrades
/* static */
void CustomElementRegistry::Upgrade(Element* aElement,
CustomElementDefinition* aDefinition,
@ -1134,13 +1134,18 @@ void CustomElementRegistry::Upgrade(Element* aElement,
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
MOZ_ASSERT(data, "CustomElementData should exist");
// Step 1 and step 2.
if (data->mState == CustomElementData::State::eCustom ||
data->mState == CustomElementData::State::eFailed) {
// Step 1.
if (data->mState != CustomElementData::State::eUndefined) {
return;
}
// Step 2.
aElement->SetCustomElementDefinition(aDefinition);
// Step 3.
data->mState = CustomElementData::State::eFailed;
// Step 4.
if (!aDefinition->mObservedAttributes.IsEmpty()) {
uint32_t count = aElement->GetAttrCount();
for (uint32_t i = 0; i < count; i++) {
@ -1165,31 +1170,29 @@ void CustomElementRegistry::Upgrade(Element* aElement,
}
}
// Step 4.
// Step 5.
if (aElement->IsInComposedDoc()) {
nsContentUtils::EnqueueLifecycleCallback(Document::eConnected, aElement,
nullptr, nullptr, aDefinition);
}
// Step 5.
// Step 6.
AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
// Step 6 and step 7.
// Step 7 and step 8.
DoUpgrade(aElement, aDefinition, MOZ_KnownLive(aDefinition->mConstructor),
aRv);
if (aRv.Failed()) {
data->mState = CustomElementData::State::eFailed;
MOZ_ASSERT(data->mState == CustomElementData::State::eFailed);
aElement->SetCustomElementDefinition(nullptr);
// Empty element's custom element reaction queue.
data->mReactionQueue.Clear();
return;
}
// Step 8.
// Step 10.
data->mState = CustomElementData::State::eCustom;
aElement->SetDefined(true);
// Step 9.
aElement->SetCustomElementDefinition(aDefinition);
}
already_AddRefed<nsISupports> CustomElementRegistry::CallGetCustomInterface(

View File

@ -101,7 +101,7 @@ struct CustomElementData {
AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
CustomElementDefinition* GetCustomElementDefinition();
CustomElementDefinition* GetCustomElementDefinition() const;
nsAtom* GetCustomElementType() const { return mType; }
void AttachedInternals();
bool HasAttachedInternals() const { return mIsAttachedInternals; }
@ -477,7 +477,7 @@ class CustomElementRegistry final : public nsISupports, public nsWrapperCache {
~CustomElementRegistry();
bool JSObjectToAtomArray(JSContext* aCx, JS::Handle<JSObject*> aConstructor,
const char16_t* aName,
const nsString& aName,
nsTArray<RefPtr<nsAtom>>& aArray, ErrorResult& aRv);
static UniquePtr<CustomElementCallback> CreateCustomElementCallback(

View File

@ -9,6 +9,7 @@
#include "nsLayoutUtils.h"
#include "mozilla/PresShell.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/dom/DocumentInlines.h"
namespace mozilla {
namespace dom {
@ -127,6 +128,11 @@ void DOMIntersectionObserver::Observe(Element& aTarget) {
aTarget.RegisterIntersectionObserver(this);
mObservationTargets.AppendElement(&aTarget);
Connect();
if (mDocument) {
if (nsPresContext* pc = mDocument->GetPresContext()) {
pc->RefreshDriver()->IntersectionObservationAdded();
}
}
}
void DOMIntersectionObserver::Unobserve(Element& aTarget) {
@ -183,25 +189,6 @@ void DOMIntersectionObserver::TakeRecords(
mQueuedEntries.Clear();
}
static bool CheckSimilarOrigin(nsINode* aNode1, nsINode* aNode2) {
nsIPrincipal* principal1 = aNode1->NodePrincipal();
nsIPrincipal* principal2 = aNode2->NodePrincipal();
nsAutoCString baseDomain1;
nsAutoCString baseDomain2;
nsresult rv = principal1->GetBaseDomain(baseDomain1);
if (NS_FAILED(rv)) {
return principal1 == principal2;
}
rv = principal2->GetBaseDomain(baseDomain2);
if (NS_FAILED(rv)) {
return principal1 == principal2;
}
return baseDomain1 == baseDomain2;
}
static Maybe<nsRect> EdgeInclusiveIntersection(const nsRect& aRect,
const nsRect& aOtherRect) {
nscoord left = std::max(aRect.x, aOtherRect.x);
@ -214,22 +201,140 @@ static Maybe<nsRect> EdgeInclusiveIntersection(const nsRect& aRect,
return Some(nsRect(left, top, right - left, bottom - top));
}
enum class BrowsingContextInfo {
SimilarOriginBrowsingContext,
DifferentOriginBrowsingContext,
UnknownBrowsingContext
};
enum class BrowsingContextOrigin { Similar, Different, Unknown };
// FIXME(emilio): The whole concept of "units of related similar-origin browsing
// contexts" is gone, but this is still in the spec, see
// https://github.com/w3c/IntersectionObserver/issues/161
static BrowsingContextOrigin SimilarOrigin(const Element& aTarget,
const Element* aRoot) {
if (!aRoot) {
return BrowsingContextOrigin::Unknown;
}
nsIPrincipal* principal1 = aTarget.NodePrincipal();
nsIPrincipal* principal2 = aRoot->NodePrincipal();
if (principal1 == principal2) {
return BrowsingContextOrigin::Similar;
}
nsAutoCString baseDomain1;
nsAutoCString baseDomain2;
if (NS_FAILED(principal1->GetBaseDomain(baseDomain1)) ||
NS_FAILED(principal2->GetBaseDomain(baseDomain2))) {
return BrowsingContextOrigin::Different;
}
return baseDomain1 == baseDomain2 ? BrowsingContextOrigin::Similar
: BrowsingContextOrigin::Different;
}
// https://w3c.github.io/IntersectionObserver/#compute-the-intersection
//
// TODO(emilio): Proof of this being equivalent to the spec welcome, seems
// reasonably close.
//
// Also, it's unclear to me why the spec talks about browsing context while
// discarding observations of targets of different documents.
//
// Both aRootBounds and the return value are relative to
// nsLayoutUtils::GetContainingBlockForClientRect(aRoot).
static Maybe<nsRect> ComputeTheIntersection(nsIFrame* aTarget, nsIFrame* aRoot,
const nsRect& aRootBounds) {
nsIFrame* target = aTarget;
// 1. Let intersectionRect be the result of running the
// getBoundingClientRect() algorithm on the target.
//
// FIXME(emilio, mstange): Spec uses `getBoundingClientRect()` (which is the
// union of all continuations), but this code doesn't handle continuations.
//
// `intersectionRect` is kept relative to `target` during the loop.
Maybe<nsRect> intersectionRect = Some(target->GetRectRelativeToSelf());
// 2. Let container be the containing block of the target.
// (We go through the parent chain and only look at scroll frames)
//
// FIXME(emilio): Spec uses containing blocks, we use scroll frames, but we
// only apply overflow-clipping, not clip-path, so it's ~fine. We do need to
// apply clip-path.
//
// 3. While container is not the intersection root:
nsIFrame* containerFrame = nsLayoutUtils::GetCrossDocParentFrame(target);
while (containerFrame && containerFrame != aRoot) {
// FIXME(emilio): What about other scroll frames that inherit from
// nsHTMLScrollFrame but have a different type, like nsListControlFrame?
// This looks bogus in that case, but different bug.
if (containerFrame->IsScrollFrame()) {
nsIScrollableFrame* scrollFrame = do_QueryFrame(containerFrame);
//
nsRect subFrameRect = scrollFrame->GetScrollPortRect();
// 3.1 Map intersectionRect to the coordinate space of container.
nsRect intersectionRectRelativeToContainer =
nsLayoutUtils::TransformFrameRectToAncestor(
target, intersectionRect.value(), containerFrame);
// 3.2 If container has overflow clipping or a css clip-path property,
// update intersectionRect by applying container's clip.
//
// TODO: Apply clip-path.
//
// 3.3 is handled, looks like, by this same clipping, given the root
// scroll-frame cannot escape the viewport, probably?
//
intersectionRect = EdgeInclusiveIntersection(
intersectionRectRelativeToContainer, subFrameRect);
if (!intersectionRect) {
return Nothing();
}
target = containerFrame;
}
containerFrame = nsLayoutUtils::GetCrossDocParentFrame(containerFrame);
}
MOZ_ASSERT(intersectionRect);
// 4. Map intersectionRect to the coordinate space of the intersection root.
nsRect intersectionRectRelativeToRoot =
nsLayoutUtils::TransformFrameRectToAncestor(
target, intersectionRect.value(),
nsLayoutUtils::GetContainingBlockForClientRect(aRoot));
// 5.Update intersectionRect by intersecting it with the root intersection
// rectangle.
intersectionRect =
EdgeInclusiveIntersection(intersectionRectRelativeToRoot, aRootBounds);
if (intersectionRect.isNothing()) {
return Nothing();
}
// 6. Map intersectionRect to the coordinate space of the viewport of the
// Document containing the target.
//
// FIXME(emilio): I think this may not be correct if the root is explicit
// and in the same document, since then the rectangle may not be relative to
// the viewport already (but it's in the same document).
nsRect rect = intersectionRect.value();
if (aTarget->PresContext() != aRoot->PresContext()) {
if (nsIFrame* rootScrollFrame =
aTarget->PresShell()->GetRootScrollFrame()) {
nsLayoutUtils::TransformRect(aRoot, rootScrollFrame, rect);
}
}
return Some(rect);
}
// https://w3c.github.io/IntersectionObserver/#update-intersection-observations-algo
// (step 2)
void DOMIntersectionObserver::Update(Document* aDocument,
DOMHighResTimeStamp time) {
Element* root = nullptr;
nsIFrame* rootFrame = nullptr;
// 1 - Let rootBounds be observer's root intersection rectangle.
// ... but since the intersection rectangle depends on the target, we defer
// the inflation until later.
nsRect rootRect;
nsIFrame* rootFrame = nullptr;
Element* root = mRoot;
if (mRoot) {
root = mRoot;
rootFrame = root->GetPrimaryFrame();
if (rootFrame) {
if ((rootFrame = mRoot->GetPrimaryFrame())) {
nsRect rootRectRelativeToRootFrame;
if (rootFrame->IsScrollFrame()) {
// rootRectRelativeToRootFrame should be the content rect of rootFrame,
@ -245,177 +350,139 @@ void DOMIntersectionObserver::Update(Document* aDocument,
rootRect = nsLayoutUtils::TransformFrameRectToAncestor(
rootFrame, rootRectRelativeToRootFrame, containingBlock);
}
} else {
RefPtr<PresShell> presShell = aDocument->GetPresShell();
if (presShell) {
rootFrame = presShell->GetRootScrollFrame();
if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) {
presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
nsIFrame* rootScrollFrame =
presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
} else if (PresShell* presShell = aDocument->GetPresShell()) {
// FIXME(emilio): This shouldn't probably go through the presShell and just
// through the document tree.
rootFrame = presShell->GetRootScrollFrame();
if (rootFrame) {
nsPresContext* presContext = rootFrame->PresContext();
while (!presContext->IsRootContentDocument()) {
presContext = presContext->GetParentPresContext();
if (!presContext) {
break;
}
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
// If we end up with a null root frame for some reason, we'll proceed
// with an empty root intersection rect.
if (scrollFrame) {
rootRect = scrollFrame->GetScrollPortRect();
nsIFrame* rootScrollFrame =
presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
rootFrame = rootScrollFrame;
} else {
break;
}
}
root = rootFrame->GetContent()->AsElement();
nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
rootRect = scrollFrame->GetScrollPortRect();
}
}
nsMargin rootMargin;
NS_FOR_CSS_SIDES(side) {
for (const auto side : mozilla::AllPhysicalSides()) {
nscoord basis = side == eSideTop || side == eSideBottom ? rootRect.Height()
: rootRect.Width();
rootMargin.Side(side) =
nsLayoutUtils::ComputeCBDependentValue(basis, mRootMargin.Get(side));
mRootMargin.Get(side).Resolve(basis, NSToCoordRoundWithClamp);
}
for (size_t i = 0; i < mObservationTargets.Length(); ++i) {
Element* target = mObservationTargets.ElementAt(i);
// 2. For each target in observers internal [[ObservationTargets]] slot,
// processed in the same order that observe() was called on each target:
for (Element* target : mObservationTargets) {
nsIFrame* targetFrame = target->GetPrimaryFrame();
nsIFrame* originalTargetFrame = targetFrame;
nsRect targetRect;
Maybe<nsRect> intersectionRect;
bool isSameDoc = root && root->GetComposedDoc() == target->GetComposedDoc();
// 2.2. If the intersection root is not the implicit root, and target is not
// in the same Document as the intersection root, skip further processing
// for target.
if (mRoot && mRoot->OwnerDoc() != target->OwnerDoc()) {
continue;
}
nsRect rootBounds;
if (rootFrame && targetFrame) {
// If mRoot is set we are testing intersection with a container element
// instead of the implicit root.
if (mRoot) {
// Skip further processing of this target if it is not in the same
// Document as the intersection root, e.g. if root is an element of
// the main document and target an element from an embedded iframe.
if (!isSameDoc) {
continue;
}
// Skip further processing of this target if is not a descendant of the
// intersection root in the containing block chain. E.g. this would be
// the case if the target is in a position:absolute element whose
// containing block is an ancestor of root.
if (!nsLayoutUtils::IsAncestorFrameCrossDoc(rootFrame, targetFrame)) {
continue;
}
// FIXME(emilio): Why only if there are frames?
rootBounds = rootRect;
}
BrowsingContextOrigin origin = SimilarOrigin(*target, root);
if (origin == BrowsingContextOrigin::Similar) {
rootBounds.Inflate(rootMargin);
}
Maybe<nsRect> intersectionRect;
nsRect targetRect;
if (targetFrame && rootFrame) {
// 2.1. If the intersection root is not the implicit root and target is
// not a descendant of the intersection root in the containing block
// chain, skip further processing for target.
if (mRoot && !nsLayoutUtils::IsProperAncestorFrameCrossDoc(rootFrame,
targetFrame)) {
continue;
}
// 2.3. Let targetRect be a DOMRectReadOnly obtained by running the
// getBoundingClientRect() algorithm on target.
targetRect = nsLayoutUtils::GetAllInFlowRectsUnion(
targetFrame,
nsLayoutUtils::GetContainingBlockForClientRect(targetFrame),
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
intersectionRect = Some(targetFrame->GetRectRelativeToSelf());
nsIFrame* containerFrame =
nsLayoutUtils::GetCrossDocParentFrame(targetFrame);
while (containerFrame && containerFrame != rootFrame) {
if (containerFrame->IsScrollFrame()) {
nsIScrollableFrame* scrollFrame = do_QueryFrame(containerFrame);
nsRect subFrameRect = scrollFrame->GetScrollPortRect();
nsRect intersectionRectRelativeToContainer =
nsLayoutUtils::TransformFrameRectToAncestor(
targetFrame, intersectionRect.value(), containerFrame);
intersectionRect = EdgeInclusiveIntersection(
intersectionRectRelativeToContainer, subFrameRect);
if (!intersectionRect) {
break;
}
targetFrame = containerFrame;
}
// TODO: Apply clip-path.
containerFrame = nsLayoutUtils::GetCrossDocParentFrame(containerFrame);
}
}
nsRect rootIntersectionRect;
BrowsingContextInfo isInSimilarOriginBrowsingContext =
BrowsingContextInfo::UnknownBrowsingContext;
if (rootFrame && targetFrame) {
rootIntersectionRect = rootRect;
}
if (root && target) {
isInSimilarOriginBrowsingContext =
CheckSimilarOrigin(root, target)
? BrowsingContextInfo::SimilarOriginBrowsingContext
: BrowsingContextInfo::DifferentOriginBrowsingContext;
}
if (isInSimilarOriginBrowsingContext ==
BrowsingContextInfo::SimilarOriginBrowsingContext) {
rootIntersectionRect.Inflate(rootMargin);
}
if (intersectionRect.isSome()) {
nsRect intersectionRectRelativeToRoot =
nsLayoutUtils::TransformFrameRectToAncestor(
targetFrame, intersectionRect.value(),
nsLayoutUtils::GetContainingBlockForClientRect(rootFrame));
intersectionRect = EdgeInclusiveIntersection(
intersectionRectRelativeToRoot, rootIntersectionRect);
if (intersectionRect.isSome() && !isSameDoc) {
nsRect rect = intersectionRect.value();
nsPresContext* presContext = originalTargetFrame->PresContext();
nsIFrame* rootScrollFrame =
presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
nsLayoutUtils::TransformRect(rootFrame, rootScrollFrame, rect);
}
intersectionRect = Some(rect);
}
// 2.4. Let intersectionRect be the result of running the compute the
// intersection algorithm on target.
intersectionRect =
ComputeTheIntersection(targetFrame, rootFrame, rootBounds);
}
// 2.5. Let targetArea be targetRects area.
int64_t targetArea =
(int64_t)targetRect.Width() * (int64_t)targetRect.Height();
// 2.6. Let intersectionArea be intersectionRects area.
int64_t intersectionArea = !intersectionRect
? 0
: (int64_t)intersectionRect->Width() *
(int64_t)intersectionRect->Height();
// 2.7. Let isIntersecting be true if targetRect and rootBounds intersect or
// are edge-adjacent, even if the intersection has zero area (because
// rootBounds or targetRect have zero area); otherwise, let isIntersecting
// be false.
const bool isIntersecting = intersectionRect.isSome();
// 2.8. If targetArea is non-zero, let intersectionRatio be intersectionArea
// divided by targetArea. Otherwise, let intersectionRatio be 1 if
// isIntersecting is true, or 0 if isIntersecting is false.
double intersectionRatio;
if (targetArea > 0.0) {
intersectionRatio =
std::min((double)intersectionArea / (double)targetArea, 1.0);
} else {
intersectionRatio = intersectionRect.isSome() ? 1.0 : 0.0;
intersectionRatio = isIntersecting ? 1.0 : 0.0;
}
int32_t threshold = -1;
if (intersectionRect.isSome()) {
// Spec: "Let thresholdIndex be the index of the first entry in
// observer.thresholds whose value is greater than intersectionRatio."
threshold = mThresholds.IndexOfFirstElementGt(intersectionRatio);
if (threshold == 0) {
// 2.9 Let thresholdIndex be the index of the first entry in
// observer.thresholds whose value is greater than intersectionRatio, or the
// length of observer.thresholds if intersectionRatio is greater than or
// equal to the last entry in observer.thresholds.
int32_t thresholdIndex = -1;
// FIXME(emilio): Why the isIntersecting check?
if (isIntersecting) {
thresholdIndex = mThresholds.IndexOfFirstElementGt(intersectionRatio);
if (thresholdIndex == 0) {
// Per the spec, we should leave threshold at 0 and distinguish between
// "less than all thresholds and intersecting" and "not intersecting"
// (queuing observer entries as both cases come to pass). However,
// neither Chrome nor the WPT tests expect this behavior, so treat these
// two cases as one.
threshold = -1;
//
// FIXME(emilio): Looks like a good candidate for a spec issue.
thresholdIndex = -1;
}
}
if (target->UpdateIntersectionObservation(this, threshold)) {
QueueIntersectionObserverEntry(
target, time,
isInSimilarOriginBrowsingContext ==
BrowsingContextInfo::DifferentOriginBrowsingContext
? Nothing()
: Some(rootIntersectionRect),
targetRect, intersectionRect, intersectionRatio);
// Steps 2.10 - 2.15.
if (target->UpdateIntersectionObservation(this, thresholdIndex)) {
QueueIntersectionObserverEntry(target, time,
origin == BrowsingContextOrigin::Different
? Nothing()
: Some(rootBounds),
targetRect, intersectionRect,
intersectionRatio);
}
}
}

View File

@ -502,8 +502,7 @@ void DOMMatrixReadOnly::Stringify(nsAString& aResult, ErrorResult& aRv) {
auto AppendDouble = [&aRv, &cbuf, &matrixStr](double d,
bool isLastItem = false) {
if (!mozilla::IsFinite(d)) {
aRv.ThrowDOMException(
NS_ERROR_DOM_INVALID_STATE_ERR,
aRv.ThrowInvalidStateError(
"Matrix with a non-finite element cannot be stringified.");
return false;
}

View File

@ -9,7 +9,6 @@
#include "AudioChannelService.h"
#include "mozilla/dom/Document.h"
#include "DocumentInlines.h"
#include "mozilla/AnimationComparator.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
@ -63,7 +62,7 @@
#include "nsIObserver.h"
#include "nsIBaseWindow.h"
#include "nsILayoutHistoryState.h"
#include "nsLayoutStylesheetCache.h"
#include "mozilla/GlobalStyleSheetCache.h"
#include "mozilla/css/Loader.h"
#include "mozilla/css/ImageLoader.h"
#include "nsDocShell.h"
@ -86,6 +85,7 @@
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/CSSImportRule.h"
#include "mozilla/dom/CSPDictionariesBinding.h"
#include "mozilla/dom/DOMIntersectionObserver.h"
#include "mozilla/dom/Element.h"
@ -195,8 +195,6 @@
#include "nsIPrompt.h"
#include "nsIPropertyBag2.h"
#include "mozilla/dom/PageTransitionEvent.h"
#include "mozilla/dom/StyleRuleChangeEvent.h"
#include "mozilla/dom/StyleSheetChangeEvent.h"
#include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
#include "nsJSUtils.h"
#include "nsFrameLoader.h"
@ -1193,11 +1191,12 @@ void Document::Shutdown() {
Document::Document(const char* aContentType)
: nsINode(nullptr),
DocumentOrShadowRoot(*this),
DocumentOrShadowRoot(this),
mBlockAllMixedContent(false),
mBlockAllMixedContentPreloads(false),
mUpgradeInsecureRequests(false),
mUpgradeInsecurePreloads(false),
mDontWarnAboutMutationEventsAndAllowSlowDOMMutations(false),
mCharacterSet(WINDOWS_1252_ENCODING),
mCharacterSetSource(0),
mParentDocument(nullptr),
@ -2233,15 +2232,17 @@ size_t Document::FindDocStyleSheetInsertionPoint(const StyleSheet& aSheet) {
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
// lowest index first
int32_t newDocIndex = IndexOfSheet(aSheet);
int32_t newDocIndex = StyleOrderIndexOfSheet(aSheet);
size_t count = mStyleSet->SheetCount(StyleOrigin::Author);
size_t index = 0;
for (; index < count; index++) {
auto* sheet = mStyleSet->SheetAt(StyleOrigin::Author, index);
MOZ_ASSERT(sheet);
int32_t sheetDocIndex = IndexOfSheet(*sheet);
if (sheetDocIndex > newDocIndex) break;
int32_t sheetDocIndex = StyleOrderIndexOfSheet(*sheet);
if (sheetDocIndex > newDocIndex) {
break;
}
// If the sheet is not owned by the document it can be an author
// sheet registered at nsStyleSheetService or an additional author
@ -2263,6 +2264,14 @@ size_t Document::FindDocStyleSheetInsertionPoint(const StyleSheet& aSheet) {
return index;
}
void Document::AppendAdoptedStyleSheet(StyleSheet& aSheet) {
DocumentOrShadowRoot::InsertAdoptedSheetAt(mAdoptedStyleSheets.Length(),
aSheet);
if (aSheet.IsApplicable()) {
AddStyleSheetToStyleSets(&aSheet);
}
}
void Document::RemoveDocStyleSheetsFromStyleSets() {
MOZ_ASSERT(mStyleSetFilled);
// The stylesheets should forget us
@ -2353,7 +2362,7 @@ void Document::FillStyleSetUserAndUASheets() {
// ordering.
// The document will fill in the document sheets when we create the presshell
auto cache = nsLayoutStylesheetCache::Singleton();
auto* cache = GlobalStyleSheetCache::Singleton();
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
MOZ_ASSERT(sheetService,
@ -2428,7 +2437,7 @@ void Document::FillStyleSet() {
void Document::RemoveContentEditableStyleSheets() {
MOZ_ASSERT(IsHTMLOrXHTML());
auto* cache = nsLayoutStylesheetCache::Singleton();
auto* cache = GlobalStyleSheetCache::Singleton();
bool changed = false;
if (mDesignModeSheetAdded) {
mStyleSet->RemoveStyleSheet(StyleOrigin::UserAgent,
@ -2453,7 +2462,7 @@ void Document::AddContentEditableStyleSheetsToStyleSet(bool aDesignMode) {
MOZ_DIAGNOSTIC_ASSERT(mStyleSetFilled,
"Caller should ensure we're being rendered");
auto* cache = nsLayoutStylesheetCache::Singleton();
auto* cache = GlobalStyleSheetCache::Singleton();
bool changed = false;
if (!mContentEditableSheetAdded) {
mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent,
@ -2481,12 +2490,20 @@ void Document::FillStyleSetDocumentSheets() {
MOZ_ASSERT(mStyleSet->SheetCount(StyleOrigin::Author) == 0,
"Style set already has document sheets?");
// Sheets are added in reverse order to avoid worst-case
// time complexity when looking up the index of a sheet
for (StyleSheet* sheet : Reversed(mStyleSheets)) {
if (sheet->IsApplicable()) {
mStyleSet->AddDocStyleSheet(sheet);
}
}
for (StyleSheet* sheet : Reversed(mAdoptedStyleSheets)) {
if (sheet->IsApplicable()) {
mStyleSet->AddDocStyleSheet(sheet);
}
}
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
mStyleSet->AppendStyleSheet(StyleOrigin::Author, sheet);
@ -2516,7 +2533,7 @@ void Document::CompatibilityModeChanged() {
if (mQuirkSheetAdded == NeedsQuirksSheet()) {
return;
}
auto cache = nsLayoutStylesheetCache::Singleton();
auto* cache = GlobalStyleSheetCache::Singleton();
StyleSheet* sheet = cache->QuirkSheet();
if (mQuirkSheetAdded) {
mStyleSet->RemoveStyleSheet(StyleOrigin::UserAgent, sheet);
@ -3526,18 +3543,6 @@ DocumentTimeline* Document::Timeline() {
return mDocumentTimeline;
}
void Document::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations) {
// Hold a strong ref for the root element since Element::GetAnimations() calls
// FlushPendingNotifications() which may destroy the element.
RefPtr<Element> root = GetRootElement();
if (!root) {
return;
}
GetAnimationsOptions options;
options.mSubtree = true;
root->GetAnimations(options, aAnimations);
}
SVGSVGElement* Document::GetSVGRootElement() const {
Element* root = GetRootElement();
if (!root || !root->IsSVGElement(nsGkAtoms::svg)) {
@ -5479,7 +5484,7 @@ Result<nsCOMPtr<nsIURI>, nsresult> Document::ResolveWithBaseURI(
nsCOMPtr<nsIURI> resolvedURI;
MOZ_TRY(
NS_NewURI(getter_AddRefs(resolvedURI), aURI, nullptr, GetDocBaseURI()));
return std::move(resolvedURI);
return resolvedURI;
}
URLExtraData* Document::DefaultStyleAttrURLData() {
@ -6024,39 +6029,6 @@ void Document::ApplicableStylesChanged() {
pc->RestyleManager()->NextRestyleIsForCSSRuleChanges();
}
#define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
do { \
className##Init init; \
init.mBubbles = true; \
init.mCancelable = true; \
init.mStylesheet = aSheet; \
init.memberName = argName; \
\
RefPtr<className> event = \
className::Constructor(this, NS_LITERAL_STRING(type), init); \
event->SetTrusted(true); \
event->SetTarget(this); \
RefPtr<AsyncEventDispatcher> asyncDispatcher = \
new AsyncEventDispatcher(this, event); \
asyncDispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes; \
asyncDispatcher->PostDOMEvent(); \
} while (0);
void Document::NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet) {
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, "StyleSheetAdded",
mDocumentSheet, aDocumentSheet);
}
}
void Document::NotifyStyleSheetRemoved(StyleSheet* aSheet,
bool aDocumentSheet) {
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, "StyleSheetRemoved",
mDocumentSheet, aDocumentSheet);
}
}
void Document::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet) {
if (mStyleSetFilled) {
mStyleSet->RemoveDocStyleSheet(aSheet);
@ -6064,21 +6036,16 @@ void Document::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet) {
}
}
void Document::RemoveStyleSheet(StyleSheet* aSheet) {
MOZ_ASSERT(aSheet);
RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(*aSheet);
void Document::RemoveStyleSheet(StyleSheet& aSheet) {
RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(aSheet);
if (!sheet) {
NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found");
return;
}
if (!mIsGoingAway) {
if (sheet->IsApplicable()) {
RemoveStyleSheetFromStyleSets(sheet);
}
NotifyStyleSheetRemoved(sheet, true);
if (!mIsGoingAway && sheet->IsApplicable()) {
RemoveStyleSheetFromStyleSets(sheet);
}
sheet->ClearAssociatedDocumentOrShadowRoot();
@ -6090,27 +6057,36 @@ void Document::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
if (aSheet.IsApplicable()) {
AddStyleSheetToStyleSets(&aSheet);
}
NotifyStyleSheetAdded(&aSheet, true);
}
void Document::SetStyleSheetApplicableState(StyleSheet* aSheet,
bool aApplicable) {
MOZ_ASSERT(aSheet, "null arg");
void Document::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
const bool applicable = aSheet.IsApplicable();
// If we're actually in the document style sheet list
if (mStyleSheets.IndexOf(aSheet) != mStyleSheets.NoIndex) {
if (aApplicable) {
AddStyleSheetToStyleSets(aSheet);
if (StyleOrderIndexOfSheet(aSheet) >= 0) {
if (applicable) {
AddStyleSheetToStyleSets(&aSheet);
} else {
RemoveStyleSheetFromStyleSets(aSheet);
RemoveStyleSheetFromStyleSets(&aSheet);
}
}
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent,
"StyleSheetApplicableStateChanged", mApplicable,
aApplicable);
StyleSheetApplicableStateChangeEventInit init;
init.mBubbles = true;
init.mCancelable = true;
init.mStylesheet = &aSheet;
init.mApplicable = applicable;
RefPtr<StyleSheetApplicableStateChangeEvent> event =
StyleSheetApplicableStateChangeEvent::Constructor(
this, NS_LITERAL_STRING("StyleSheetApplicableStateChanged"),
init);
event->SetTrusted(true);
event->SetTarget(this);
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->mOnlyChromeDispatch = ChromeOnlyDispatch::eYes;
asyncDispatcher->PostDOMEvent();
}
if (!mSSApplicableStateNotificationPending) {
@ -6206,9 +6182,13 @@ nsresult Document::LoadAdditionalStyleSheet(additionalSheetType aType,
nsresult Document::AddAdditionalStyleSheet(additionalSheetType aType,
StyleSheet* aSheet) {
if (mAdditionalSheets[aType].Contains(aSheet)) return NS_ERROR_INVALID_ARG;
if (mAdditionalSheets[aType].Contains(aSheet)) {
return NS_ERROR_INVALID_ARG;
}
if (!aSheet->IsApplicable()) return NS_ERROR_INVALID_ARG;
if (!aSheet->IsApplicable()) {
return NS_ERROR_INVALID_ARG;
}
mAdditionalSheets[aType].AppendElement(aSheet);
@ -6216,10 +6196,6 @@ nsresult Document::AddAdditionalStyleSheet(additionalSheetType aType,
mStyleSet->AppendStyleSheet(ConvertAdditionalSheetType(aType), aSheet);
ApplicableStylesChanged();
}
// Passing false, so documet.styleSheets.length will not be affected by
// these additional sheets.
NotifyStyleSheetAdded(aSheet, false);
return NS_OK;
}
@ -6242,10 +6218,6 @@ void Document::RemoveAdditionalStyleSheet(additionalSheetType aType,
ApplicableStylesChanged();
}
}
// Passing false, so documet.styleSheets.length will not be affected by
// these additional sheets.
NotifyStyleSheetRemoved(sheetRef, false);
sheetRef->ClearAssociatedDocumentOrShadowRoot();
}
}
@ -6967,40 +6939,33 @@ void Document::ContentStateChanged(nsIContent* aContent,
(this, aContent, aStateMask));
}
void Document::StyleRuleChanged(StyleSheet* aSheet, css::Rule* aStyleRule) {
ApplicableStylesChanged();
void Document::RuleChanged(StyleSheet& aSheet, css::Rule* aRule) {
if (aSheet.IsApplicable()) {
ApplicableStylesChanged();
}
}
if (!StyleSheetChangeEventsEnabled()) {
void Document::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
if (aRule.IsIncompleteImportRule()) {
return;
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, "StyleRuleChanged", mRule,
aStyleRule);
}
void Document::StyleRuleAdded(StyleSheet* aSheet, css::Rule* aStyleRule) {
ApplicableStylesChanged();
if (!StyleSheetChangeEventsEnabled()) {
return;
if (aSheet.IsApplicable()) {
ApplicableStylesChanged();
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, "StyleRuleAdded", mRule,
aStyleRule);
}
void Document::StyleRuleRemoved(StyleSheet* aSheet, css::Rule* aStyleRule) {
ApplicableStylesChanged();
if (!StyleSheetChangeEventsEnabled()) {
return;
void Document::ImportRuleLoaded(dom::CSSImportRule& aRule, StyleSheet& aSheet) {
if (aSheet.IsApplicable()) {
ApplicableStylesChanged();
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, "StyleRuleRemoved", mRule,
aStyleRule);
}
#undef DO_STYLESHEET_NOTIFICATION
void Document::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
if (aSheet.IsApplicable()) {
ApplicableStylesChanged();
}
}
static Element* GetCustomContentContainer(PresShell* aPresShell) {
if (!aPresShell || !aPresShell->GetCanvasFrame()) {
@ -7545,7 +7510,7 @@ already_AddRefed<nsINode> Document::ImportNode(nsINode& aNode, bool aDeep,
case CDATA_SECTION_NODE:
case COMMENT_NODE:
case DOCUMENT_TYPE_NODE: {
return imported->Clone(aDeep, mNodeInfoManager, nullptr, rv);
return imported->Clone(aDeep, mNodeInfoManager, rv);
}
default: {
NS_WARNING("Don't know how to clone this nodetype for importNode.");
@ -8557,7 +8522,7 @@ Document* Document::Open(const Optional<nsAString>& /* unused */,
aError.Throw(rv);
return nullptr;
}
newURI = noFragmentURI.forget();
newURI = std::move(noFragmentURI);
}
// UpdateURLAndHistory might do various member-setting, so make sure we're
@ -8668,35 +8633,6 @@ void Document::Close(ErrorResult& rv) {
rv = (static_cast<nsHtml5Parser*>(mParser.get()))
->Parse(EmptyString(), nullptr, true);
--mWriteLevel;
// Even if that Parse() call failed, do the rest of this method
// XXX Make sure that all the document.written content is
// reflowed. We should remove this call once we change
// Document::OpenCommon() so that it completely destroys the
// earlier document's content and frame hierarchy. Right now, it
// re-uses the earlier document's root content object and
// corresponding frame objects. These re-used frame objects think
// that they have already been reflowed, so they drop initial
// reflows. For certain cases of document.written content, like a
// frameset document, the dropping of the initial reflow means
// that we end up in document.close() without appended any reflow
// commands to the reflow queue and, consequently, without adding
// the dummy layout request to the load group. Since the dummy
// layout request is not added to the load group, the onload
// handler of the frameset fires before the frames get reflowed
// and loaded. That is the long explanation for why we need this
// one line of code here!
// XXXbz as far as I can tell this may not be needed anymore; all
// the testcases in bug 57636 pass without this line... Leaving
// it be for now, though. In any case, there's no reason to do
// this if we have no presshell, since in that case none of the
// above about reusing frames applies.
//
// XXXhsivonen keeping this around for bug 577508 / 253951 still :-(
if (GetPresShell()) {
FlushPendingNotifications(FlushType::Layout);
}
}
void Document::WriteCommon(const Sequence<nsString>& aText,
@ -9083,41 +9019,16 @@ nsINode* Document::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv) {
}
}
nsCOMArray<nsINode> nodesWithProperties;
adoptedNode->Adopt(sameDocument ? nullptr : mNodeInfoManager, newScope,
nodesWithProperties, rv);
adoptedNode->Adopt(sameDocument ? nullptr : mNodeInfoManager, newScope, rv);
if (rv.Failed()) {
// Disconnect all nodes from their parents, since some have the old document
// as their ownerDocument and some have this as their ownerDocument.
nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
if (!sameDocument && oldDocument) {
for (nsINode* node : nodesWithProperties) {
// Remove all properties.
oldDocument->PropertyTable().DeleteAllPropertiesFor(node);
}
}
return nullptr;
}
if (!sameDocument && oldDocument) {
nsPropertyTable& oldTable = oldDocument->PropertyTable();
nsPropertyTable& newTable = PropertyTable();
for (nsINode* node : nodesWithProperties) {
rv = oldTable.TransferOrDeleteAllPropertiesFor(node, newTable);
}
if (rv.Failed()) {
// Disconnect all nodes from their parents.
nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
return nullptr;
}
}
NS_ASSERTION(adoptedNode->OwnerDoc() == this,
"Should still be in the document we just got adopted into");
MOZ_ASSERT(adoptedNode->OwnerDoc() == this,
"Should still be in the document we just got adopted into");
return adoptedNode;
}
@ -10236,6 +10147,10 @@ void Document::Destroy() {
// leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
// tearing down all those frame trees right now is the right thing to do.
mExternalResourceMap.Shutdown();
// Manually break cycles via promise's global object pointer.
mReadyForIdle = nullptr;
mOrientationPendingPromise = nullptr;
}
void Document::RemovedFromDocShell() {
@ -10707,8 +10622,8 @@ void Document::MutationEventDispatched(nsINode* aTarget) {
nsINode* commonAncestor = nullptr;
int32_t realTargetCount = realTargets.Count();
for (int32_t j = 0; j < realTargetCount; ++j) {
commonAncestor =
nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]);
commonAncestor = nsContentUtils::GetClosestCommonInclusiveAncestor(
possibleTarget, realTargets[j]);
if (commonAncestor) {
realTargets.ReplaceObjectAt(commonAncestor, j);
break;
@ -11432,7 +11347,7 @@ static already_AddRefed<nsPIDOMWindowOuter> FindTopWindowForElement(
// Trying to find the top window (equivalent to window.top).
if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetInProcessTop()) {
window = top.forget();
window = std::move(top);
}
return window.forget();
}
@ -11443,11 +11358,11 @@ static already_AddRefed<nsPIDOMWindowOuter> FindTopWindowForElement(
*/
class nsAutoFocusEvent : public Runnable {
public:
explicit nsAutoFocusEvent(already_AddRefed<Element>&& aElement,
already_AddRefed<nsPIDOMWindowOuter>&& aTopWindow)
explicit nsAutoFocusEvent(nsCOMPtr<Element>&& aElement,
nsCOMPtr<nsPIDOMWindowOuter>&& aTopWindow)
: mozilla::Runnable("nsAutoFocusEvent"),
mElement(aElement),
mTopWindow(aTopWindow) {}
mElement(std::move(aElement)),
mTopWindow(std::move(aTopWindow)) {}
NS_IMETHOD Run() override {
nsCOMPtr<nsPIDOMWindowOuter> currentTopWindow =
@ -11520,7 +11435,7 @@ void Document::TriggerAutoFocus() {
}
nsCOMPtr<nsIRunnable> event =
new nsAutoFocusEvent(autoFocusElement.forget(), topWindow.forget());
new nsAutoFocusEvent(std::move(autoFocusElement), topWindow.forget());
nsresult rv = NS_DispatchToCurrentThread(event.forget());
NS_ENSURE_SUCCESS_VOID(rv);
}
@ -12269,6 +12184,11 @@ already_AddRefed<nsIURI> Document::GetMozDocumentURIIfNotForErrorPages() {
}
Promise* Document::GetDocumentReadyForIdle(ErrorResult& aRv) {
if (mIsGoingAway) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
if (!mReadyForIdle) {
nsIGlobalObject* global = GetScopeObject();
if (!global) {
@ -13118,14 +13038,6 @@ void Document::RemoteFrameFullscreenReverted() {
RestorePreviousFullscreenState(std::move(exit));
}
/* static */
bool Document::IsUnprefixedFullscreenEnabled(JSContext* aCx,
JSObject* aObject) {
MOZ_ASSERT(NS_IsMainThread());
return nsContentUtils::IsSystemCaller(aCx) ||
StaticPrefs::full_screen_api_unprefix_enabled();
}
static bool HasFullscreenSubDocument(Document& aDoc) {
uint32_t count = CountFullscreenSubDocuments(aDoc);
NS_ASSERTION(count <= 1,
@ -13137,17 +13049,16 @@ static bool HasFullscreenSubDocument(Document& aDoc) {
// in the given document. Returns a static string indicates the reason
// why it is not enabled otherwise.
static const char* GetFullscreenError(Document* aDoc, CallerType aCallerType) {
bool apiEnabled = StaticPrefs::full_screen_api_enabled();
if (apiEnabled && aCallerType == CallerType::System) {
if (!StaticPrefs::full_screen_api_enabled()) {
return "FullscreenDeniedDisabled";
}
if (aCallerType == CallerType::System) {
// Chrome code can always use the fullscreen API, provided it's not
// explicitly disabled.
return nullptr;
}
if (!apiEnabled) {
return "FullscreenDeniedDisabled";
}
if (!aDoc->IsVisible()) {
return "FullscreenDeniedHidden";
}
@ -13448,8 +13359,17 @@ bool Document::FullscreenEnabled(CallerType aCallerType) {
return !GetFullscreenError(this, aCallerType);
}
void Document::SetOrientationPendingPromise(Promise* aPromise) {
void Document::ClearOrientationPendingPromise() {
mOrientationPendingPromise = nullptr;
}
bool Document::SetOrientationPendingPromise(Promise* aPromise) {
if (mIsGoingAway) {
return false;
}
mOrientationPendingPromise = aPromise;
return true;
}
static void DispatchPointerLockChange(Document* aTarget) {
@ -13813,8 +13733,15 @@ void Document::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
// Lumping in the loader with the style-sheets size is not ideal,
// but most of the things in there are in fact stylesheets, so it
// doesn't seem worthwhile to separate it out.
aWindowSizes.mLayoutStyleSheetsSize +=
CSSLoader()->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
// This can be null if we've already been unlinked.
if (mCSSLoader) {
aWindowSizes.mLayoutStyleSheetsSize +=
mCSSLoader->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
}
if (mResizeObserverController) {
mResizeObserverController->AddSizeOfIncludingThis(aWindowSizes);
}
aWindowSizes.mDOMOtherSize += mAttrStyleSheet
? mAttrStyleSheet->DOMSizeOfIncludingThis(
@ -14701,12 +14628,19 @@ FlashClassification Document::DocumentFlashClassification() {
return mFlashClassification;
}
void Document::AddResizeObserver(ResizeObserver* aResizeObserver) {
void Document::AddResizeObserver(ResizeObserver& aObserver) {
if (!mResizeObserverController) {
mResizeObserverController = MakeUnique<ResizeObserverController>(this);
}
mResizeObserverController->AddResizeObserver(aObserver);
}
mResizeObserverController->AddResizeObserver(aResizeObserver);
void Document::RemoveResizeObserver(ResizeObserver& aObserver) {
MOZ_DIAGNOSTIC_ASSERT(mResizeObserverController, "No controller?");
if (MOZ_UNLIKELY(!mResizeObserverController)) {
return;
}
mResizeObserverController->RemoveResizeObserver(aObserver);
}
PermissionDelegateHandler* Document::GetPermissionDelegateHandler() {
@ -14714,6 +14648,11 @@ PermissionDelegateHandler* Document::GetPermissionDelegateHandler() {
mPermissionDelegateHandler =
mozilla::MakeAndAddRef<PermissionDelegateHandler>(this);
}
if (!mPermissionDelegateHandler->Initialize()) {
mPermissionDelegateHandler = nullptr;
}
return mPermissionDelegateHandler;
}
@ -15086,7 +15025,7 @@ already_AddRefed<Promise> Document::RequestStorageAccess(ErrorResult& aRv) {
ContentPermissionRequestBase::DelayedTaskType::Request);
});
return p.forget();
return std::move(p);
};
AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(
NodePrincipal(), inner, AntiTrackingCommon::eStorageAccessAPI,
@ -15371,7 +15310,7 @@ void Document::RecomputeLanguageFromCharset() {
}
mMayNeedFontPrefsUpdate = true;
mLanguageFromCharset = language.forget();
mLanguageFromCharset = std::move(language);
}
nsICookieSettings* Document::CookieSettings() {
@ -15479,5 +15418,34 @@ Document::RecomputeContentBlockingAllowListPrincipal(
return copy.forget();
}
// https://wicg.github.io/construct-stylesheets/#dom-documentorshadowroot-adoptedstylesheets
void Document::SetAdoptedStyleSheets(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv) {
// Step 1 is a variable declaration
// 2.1 Check if all sheets are constructed, else throw NotAllowedError
// 2.2 Check if all sheets' constructor documents match the
// DocumentOrShadowRoot's node document, else throw NotAlloweError
EnsureAdoptedSheetsAreValid(aAdoptedStyleSheets, aRv);
if (aRv.Failed()) {
return;
}
// 3. Set the adopted style sheets to the new sheets
for (const RefPtr<StyleSheet>& sheet : mAdoptedStyleSheets) {
if (sheet->IsApplicable()) {
RemoveStyleSheetFromStyleSets(sheet);
}
sheet->RemoveAdopter(*this);
}
mAdoptedStyleSheets.ClearAndRetainStorage();
mAdoptedStyleSheets.SetCapacity(aAdoptedStyleSheets.Length());
for (const OwningNonNull<StyleSheet>& sheet : aAdoptedStyleSheets) {
sheet->AddAdopter(*this);
AppendAdoptedStyleSheet(*sheet);
}
}
} // namespace dom
} // namespace mozilla

View File

@ -37,6 +37,7 @@
#include "nsStubMutationObserver.h"
#include "nsTHashtable.h" // for member
#include "nsURIHashKey.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/WeakPtr.h"
#include "Units.h"
#include "nsContentListDeclarations.h"
@ -54,7 +55,6 @@
#include "mozilla/LinkedList.h"
#include "mozilla/NotNull.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include <bitset> // for member
@ -129,7 +129,7 @@ struct nsFont;
namespace mozilla {
class AbstractThread;
class CSSStyleSheet;
class StyleSheet;
class EditorCommand;
class Encoding;
class ErrorResult;
@ -137,9 +137,11 @@ class EventStates;
class EventListenerManager;
class FullscreenExit;
class FullscreenRequest;
struct LangGroupFontPrefs;
class PendingAnimationTracker;
class PresShell;
class ServoStyleSet;
enum class StyleOrigin : uint8_t;
class SMILAnimationController;
enum class StyleCursorKind : uint8_t;
template <typename>
@ -153,7 +155,6 @@ class Rule;
} // namespace css
namespace dom {
class Animation;
class AnonymousContent;
class Attr;
class BoxObject;
@ -163,6 +164,7 @@ class ClientInfo;
class ClientState;
class CDATASection;
class Comment;
class CSSImportRule;
struct CustomElementDefinition;
class DocGroup;
class DocumentL10n;
@ -1863,10 +1865,6 @@ class Document : public nsINode,
* Style sheets are ordered, most significant last.
*/
StyleSheetList* StyleSheets() {
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
}
void InsertSheetAt(size_t aIndex, StyleSheet&);
/**
@ -1883,13 +1881,13 @@ class Document : public nsINode,
/**
* Remove a stylesheet from the document
*/
void RemoveStyleSheet(StyleSheet* aSheet);
void RemoveStyleSheet(StyleSheet&);
/**
* Notify the document that the applicable state of the sheet changed
* and that observers should be notified and style sets updated
*/
void SetStyleSheetApplicableState(StyleSheet* aSheet, bool aApplicable);
void StyleSheetApplicableStateChanged(StyleSheet&);
enum additionalSheetType {
eAgentSheet,
@ -1908,6 +1906,8 @@ class Document : public nsINode,
return mAdditionalSheets[eAuthorSheet].SafeElementAt(0);
}
void AppendAdoptedStyleSheet(StyleSheet& aSheet);
/**
* Returns the index that aSheet should be inserted at to maintain document
* ordering.
@ -2162,7 +2162,8 @@ class Document : public nsINode,
OrientationType CurrentOrientationType() const {
return mCurrentOrientationType;
}
void SetOrientationPendingPromise(Promise* aPromise);
void ClearOrientationPendingPromise();
bool SetOrientationPendingPromise(Promise* aPromise);
Promise* GetOrientationPendingPromise() const {
return mOrientationPendingPromise;
}
@ -2235,9 +2236,11 @@ class Document : public nsINode,
// Observation hooks for style data to propagate notifications
// to document observers
void StyleRuleChanged(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
void StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
void StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule);
void RuleChanged(StyleSheet&, css::Rule*);
void RuleAdded(StyleSheet&, css::Rule&);
void RuleRemoved(StyleSheet&, css::Rule&);
void SheetCloned(StyleSheet&) {}
void ImportRuleLoaded(CSSImportRule&, StyleSheet&);
/**
* Flush notifications for this document and its parent documents
@ -3168,8 +3171,6 @@ class Document : public nsINode,
DocumentTimeline* Timeline();
LinkedList<DocumentTimeline>& Timelines() { return mTimelines; }
void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
SVGSVGElement* GetSVGRootElement() const;
struct FrameRequest {
@ -3547,7 +3548,6 @@ class Document : public nsINode,
mozilla::dom::HTMLAllCollection* All();
static bool IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject);
static bool DocumentSupportsL10n(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(CallerType aCallerType);
@ -3658,6 +3658,15 @@ class Document : public nsINode,
void SetTooltipNode(nsINode* aNode) { /* do nothing */
}
bool DontWarnAboutMutationEventsAndAllowSlowDOMMutations() {
return mDontWarnAboutMutationEventsAndAllowSlowDOMMutations;
}
void SetDontWarnAboutMutationEventsAndAllowSlowDOMMutations(
bool aDontWarnAboutMutationEventsAndAllowSlowDOMMutations) {
mDontWarnAboutMutationEventsAndAllowSlowDOMMutations =
aDontWarnAboutMutationEventsAndAllowSlowDOMMutations;
}
// ParentNode
nsIHTMLCollection* Children();
uint32_t ChildElementCount();
@ -3823,7 +3832,8 @@ class Document : public nsINode,
FlashClassification DocumentFlashClassification();
// ResizeObserver usage.
void AddResizeObserver(ResizeObserver* aResizeObserver);
void AddResizeObserver(ResizeObserver&);
void RemoveResizeObserver(ResizeObserver&);
void ScheduleResizeObserversNotification() const;
// Getter for PermissionDelegateHandler. Performs lazy initialization.
@ -4050,6 +4060,10 @@ class Document : public nsINode,
static bool AutomaticStorageAccessCanBeGranted(nsIPrincipal* aPrincipal);
void SetAdoptedStyleSheets(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv);
protected:
void DoUpdateSVGUseElementShadowTrees();
@ -4106,8 +4120,6 @@ class Document : public nsINode,
void RemoveContentEditableStyleSheets();
void AddStyleSheetToStyleSets(StyleSheet* aSheet);
void RemoveStyleSheetFromStyleSets(StyleSheet* aSheet);
void NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet);
void NotifyStyleSheetRemoved(StyleSheet* aSheet, bool aDocumentSheet);
void NotifyStyleSheetApplicableStateChanged();
// Just like EnableStyleSheetsForSet, but doesn't check whether
// aSheetSet is null and allows the caller to control whether to set
@ -4337,6 +4349,8 @@ class Document : public nsINode,
bool mUpgradeInsecureRequests;
bool mUpgradeInsecurePreloads;
bool mDontWarnAboutMutationEventsAndAllowSlowDOMMutations;
WeakPtr<nsDocShell> mDocumentContainer;
NotNull<const Encoding*> mCharacterSet;
@ -4431,7 +4445,7 @@ class Document : public nsINode,
UniquePtr<ResizeObserverController> mResizeObserverController;
// Permission Delegate Handler, lazily-initialized in
// PermissionDelegateHandler
// GetPermissionDelegateHandler
RefPtr<PermissionDelegateHandler> mPermissionDelegateHandler;
// True if BIDI is enabled.
@ -5086,6 +5100,8 @@ class Document : public nsINode,
nsCOMPtr<nsIRunnable> mMaybeEndOutermostXBLUpdateRunner;
nsCOMPtr<nsIRequest> mOnloadBlocker;
// Gecko-internal sheets used for extensions and such.
// Exposed to privileged script via nsIDOMWindowUtils.loadSheet.
nsTArray<RefPtr<StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
// Member to store out last-selected stylesheet set.

View File

@ -3,12 +3,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DocumentOrShadowRoot.h"
#include "mozilla/AnimationComparator.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/StyleSheetList.h"
#include "nsTHashtable.h"
#include "nsFocusManager.h"
#include "nsIRadioVisitor.h"
#include "nsIFormControl.h"
@ -19,12 +22,15 @@
namespace mozilla {
namespace dom {
DocumentOrShadowRoot::DocumentOrShadowRoot(
mozilla::dom::ShadowRoot& aShadowRoot)
: mAsNode(aShadowRoot), mKind(Kind::ShadowRoot) {}
DocumentOrShadowRoot::DocumentOrShadowRoot(ShadowRoot* aShadowRoot)
: mAsNode(aShadowRoot), mKind(Kind::ShadowRoot) {
MOZ_ASSERT(mAsNode);
}
DocumentOrShadowRoot::DocumentOrShadowRoot(Document& aDoc)
: mAsNode(aDoc), mKind(Kind::Document) {}
DocumentOrShadowRoot::DocumentOrShadowRoot(Document* aDoc)
: mAsNode(aDoc), mKind(Kind::Document) {
MOZ_ASSERT(mAsNode);
}
void DocumentOrShadowRoot::AddSizeOfOwnedSheetArrayExcludingThis(
nsWindowSizes& aSizes, const nsTArray<RefPtr<StyleSheet>>& aSheets) const {
@ -57,11 +63,11 @@ DocumentOrShadowRoot::~DocumentOrShadowRoot() {
}
}
StyleSheetList& DocumentOrShadowRoot::EnsureDOMStyleSheets() {
StyleSheetList* DocumentOrShadowRoot::StyleSheets() {
if (!mDOMStyleSheets) {
mDOMStyleSheets = new StyleSheetList(*this);
}
return *mDOMStyleSheets;
return mDOMStyleSheets;
}
void DocumentOrShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
@ -70,6 +76,11 @@ void DocumentOrShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
mStyleSheets.InsertElementAt(aIndex, &aSheet);
}
void DocumentOrShadowRoot::InsertAdoptedSheetAt(size_t aIndex,
StyleSheet& aSheet) {
mAdoptedStyleSheets.InsertElementAt(aIndex, &aSheet);
}
already_AddRefed<StyleSheet> DocumentOrShadowRoot::RemoveSheet(
StyleSheet& aSheet) {
auto index = mStyleSheets.IndexOf(&aSheet);
@ -82,6 +93,39 @@ already_AddRefed<StyleSheet> DocumentOrShadowRoot::RemoveSheet(
return sheet.forget();
}
// https://wicg.github.io/construct-stylesheets/#dom-documentorshadowroot-adoptedstylesheets
void DocumentOrShadowRoot::EnsureAdoptedSheetsAreValid(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv) {
nsTHashtable<nsPtrHashKey<const StyleSheet>> set(
aAdoptedStyleSheets.Length());
for (const OwningNonNull<StyleSheet>& sheet : aAdoptedStyleSheets) {
// 2.1 Check if all sheets are constructed, else throw NotAllowedError
if (!sheet->IsConstructed()) {
return aRv.ThrowNotAllowedError(
"Each adopted style sheet must be created through the Constructable "
"StyleSheets API");
}
// 2.2 Check if all sheets' constructor documents match the
// DocumentOrShadowRoot's node document, else throw NotAlloweError
if (!sheet->ConstructorDocumentMatches(AsNode().OwnerDoc())) {
return aRv.ThrowNotAllowedError(
"Each adopted style sheet's constructor document must match the "
"document or shadow root's node document");
}
// FIXME(nordzilla): This is temporary code to disallow duplicate sheets.
// This exists to ensure that the fuzzers aren't blocked.
// This code will eventually be removed.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1617302
if (!set.EnsureInserted(sheet.get())) {
return aRv.ThrowNotAllowedError(
"Temporarily disallowing duplicate stylesheets.");
}
}
}
Element* DocumentOrShadowRoot::GetElementById(const nsAString& aElementId) {
if (MOZ_UNLIKELY(aElementId.IsEmpty())) {
nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
@ -110,7 +154,7 @@ already_AddRefed<nsContentList> DocumentOrShadowRoot::GetElementsByTagNameNS(
already_AddRefed<nsContentList> DocumentOrShadowRoot::GetElementsByTagNameNS(
const nsAString& aNamespaceURI, const nsAString& aLocalName,
mozilla::ErrorResult& aResult) {
ErrorResult& aResult) {
int32_t nameSpaceId = kNameSpaceID_Wildcard;
if (!aNamespaceURI.EqualsLiteral("*")) {
@ -449,6 +493,31 @@ struct nsRadioGroupStruct {
bool mGroupSuffersFromValueMissing;
};
void DocumentOrShadowRoot::GetAnimations(
nsTArray<RefPtr<Animation>>& aAnimations) {
// As with Element::GetAnimations we initially flush style here.
// This should ensure that there are no subsequent changes to the tree
// structure while iterating over the children below.
if (Document* doc = AsNode().GetComposedDoc()) {
doc->FlushPendingNotifications(
ChangesToFlush(FlushType::Style, false /* flush animations */));
}
GetAnimationsOptions options;
options.mSubtree = true;
for (RefPtr<nsIContent> child = AsNode().GetFirstChild(); child;
child = child->GetNextSibling()) {
if (RefPtr<Element> element = Element::FromNode(child)) {
nsTArray<RefPtr<Animation>> result;
element->GetAnimations(options, result, Element::Flush::No);
aAnimations.AppendElements(std::move(result));
}
}
aAnimations.Sort(AnimationPtrComparator<RefPtr<Animation>>());
}
nsresult DocumentOrShadowRoot::WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent) {
@ -583,32 +652,56 @@ nsRadioGroupStruct* DocumentOrShadowRoot::GetRadioGroup(
nsRadioGroupStruct* DocumentOrShadowRoot::GetOrCreateRadioGroup(
const nsAString& aName) {
return mRadioGroups.LookupForAdd(aName).OrInsert(
[]() { return new nsRadioGroupStruct(); });
return mRadioGroups.LookupForAdd(aName)
.OrInsert([]() { return new nsRadioGroupStruct(); })
.get();
}
int32_t DocumentOrShadowRoot::StyleOrderIndexOfSheet(
const StyleSheet& aSheet) const {
if (aSheet.IsConstructed()) {
int32_t index = mAdoptedStyleSheets.IndexOf(&aSheet);
return (index < 0) ? index : index + SheetCount();
}
return mStyleSheets.IndexOf(&aSheet);
}
void DocumentOrShadowRoot::GetAdoptedStyleSheets(
nsTArray<RefPtr<StyleSheet>>& aAdoptedStyleSheets) const {
aAdoptedStyleSheets = mAdoptedStyleSheets;
}
void DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
nsCycleCollectionTraversalCallback& cb) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
for (StyleSheet* sheet : tmp->mStyleSheets) {
if (!sheet->IsApplicable()) {
continue;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdoptedStyleSheets)
auto NoteSheets = [tmp, &cb = cb](nsTArray<RefPtr<StyleSheet>>& sheetList) {
for (StyleSheet* sheet : sheetList) {
if (!sheet->IsApplicable()) {
continue;
}
// The style set or mServoStyles keep more references to it if the sheet
// is applicable.
if (tmp->mKind == Kind::ShadowRoot) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
cb.NoteXPCOMChild(sheet);
} else if (tmp->AsNode().AsDocument()->StyleSetFilled()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mStyleSet->mRawSet.stylist.stylesheets.author[i]");
cb.NoteXPCOMChild(sheet);
}
}
// The style set or mServoStyles keep more references to it if the sheet is
// applicable.
if (tmp->mKind == Kind::ShadowRoot) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
cb.NoteXPCOMChild(sheet);
} else if (tmp->AsNode().AsDocument()->StyleSetFilled()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mStyleSet->mRawSet.stylist.stylesheets.author[i]");
cb.NoteXPCOMChild(sheet);
}
}
};
NoteSheets(tmp->mStyleSheets);
NoteSheets(tmp->mAdoptedStyleSheets);
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
iter.Get()->Traverse(&cb);
}
for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
nsRadioGroupStruct* radioGroup = iter.UserData();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
@ -625,7 +718,11 @@ void DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
}
void DocumentOrShadowRoot::Unlink(DocumentOrShadowRoot* tmp) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets);
for (RefPtr<StyleSheet>& sheet : tmp->mAdoptedStyleSheets) {
sheet->RemoveAdopter(*tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAdoptedStyleSheets);
tmp->mIdentifierMap.Clear();
tmp->mRadioGroups.Clear();
}

View File

@ -19,16 +19,22 @@ class nsIRadioVisitor;
class nsWindowSizes;
namespace mozilla {
class ErrorResult;
class StyleSheet;
class ErrorResult;
namespace dom {
class Animation;
class Element;
class Document;
class DocumentOrShadowRoot;
class HTMLInputElement;
struct nsRadioGroupStruct;
class StyleSheetList;
class ShadowRoot;
template <typename T>
class Sequence;
/**
* A class meant to be shared by ShadowRoot and Document, that holds a list of
@ -44,17 +50,20 @@ class DocumentOrShadowRoot {
};
public:
explicit DocumentOrShadowRoot(Document&);
explicit DocumentOrShadowRoot(ShadowRoot&);
// These should always be non-null, but can't use a reference because
// dereferencing `this` on initializer lists is UB, apparently, see
// bug 1596499.
explicit DocumentOrShadowRoot(Document*);
explicit DocumentOrShadowRoot(ShadowRoot*);
// Unusual argument naming is because of cycle collection macros.
static void Traverse(DocumentOrShadowRoot* tmp,
nsCycleCollectionTraversalCallback& cb);
static void Unlink(DocumentOrShadowRoot* tmp);
nsINode& AsNode() { return mAsNode; }
nsINode& AsNode() { return *mAsNode; }
const nsINode& AsNode() const { return mAsNode; }
const nsINode& AsNode() const { return *mAsNode; }
StyleSheet* SheetAt(size_t aIndex) const {
return mStyleSheets.SafeElementAt(aIndex);
@ -62,11 +71,20 @@ class DocumentOrShadowRoot {
size_t SheetCount() const { return mStyleSheets.Length(); }
int32_t IndexOfSheet(const StyleSheet& aSheet) const {
return mStyleSheets.IndexOf(&aSheet);
}
size_t AdoptedSheetCount() const { return mAdoptedStyleSheets.Length(); }
StyleSheetList& EnsureDOMStyleSheets();
/**
* Returns an index for the sheet in relative style order.
* If there are non-applicable sheets, then this index may
* not match 1:1 with the sheet's actual index in the style set.
*
* Handles sheets from both mStyleSheets and mAdoptedStyleSheets
*/
int32_t StyleOrderIndexOfSheet(const StyleSheet& aSheet) const;
StyleSheetList* StyleSheets();
void GetAdoptedStyleSheets(nsTArray<RefPtr<StyleSheet>>&) const;
Element* GetElementById(const nsAString& aElementId);
@ -176,6 +194,10 @@ class DocumentOrShadowRoot {
void ReportEmptyGetElementByIdArg();
// Web Animations
MOZ_CAN_RUN_SCRIPT
void GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations);
// nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
bool aFlushContent);
@ -201,6 +223,11 @@ class DocumentOrShadowRoot {
// Returns the reference to the sheet, if found in mStyleSheets.
already_AddRefed<StyleSheet> RemoveSheet(StyleSheet& aSheet);
void InsertSheetAt(size_t aIndex, StyleSheet& aSheet);
void InsertAdoptedSheetAt(size_t aIndex, StyleSheet& aSheet);
void EnsureAdoptedSheetsAreValid(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv);
void AddSizeOfExcludingThis(nsWindowSizes&) const;
void AddSizeOfOwnedSheetArrayExcludingThis(
@ -216,6 +243,10 @@ class DocumentOrShadowRoot {
nsTArray<RefPtr<StyleSheet>> mStyleSheets;
RefPtr<StyleSheetList> mDOMStyleSheets;
// Style sheets that are adopted by assinging to the `adoptedStyleSheets`
// WebIDL atribute. These can only be constructed stylesheets.
nsTArray<RefPtr<StyleSheet>> mAdoptedStyleSheets;
/*
* mIdentifierMap works as follows for IDs:
* 1) Attribute changes affect the table immediately (removing and adding
@ -228,7 +259,9 @@ class DocumentOrShadowRoot {
nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
nsINode& mAsNode;
// Always non-null, see comment in the constructor as to why a pointer instead
// of a reference.
nsINode* mAsNode;
const Kind mKind;
};

View File

@ -2379,16 +2379,16 @@ nsresult Element::SetAttr(int32_t aNamespaceID, nsAtom* aName, nsAtom* aPrefix,
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
if (aNotify) {
MutationObservers::NotifyAttributeWillChange(this, aNamespaceID, aName,
modType);
}
// Hold a script blocker while calling ParseAttribute since that can call
// out to id-observers
Document* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, aNotify);
if (aNotify) {
MutationObservers::NotifyAttributeWillChange(this, aNamespaceID, aName,
modType);
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
@ -2426,6 +2426,9 @@ nsresult Element::SetParsedAttr(int32_t aNamespaceID, nsAtom* aName,
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
}
Document* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, aNotify);
if (aNotify) {
MutationObservers::NotifyAttributeWillChange(this, aNamespaceID, aName,
modType);
@ -2436,8 +2439,6 @@ nsresult Element::SetParsedAttr(int32_t aNamespaceID, nsAtom* aName,
PreIdMaybeChange(aNamespaceID, aName, &value);
Document* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, aNotify);
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
oldValueSet ? &oldValue : nullptr, aParsedValue,
nullptr, modType, hasListeners, aNotify,
@ -2518,31 +2519,34 @@ nsresult Element::SetAttrAndNotify(
}
}
CustomElementDefinition* definition = GetCustomElementDefinition();
// Only custom element which is in `custom` state could get the
// CustomElementDefinition.
if (definition && definition->IsInObservedAttributeList(aName)) {
RefPtr<nsAtom> 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();
const CustomElementData* data = GetCustomElementData();
if (data && data->mState == CustomElementData::State::eCustom) {
CustomElementDefinition* definition = data->GetCustomElementDefinition();
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
if (definition->IsInObservedAttributeList(aName)) {
RefPtr<nsAtom> 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();
}
RefPtr<nsAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
LifecycleCallbackArgs args = {nsDependentAtomString(aName),
aModType == MutationEvent_Binding::ADDITION
? VoidString()
: nsDependentAtomString(oldValueAtom),
nsDependentAtomString(newValueAtom),
(ns.IsEmpty() ? VoidString() : ns)};
nsContentUtils::EnqueueLifecycleCallback(
Document::eAttributeChanged, this, &args, nullptr, definition);
}
RefPtr<nsAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
LifecycleCallbackArgs args = {nsDependentAtomString(aName),
aModType == MutationEvent_Binding::ADDITION
? VoidString()
: nsDependentAtomString(oldValueAtom),
nsDependentAtomString(newValueAtom),
(ns.IsEmpty() ? VoidString() : ns)};
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
&args, nullptr, definition);
}
if (aCallAfterSetAttr) {
@ -2710,19 +2714,22 @@ void Element::PostIdMaybeChange(int32_t aNamespaceID, nsAtom* aName,
nsresult Element::OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValueOrString& aValue,
bool aNotify) {
// Only custom element which is in `custom` state could get the
// CustomElementDefinition.
CustomElementDefinition* definition = GetCustomElementDefinition();
if (definition && definition->IsInObservedAttributeList(aName)) {
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
const CustomElementData* data = GetCustomElementData();
if (data && data->mState == CustomElementData::State::eCustom) {
CustomElementDefinition* definition = data->GetCustomElementDefinition();
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
nsAutoString value(aValue.String());
LifecycleCallbackArgs args = {nsDependentAtomString(aName), value, value,
(ns.IsEmpty() ? VoidString() : ns)};
if (definition->IsInObservedAttributeList(aName)) {
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
&args, nullptr, definition);
nsAutoString value(aValue.String());
LifecycleCallbackArgs args = {nsDependentAtomString(aName), value, value,
(ns.IsEmpty() ? VoidString() : ns)};
nsContentUtils::EnqueueLifecycleCallback(
Document::eAttributeChanged, this, &args, nullptr, definition);
}
}
return NS_OK;
@ -2825,20 +2832,23 @@ nsresult Element::UnsetAttr(int32_t aNameSpaceID, nsAtom* aName, bool aNotify) {
}
}
CustomElementDefinition* definition = GetCustomElementDefinition();
// Only custom element which is in `custom` state could get the
// CustomElementDefinition.
if (definition && definition->IsInObservedAttributeList(aName)) {
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
const CustomElementData* data = GetCustomElementData();
if (data && data->mState == CustomElementData::State::eCustom) {
CustomElementDefinition* definition = data->GetCustomElementDefinition();
MOZ_ASSERT(definition, "Should have a valid CustomElementDefinition");
RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom();
LifecycleCallbackArgs args = {
nsDependentAtomString(aName), nsDependentAtomString(oldValueAtom),
VoidString(), (ns.IsEmpty() ? VoidString() : ns)};
if (definition->IsInObservedAttributeList(aName)) {
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
nsContentUtils::EnqueueLifecycleCallback(Document::eAttributeChanged, this,
&args, nullptr, definition);
RefPtr<nsAtom> oldValueAtom = oldValue.GetAsAtom();
LifecycleCallbackArgs args = {
nsDependentAtomString(aName), nsDependentAtomString(oldValueAtom),
VoidString(), (ns.IsEmpty() ? VoidString() : ns)};
nsContentUtils::EnqueueLifecycleCallback(
Document::eAttributeChanged, this, &args, nullptr, definition);
}
}
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, nullptr, aNotify);
@ -2918,8 +2928,9 @@ void Element::List(FILE* out, int32_t aIndent, const nsCString& aPrefix) const {
fprintf(out, " state=[%llx]",
static_cast<unsigned long long>(State().GetInternalValue()));
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
if (IsCommonAncestorForRangeInSelection()) {
const LinkedList<nsRange>* ranges = GetExistingCommonAncestorRanges();
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
const LinkedList<nsRange>* ranges =
GetExistingClosestCommonInclusiveAncestorRanges();
int32_t count = 0;
if (ranges) {
// Can't use range-based iteration on a const LinkedList, unfortunately.
@ -3495,15 +3506,21 @@ already_AddRefed<Animation> Element::Animate(
}
void Element::GetAnimations(const GetAnimationsOptions& aOptions,
nsTArray<RefPtr<Animation>>& aAnimations) {
Document* doc = GetComposedDoc();
if (doc) {
// We don't need to explicitly flush throttled animations here, since
// updating the animation style of elements will never affect the set of
// running animations and it's only the set of running animations that is
// important here.
doc->FlushPendingNotifications(
ChangesToFlush(FlushType::Style, false /* flush animations */));
nsTArray<RefPtr<Animation>>& aAnimations,
Flush aFlush) {
if (aFlush == Flush::Yes) {
if (Document* doc = GetComposedDoc()) {
// We don't need to explicitly flush throttled animations here, since
// updating the animation style of elements will never affect the set of
// running animations and it's only the set of running animations that is
// important here.
//
// NOTE: Any changes to the flags passed to the following call should
// be reflected in the flags passed in DocumentOrShadowRoot::GetAnimations
// too.
doc->FlushPendingNotifications(
ChangesToFlush(FlushType::Style, false /* flush animations */));
}
}
Element* elem = this;
@ -3830,9 +3847,8 @@ void Element::SetOrRemoveNullableStringAttr(nsAtom* aName,
}
Directionality Element::GetComputedDirectionality() const {
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
return frame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR
if (nsIFrame* frame = GetPrimaryFrame()) {
return frame->StyleVisibility()->mDirection == StyleDirection::Ltr
? eDir_LTR
: eDir_RTL;
}
@ -3898,9 +3914,8 @@ static void IntersectionObserverPropertyDtor(void* aObject,
nsAtom* aPropertyName,
void* aPropertyValue,
void* aData) {
Element* element = static_cast<Element*>(aObject);
IntersectionObserverList* observers =
static_cast<IntersectionObserverList*>(aPropertyValue);
auto* element = static_cast<Element*>(aObject);
auto* observers = static_cast<IntersectionObserverList*>(aPropertyValue);
for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
observer->UnlinkTarget(*element);
@ -3916,7 +3931,7 @@ void Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) {
observers = new IntersectionObserverList();
observers->Put(aObserver, eUninitialized);
SetProperty(nsGkAtoms::intersectionobserverlist, observers,
IntersectionObserverPropertyDtor, true);
IntersectionObserverPropertyDtor, /* aTransfer = */ true);
return;
}
@ -3932,29 +3947,24 @@ void Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver) {
void Element::UnregisterIntersectionObserver(
DOMIntersectionObserver* aObserver) {
IntersectionObserverList* observers = static_cast<IntersectionObserverList*>(
auto* observers = static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist));
if (observers) {
observers->Remove(aObserver);
if (observers->IsEmpty()) {
DeleteProperty(nsGkAtoms::intersectionobserverlist);
}
}
}
void Element::UnlinkIntersectionObservers() {
IntersectionObserverList* observers = static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist));
if (!observers) {
return;
}
for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
DOMIntersectionObserver* observer = iter.Key();
observer->UnlinkTarget(*this);
}
observers->Clear();
// IntersectionObserverPropertyDtor takes care of the hard work.
DeleteProperty(nsGkAtoms::intersectionobserverlist);
}
bool Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver,
int32_t aThreshold) {
IntersectionObserverList* observers = static_cast<IntersectionObserverList*>(
auto* observers = static_cast<IntersectionObserverList*>(
GetProperty(nsGkAtoms::intersectionobserverlist));
if (!observers) {
return false;
@ -4431,14 +4441,5 @@ double Element::FirstLineBoxBSize() const {
: 0.0;
}
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
void Element::AssertInvariantsOnNodeInfoChange() {
MOZ_DIAGNOSTIC_ASSERT(!IsInComposedDoc());
if (nsCOMPtr<Link> link = do_QueryInterface(this)) {
MOZ_DIAGNOSTIC_ASSERT(!link->HasPendingLinkUpdate());
}
}
#endif
} // namespace dom
} // namespace mozilla

View File

@ -760,6 +760,20 @@ class Element : public FragmentOrElement {
return HasAttr(kNameSpaceID_None, aAttr);
}
/**
* Determine if an attribute has been set to a non-empty string value. If the
* attribute is not set at all, this will return false.
*
* @param aNameSpaceId the namespace id of the attribute (defaults to
* kNameSpaceID_None in the overload that omits this arg)
* @param aAttr the attribute name
*/
inline bool HasNonEmptyAttr(int32_t aNameSpaceID, const nsAtom* aName) const;
bool HasNonEmptyAttr(const nsAtom* aAttr) const {
return HasNonEmptyAttr(kNameSpaceID_None, aAttr);
}
/**
* Test whether this Element's given attribute has the given value. If the
* attribute is not set at all, this will return false.
@ -1059,7 +1073,6 @@ class Element : public FragmentOrElement {
ErrorResult& aError) {
SetAttribute(aName, aValue, nullptr, aError);
}
void RemoveAttribute(const nsAString& aName, ErrorResult& aError);
void RemoveAttributeNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName, ErrorResult& aError);
@ -1332,11 +1345,13 @@ class Element : public FragmentOrElement {
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
ErrorResult& aError);
// Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
// Callers must keep this element alive because flushing style may destroy
// this element.
enum class Flush { Yes, No };
MOZ_CAN_RUN_SCRIPT
void GetAnimations(const GetAnimationsOptions& aOptions,
nsTArray<RefPtr<Animation>>& aAnimations);
nsTArray<RefPtr<Animation>>& aAnimations,
Flush aFlush = Flush::Yes);
static void GetAnimationsUnsorted(Element* aElement,
PseudoStyleType aPseudoType,
nsTArray<RefPtr<Animation>>& aAnimations);
@ -1455,23 +1470,6 @@ class Element : public FragmentOrElement {
return mAttrs.AttrInfoAt(index);
}
/**
* Called when we have been adopted, and the information of the
* node has been changed.
*
* The new document can be reached via OwnerDoc().
*
* If you override this method,
* please call up to the parent NodeInfoChanged.
*
* If you change this, change also the similar method in Link.
*/
virtual void NodeInfoChanged(Document* aOldDoc) {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
AssertInvariantsOnNodeInfoChange();
#endif
}
/**
* Parse a string into an nsAttrValue for a CORS attribute. This
* never fails. The resulting value is an enumerated value whose
@ -1982,6 +1980,15 @@ inline bool Element::HasAttr(int32_t aNameSpaceID, const nsAtom* aName) const {
return mAttrs.IndexOfAttr(aName, aNameSpaceID) >= 0;
}
inline bool Element::HasNonEmptyAttr(int32_t aNameSpaceID,
const nsAtom* aName) const {
MOZ_ASSERT(aNameSpaceID > kNameSpaceID_Unknown, "Must have namespace");
MOZ_ASSERT(aName, "Must have attribute name");
const nsAttrValue* val = mAttrs.GetAttr(aName, aNameSpaceID);
return val && !val->IsEmptyString();
}
inline bool Element::AttrValueIs(int32_t aNameSpaceID, const nsAtom* aName,
const nsAString& aValue,
nsCaseTreatment aCaseSensitive) const {

View File

@ -55,7 +55,7 @@ void IdleRequest::IdleRun(nsPIDOMWindowInner* aWindow,
RefPtr<IdleDeadline> deadline =
new IdleDeadline(aWindow, aDidTimeout, aDeadline);
RefPtr<IdleRequestCallback> callback(mCallback.forget());
RefPtr<IdleRequestCallback> callback(std::move(mCallback));
MOZ_ASSERT(!mCallback);
callback->Call(*deadline, "requestIdleCallback handler");
}

View File

@ -97,7 +97,7 @@ class EncodingCompleteEvent : public CancelableRunnable {
nsresult rv = NS_OK;
// We want to null out mEncodeCompleteCallback no matter what.
RefPtr<EncodeCompleteCallback> callback(mEncodeCompleteCallback.forget());
RefPtr<EncodeCompleteCallback> callback(std::move(mEncodeCompleteCallback));
if (!mFailed) {
RefPtr<BlobImpl> blobImpl = new MemoryBlobImpl(mImgData, mImgSize, mType);
rv = callback->ReceiveBlobImpl(blobImpl.forget());

View File

@ -128,7 +128,7 @@ class Link : public nsISupports {
// To ensure correct mHasPendingLinkUpdate handling, we have this method
// similar to the one in Element. Overriders must call
// ClearHasPendingLinkUpdate().
// If you change this, change also the method in Element.
// If you change this, change also the method in nsINode.
virtual void NodeInfoChanged(Document* aOldDoc) = 0;
bool IsInDNSPrefetch() { return mInDNSPrefetch; }

View File

@ -823,14 +823,14 @@ void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
aHandlerURI->GetSpec(spec);
nsPrintfCString message("Permission denied to add %s as a protocol handler",
spec.get());
aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
aRv.ThrowSecurityError(message);
};
auto raisePermissionDeniedScheme = [&] {
nsPrintfCString message(
"Permission denied to add a protocol handler for %s",
NS_ConvertUTF16toUTF8(aScheme).get());
aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
aRv.ThrowSecurityError(message);
};
if (!aDocumentURI || !aHandlerURI) {
@ -843,8 +843,7 @@ void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
// If the uri doesn't contain '%s', it won't be a good handler - the %s
// gets replaced with the handled URI.
if (!FindInReadable(NS_LITERAL_CSTRING("%s"), spec)) {
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
"Handler URI does not contain \"%s\".");
aRv.ThrowSyntaxError("Handler URI does not contain \"%s\".");
return;
}

View File

@ -56,7 +56,7 @@ class PostMessageEvent final : public Runnable {
mHolder.construct<StructuredCloneHolder>(
StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
JS::StructuredCloneScope::SameProcessDifferentThread);
JS::StructuredCloneScope::SameProcess);
mHolder.ref<StructuredCloneHolder>().Write(aCx, aMessage, aTransfer,
JS::CloneDataPolicy(), aError);
}

View File

@ -7,8 +7,11 @@
#include "nsCOMPtr.h"
#include "nsIContent.h"
#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
class nsRange;
namespace mozilla {
template <typename T, typename U>
@ -46,11 +49,15 @@ class RangeBoundaryBase {
template <typename T, typename U>
friend class EditorDOMPointBase;
friend nsRange;
friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&,
RangeBoundary&, const char*,
uint32_t);
friend void ImplCycleCollectionUnlink(RangeBoundary&);
static const uint32_t kFallbackOffset = 0;
public:
RangeBoundaryBase(nsINode* aContainer, nsIContent* aRef)
: mParent(aContainer), mRef(aRef) {
@ -96,10 +103,12 @@ class RangeBoundaryBase {
return nullptr;
}
if (!mRef) {
MOZ_ASSERT(Offset() == 0, "invalid RangeBoundary");
MOZ_ASSERT(*Offset(OffsetFilter::kValidOrInvalidOffsets) == 0,
"invalid RangeBoundary");
return mParent->GetFirstChild();
}
MOZ_ASSERT(mParent->GetChildAt_Deprecated(Offset()) ==
MOZ_ASSERT(mParent->GetChildAt_Deprecated(
*Offset(OffsetFilter::kValidOrInvalidOffsets)) ==
mRef->GetNextSibling());
return mRef->GetNextSibling();
}
@ -136,20 +145,52 @@ class RangeBoundaryBase {
return mRef;
}
uint32_t Offset() const {
if (mOffset.isSome()) {
return mOffset.value();
enum class OffsetFilter { kValidOffsets, kValidOrInvalidOffsets };
/**
* @return maybe an offset, depending on aOffsetFilter. If it is:
* kValidOffsets: if the offset is valid, it, Nothing{} otherwise.
* kValidOrInvalidOffsets: the internally stored offset, even if
* invalid, or if not available, a defined
* default value. That is, always some value.
*/
Maybe<uint32_t> Offset(const OffsetFilter aOffsetFilter) const {
switch (aOffsetFilter) {
case OffsetFilter::kValidOffsets: {
if (IsSetAndValid()) {
if (!mOffset) {
DetermineOffsetFromReference();
}
}
return mOffset;
}
case OffsetFilter::kValidOrInvalidOffsets: {
if (mOffset.isSome()) {
return mOffset;
}
if (mParent) {
DetermineOffsetFromReference();
return mOffset;
}
return Some(kFallbackOffset);
}
}
if (!mParent) {
return 0;
}
// Needed to calm the compiler. There was deliberately no default case added
// to the above switch-statement, because it would prevent build-errors when
// not all enumerators are handled.
MOZ_ASSERT_UNREACHABLE();
return Some(kFallbackOffset);
}
private:
void DetermineOffsetFromReference() const {
MOZ_ASSERT(mParent);
MOZ_ASSERT(mRef);
MOZ_ASSERT(mRef->GetParentNode() == mParent);
mOffset = mozilla::Some(mParent->ComputeIndexOf(mRef) + 1);
return mOffset.value();
}
void InvalidateOffset() {
@ -165,6 +206,7 @@ class RangeBoundaryBase {
mOffset.reset();
}
public:
bool IsSet() const { return mParent && (mRef || mOffset.isSome()); }
bool IsSetAndValid() const {
@ -175,7 +217,9 @@ class RangeBoundaryBase {
if (Ref()) {
return Ref()->GetParentNode() == Container();
}
return Offset() <= Container()->Length();
MOZ_ASSERT(mOffset.isSome());
return *mOffset <= Container()->Length();
}
bool IsStartOfContainer() const {
@ -214,6 +258,15 @@ class RangeBoundaryBase {
return *this;
}
bool Equals(const nsINode* aNode, uint32_t aOffset) const {
if (mParent != aNode) {
return false;
}
const Maybe<uint32_t> offset = Offset(OffsetFilter::kValidOffsets);
return offset && (*offset == aOffset);
}
template <typename A, typename B>
bool operator==(const RangeBoundaryBase<A, B>& aOther) const {
return mParent == aOther.mParent &&
@ -232,6 +285,9 @@ class RangeBoundaryBase {
mutable mozilla::Maybe<uint32_t> mOffset;
};
template <typename ParentType, typename RefType>
const uint32_t RangeBoundaryBase<ParentType, RefType>::kFallbackOffset;
inline void ImplCycleCollectionUnlink(RangeBoundary& aField) {
ImplCycleCollectionUnlink(aField.mParent);
ImplCycleCollectionUnlink(aField.mRef);

View File

@ -4,6 +4,7 @@
#include "mozilla/RangeUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/AbstractRange.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsContentUtils.h"
@ -79,13 +80,14 @@ bool RangeUtils::IsValidPoints(
return false;
}
bool disconnected = false;
int32_t order = nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary,
&disconnected);
if (NS_WARN_IF(disconnected)) {
const Maybe<int32_t> order =
nsContentUtils::ComparePoints(aStartBoundary, aEndBoundary);
if (!order) {
MOZ_ASSERT_UNREACHABLE();
return false;
}
return order != 1;
return *order != 1;
}
// Utility routine to detect if a content node is completely contained in a
@ -148,23 +150,29 @@ nsresult RangeUtils::CompareNodeToRange(nsINode* aNode,
// silence the warning. (Bug 1438996)
// is RANGE(start) <= NODE(start) ?
bool disconnected = false;
*aNodeIsBeforeRange =
nsContentUtils::ComparePoints(aAbstractRange->StartRef().Container(),
aAbstractRange->StartRef().Offset(), parent,
nodeStart, &disconnected) > 0;
if (NS_WARN_IF(disconnected)) {
Maybe<int32_t> order = nsContentUtils::ComparePoints(
aAbstractRange->StartRef().Container(),
*aAbstractRange->StartRef().Offset(
RangeBoundary::OffsetFilter::kValidOrInvalidOffsets),
parent, nodeStart);
if (NS_WARN_IF(!order)) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
*aNodeIsBeforeRange = *order > 0;
// is RANGE(end) >= NODE(end) ?
order = nsContentUtils::ComparePoints(
aAbstractRange->EndRef().Container(),
*aAbstractRange->EndRef().Offset(
RangeBoundary::OffsetFilter::kValidOrInvalidOffsets),
parent, nodeEnd);
if (NS_WARN_IF(!order)) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
// is RANGE(end) >= NODE(end) ?
*aNodeIsAfterRange =
nsContentUtils::ComparePoints(aAbstractRange->EndRef().Container(),
aAbstractRange->EndRef().Offset(), parent,
nodeEnd, &disconnected) < 0;
if (NS_WARN_IF(disconnected)) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
*aNodeIsAfterRange = *order < 0;
return NS_OK;
}

View File

@ -38,7 +38,8 @@ class RangeUtils final {
// If aNode isn't in the child nodes of its parent node, we hit this case.
// This may occur when we're called by a mutation observer while aNode is
// removed from the parent node.
if (NS_WARN_IF(afterNode.Offset() == 0)) {
if (NS_WARN_IF(
!afterNode.Offset(RawRangeBoundary::OffsetFilter::kValidOffsets))) {
return RawRangeBoundary();
}
return afterNode;

View File

@ -106,8 +106,9 @@ void ResizeObservation::UpdateLastReportedSize(const nsSize& aSize) {
}
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ResizeObserver, mOwner, mCallback,
mActiveTargets, mObservationMap)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ResizeObserver, mOwner, mDocument,
mCallback, mActiveTargets,
mObservationMap)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ResizeObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ResizeObserver)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ResizeObserver)
@ -120,31 +121,37 @@ already_AddRefed<ResizeObserver> ResizeObserver::Constructor(
ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
Document* document = window->GetExtantDoc();
if (!document) {
Document* doc = window->GetExtantDoc();
if (!doc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<ResizeObserver> observer = new ResizeObserver(window.forget(), aCb);
document->AddResizeObserver(observer);
return observer.forget();
return do_AddRef(new ResizeObserver(std::move(window), doc, aCb));
}
void ResizeObserver::Observe(Element& aTarget,
const ResizeObserverOptions& aOptions,
ErrorResult& aRv) {
RefPtr<ResizeObservation> observation;
// NOTE(emilio): Per spec, this is supposed to happen on construction, but the
// spec isn't particularly sane here, see
// https://github.com/w3c/csswg-drafts/issues/4518
if (mObservationList.isEmpty()) {
MOZ_ASSERT(mObservationMap.IsEmpty());
if (MOZ_UNLIKELY(!mDocument)) {
return aRv.Throw(NS_ERROR_FAILURE);
}
mDocument->AddResizeObserver(*this);
}
if (mObservationMap.Get(&aTarget, getter_AddRefs(observation))) {
RefPtr<ResizeObservation>& observation =
mObservationMap.LookupForAdd(&aTarget).OrInsert([] { return nullptr; });
if (observation) {
if (observation->BoxOptions() == aOptions.mBox) {
// Already observed this target and the observed box is the same, so
// return.
@ -155,14 +162,17 @@ void ResizeObserver::Observe(Element& aTarget,
// should be kept to make sure IsActive() returns the correct result.
return;
}
Unobserve(aTarget, aRv);
// Remove the pre-existing entry, but without unregistering ourselves from
// the controller.
observation->remove();
observation = nullptr;
}
// FIXME(emilio): This should probably either flush or not look at the
// writing-mode or something.
nsIFrame* frame = aTarget.GetPrimaryFrame();
observation = new ResizeObservation(
aTarget, aOptions.mBox, frame ? frame->GetWritingMode() : WritingMode());
mObservationMap.Put(&aTarget, observation);
mObservationList.insertBack(observation);
// Per the spec, we need to trigger notification in event loop that
@ -181,19 +191,28 @@ void ResizeObserver::Unobserve(Element& aTarget, ErrorResult& aRv) {
"If ResizeObservation found for an element, observation list "
"must be not empty.");
observation->remove();
if (mObservationList.isEmpty()) {
if (MOZ_LIKELY(mDocument)) {
mDocument->RemoveResizeObserver(*this);
}
}
}
void ResizeObserver::Disconnect() {
const bool registered = !mObservationList.isEmpty();
mObservationList.clear();
mObservationMap.Clear();
mActiveTargets.Clear();
if (registered && MOZ_LIKELY(mDocument)) {
mDocument->RemoveResizeObserver(*this);
}
}
void ResizeObserver::GatherActiveObservations(uint32_t aDepth) {
mActiveTargets.Clear();
mHasSkippedTargets = false;
for (auto observation : mObservationList) {
for (auto* observation : mObservationList) {
if (!observation->IsActive()) {
continue;
}
@ -285,7 +304,7 @@ void ResizeObserverEntry::SetContentRectAndSize(const nsSize& aSize) {
nsRect rect(nsPoint(padding.left, padding.top), aSize);
RefPtr<DOMRect> contentRect = new DOMRect(this);
contentRect->SetLayoutRect(rect);
mContentRect = contentRect.forget();
mContentRect = std::move(contentRect);
// 2. Update mContentBoxSize.
const WritingMode wm = frame ? frame->GetWritingMode() : WritingMode();

View File

@ -86,10 +86,12 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ResizeObserver)
ResizeObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
ResizeObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner, Document* aDocument,
ResizeObserverCallback& aCb)
: mOwner(aOwner), mCallback(&aCb) {
: mOwner(std::move(aOwner)), mDocument(aDocument), mCallback(&aCb) {
MOZ_ASSERT(mOwner, "Need a non-null owner window");
MOZ_ASSERT(mDocument, "Need a non-null doc");
MOZ_ASSERT(mDocument == mOwner->GetExtantDoc());
}
nsISupports* GetParentObject() const { return mOwner; }
@ -145,6 +147,8 @@ class ResizeObserver final : public nsISupports, public nsWrapperCache {
~ResizeObserver() { mObservationList.clear(); }
nsCOMPtr<nsPIDOMWindowInner> mOwner;
// The window's document at the time of ResizeObserver creation.
RefPtr<Document> mDocument;
RefPtr<ResizeObserverCallback> mCallback;
nsTArray<RefPtr<ResizeObservation>> mActiveTargets;
// The spec uses a list to store the skipped targets. However, it seems what

View File

@ -80,13 +80,6 @@ void ResizeObserverController::Traverse(
void ResizeObserverController::Unlink() { mResizeObservers.Clear(); }
void ResizeObserverController::AddResizeObserver(ResizeObserver* aObserver) {
MOZ_ASSERT(aObserver,
"AddResizeObserver() should never be called with a null "
"parameter");
mResizeObservers.AppendElement(aObserver);
}
void ResizeObserverController::ShellDetachedFromDocument() {
mResizeObserverNotificationHelper->Unregister();
}
@ -145,10 +138,7 @@ void ResizeObserverController::Notify() {
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsPIDOMWindowInner> window =
doc->GetWindow()->GetCurrentInnerWindow();
if (window) {
if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) {
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
MOZ_ASSERT(sgo);
@ -166,26 +156,19 @@ void ResizeObserverController::Notify() {
}
void ResizeObserverController::GatherAllActiveObservations(uint32_t aDepth) {
nsTObserverArray<RefPtr<ResizeObserver>>::ForwardIterator iter(
mResizeObservers);
while (iter.HasMore()) {
iter.GetNext()->GatherActiveObservations(aDepth);
for (ResizeObserver* observer : mResizeObservers) {
observer->GatherActiveObservations(aDepth);
}
}
uint32_t ResizeObserverController::BroadcastAllActiveObservations() {
uint32_t shallowestTargetDepth = std::numeric_limits<uint32_t>::max();
// Use EndLimitedIterator, so we handle the new-added observers (from the JS
// callback) in the next iteration of the while loop.
// Note: the while loop is in ResizeObserverController::Notify()).
nsTObserverArray<RefPtr<ResizeObserver>>::EndLimitedIterator iter(
mResizeObservers);
while (iter.HasMore()) {
RefPtr<ResizeObserver>& observer = iter.GetNext();
// Copy the observers as this invokes the callbacks and could register and
// unregister observers at will.
nsTArray<RefPtr<ResizeObserver>> observers(mResizeObservers);
for (auto& observer : observers) {
uint32_t targetDepth = observer->BroadcastActiveObservations();
if (targetDepth < shallowestTargetDepth) {
shallowestTargetDepth = targetDepth;
}
@ -195,10 +178,8 @@ uint32_t ResizeObserverController::BroadcastAllActiveObservations() {
}
bool ResizeObserverController::HasAnyActiveObservations() const {
nsTObserverArray<RefPtr<ResizeObserver>>::ForwardIterator iter(
mResizeObservers);
while (iter.HasMore()) {
if (iter.GetNext()->HasActiveObservations()) {
for (auto& observer : mResizeObservers) {
if (observer->HasActiveObservations()) {
return true;
}
}
@ -206,10 +187,8 @@ bool ResizeObserverController::HasAnyActiveObservations() const {
}
bool ResizeObserverController::HasAnySkippedObservations() const {
nsTObserverArray<RefPtr<ResizeObserver>>::ForwardIterator iter(
mResizeObservers);
while (iter.HasMore()) {
if (iter.GetNext()->HasSkippedObservations()) {
for (auto& observer : mResizeObservers) {
if (observer->HasSkippedObservations()) {
return true;
}
}
@ -227,5 +206,15 @@ ResizeObserverController::~ResizeObserverController() {
mResizeObserverNotificationHelper->DetachFromOwner();
}
void ResizeObserverController::AddSizeOfIncludingThis(
nsWindowSizes& aSizes) const {
MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
size_t size = mallocSizeOf(this);
size += mResizeObservers.ShallowSizeOfExcludingThis(mallocSizeOf);
// TODO(emilio): Measure the observers individually or something? They aren't
// really owned by us.
aSizes.mDOMResizeObserverControllerSize += size;
}
} // namespace dom
} // namespace mozilla

View File

@ -68,8 +68,18 @@ class ResizeObserverController final {
void Traverse(nsCycleCollectionTraversalCallback& aCb);
void Unlink();
void AddSizeOfIncludingThis(nsWindowSizes&) const;
void ShellDetachedFromDocument();
void AddResizeObserver(ResizeObserver* aObserver);
void AddResizeObserver(ResizeObserver& aObserver) {
MOZ_ASSERT(!mResizeObservers.Contains(&aObserver));
mResizeObservers.AppendElement(&aObserver);
}
void RemoveResizeObserver(ResizeObserver& aObserver) {
MOZ_ASSERT(mResizeObservers.Contains(&aObserver));
mResizeObservers.RemoveElement(&aObserver);
}
/**
* Schedule the notification via ResizeObserverNotificationHelper refresh
@ -119,7 +129,7 @@ class ResizeObserverController final {
Document* const mDocument;
RefPtr<ResizeObserverNotificationHelper> mResizeObserverNotificationHelper;
nsTObserverArray<RefPtr<ResizeObserver>> mResizeObservers;
nsTArray<RefPtr<ResizeObserver>> mResizeObservers;
};
} // namespace dom

View File

@ -166,14 +166,14 @@ ScreenOrientation::LockOrientationTask::Run() {
if (mDocument->Hidden()) {
// Active orientation lock is not the document's orientation lock.
mPromise->MaybeResolveWithUndefined();
mDocument->SetOrientationPendingPromise(nullptr);
mDocument->ClearOrientationPendingPromise();
return NS_OK;
}
if (mOrientationLock == hal::eScreenOrientation_None) {
mScreenOrientation->UnlockDeviceOrientation();
mPromise->MaybeResolveWithUndefined();
mDocument->SetOrientationPendingPromise(nullptr);
mDocument->ClearOrientationPendingPromise();
return NS_OK;
}
@ -186,7 +186,7 @@ ScreenOrientation::LockOrientationTask::Run() {
if (NS_WARN_IF(!result)) {
mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
mDocument->SetOrientationPendingPromise(nullptr);
mDocument->ClearOrientationPendingPromise();
return NS_OK;
}
@ -195,7 +195,7 @@ ScreenOrientation::LockOrientationTask::Run() {
mDocument->CurrentOrientationAngle() == 0)) {
// Orientation lock will not cause an orientation change.
mPromise->MaybeResolveWithUndefined();
mDocument->SetOrientationPendingPromise(nullptr);
mDocument->ClearOrientationPendingPromise();
}
return NS_OK;
@ -252,7 +252,7 @@ static inline void AbortOrientationPromises(nsIDocShell* aDocShell) {
Promise* promise = doc->GetOrientationPendingPromise();
if (promise) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
doc->SetOrientationPendingPromise(nullptr);
doc->ClearOrientationPendingPromise();
}
}
@ -321,7 +321,10 @@ already_AddRefed<Promise> ScreenOrientation::LockInternal(
rootShell->SetOrientationLock(aOrientation);
AbortOrientationPromises(rootShell);
doc->SetOrientationPendingPromise(p);
if (!doc->SetOrientationPendingPromise(p)) {
p->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return p.forget();
}
nsCOMPtr<nsIRunnable> lockOrientationTask = new LockOrientationTask(
this, p, aOrientation, doc, perm == FULLSCREEN_LOCK_ALLOWED);
@ -549,7 +552,7 @@ ScreenOrientation::DispatchChangeEventAndResolvePromise() {
Promise* pendingPromise = doc->GetOrientationPendingPromise();
if (pendingPromise) {
pendingPromise->MaybeResolveWithUndefined();
doc->SetOrientationPendingPromise(nullptr);
doc->ClearOrientationPendingPromise();
}
}
});

File diff suppressed because it is too large Load Diff

View File

@ -157,17 +157,26 @@ class Selection final : public nsSupportsWeakReference,
ScrollAxis aVertical = ScrollAxis(),
ScrollAxis aHorizontal = ScrollAxis(),
int32_t aFlags = 0);
nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract,
nsTArray<RangeData>* aOutput);
static nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract,
nsTArray<RangeData>* aOutput);
private:
/**
* AddItem adds aRange to this Selection. If mUserInitiated is true,
* Adds aRange to this Selection. If mUserInitiated is true,
* then aRange is first scanned for -moz-user-select:none nodes and split up
* into multiple ranges to exclude those before adding the resulting ranges
* to this Selection.
*
* @param aOutIndex points to the range last added, if at least one was added.
* If aRange is already contained, it points to the range
* containing it. -1 if mRanges was empty and no range was
* added.
*/
nsresult AddItem(nsRange* aRange, int32_t* aOutIndex,
bool aNoStartSelect = false);
nsresult RemoveItem(nsRange* aRange);
nsresult AddRangesForSelectableNodes(nsRange* aRange, int32_t* aOutIndex,
bool aNoStartSelect = false);
nsresult RemoveRangeInternal(nsRange& aRange);
public:
nsresult RemoveCollapsedRanges();
nsresult Clear(nsPresContext* aPresContext);
nsresult Collapse(nsINode* aContainer, int32_t aOffset) {
@ -185,6 +194,9 @@ class Selection final : public nsSupportsWeakReference,
MOZ_CAN_RUN_SCRIPT_BOUNDARY
nsresult Extend(nsINode* aContainer, int32_t aOffset);
/**
* See mRanges.
*/
nsRange* GetRangeAt(int32_t aIndex) const;
// Get the anchor-to-focus range if we don't care which end is
@ -225,7 +237,9 @@ class Selection final : public nsSupportsWeakReference,
}
uint32_t AnchorOffset() const {
const RangeBoundary& anchor = AnchorRef();
return anchor.IsSet() ? anchor.Offset() : 0;
const Maybe<uint32_t> offset =
anchor.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
return offset ? *offset : 0;
}
nsINode* GetFocusNode() const {
const RangeBoundary& focus = FocusRef();
@ -233,7 +247,9 @@ class Selection final : public nsSupportsWeakReference,
}
uint32_t FocusOffset() const {
const RangeBoundary& focus = FocusRef();
return focus.IsSet() ? focus.Offset() : 0;
const Maybe<uint32_t> offset =
focus.Offset(RangeBoundary::OffsetFilter::kValidOffsets);
return offset ? *offset : 0;
}
nsIContent* GetChildAtAnchorOffset() {
@ -498,10 +514,7 @@ class Selection final : public nsSupportsWeakReference,
MOZ_CAN_RUN_SCRIPT
void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
nsINode& aFocusNode, uint32_t aFocusOffset,
ErrorResult& aRv) {
SetBaseAndExtent(RawRangeBoundary(&aAnchorNode, aAnchorOffset),
RawRangeBoundary(&aFocusNode, aFocusOffset), aRv);
}
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void SetBaseAndExtent(const RawRangeBoundary& aAnchorRef,
const RawRangeBoundary& aFocusRef, ErrorResult& aRv) {
@ -693,9 +706,15 @@ class Selection final : public nsSupportsWeakReference,
* nothing.
*/
void SetAnchorFocusRange(int32_t aIndex);
void SelectFramesForContent(nsIContent* aContent, bool aSelected);
nsresult SelectAllFramesForContent(PostContentIterator& aPostOrderIter,
nsIContent* aContent, bool aSelected);
void SelectFramesOf(nsIContent* aContent, bool aSelected) const;
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant.
*/
nsresult SelectFramesOfInclusiveDescendantsOfContent(
PostContentIterator& aPostOrderIter, nsIContent* aContent,
bool aSelected) const;
nsresult SelectFrames(nsPresContext* aPresContext, nsRange* aRange,
bool aSelect);
@ -716,30 +735,60 @@ class Selection final : public nsSupportsWeakReference,
nsresult GetTableCellLocationFromRange(nsRange* aRange,
TableSelection* aSelectionType,
int32_t* aRow, int32_t* aCol);
nsresult AddTableCellRange(nsRange* aRange, bool* aDidAddRange,
int32_t* aOutIndex);
nsresult FindInsertionPoint(nsTArray<RangeData>* aElementArray,
nsINode* aPointNode, int32_t aPointOffset,
nsresult (*aComparator)(nsINode*, int32_t,
nsRange*, int32_t*),
int32_t* aPoint);
bool EqualsRangeAtPoint(nsINode* aBeginNode, int32_t aBeginOffset,
nsINode* aEndNode, int32_t aEndOffset,
int32_t aRangeIndex);
nsresult GetIndicesForInterval(nsINode* aBeginNode, int32_t aBeginOffset,
nsINode* aEndNode, int32_t aEndOffset,
bool aAllowAdjacent, int32_t* aStartIndex,
int32_t* aEndIndex);
RangeData* FindRangeData(nsRange* aRange);
void UserSelectRangesToAdd(nsRange* aItem,
nsTArray<RefPtr<nsRange>>& rangesToAdd);
/**
* Helper method for AddItem.
* @param aOutIndex points to the index of the range in mRanges. If
* aDidAddRange is true, it is in [0, mRanges.Length()).
*/
nsresult AddItemInternal(nsRange* aRange, int32_t* aOutIndex);
nsresult MaybeAddTableCellRange(nsRange* aRange, bool* aDidAddRange,
int32_t* aOutIndex);
/**
* Binary searches the given sorted array of ranges for the insertion point
* for the given node/offset. The given comparator is used, and the index
* where the point should appear in the array is placed in *aInsertionPoint.
* If there is an item in the array equal to the input point (aPointNode,
* aPointOffset), we will return the index of this item.
*
* @param aInsertionPoint can be in [0, `aElementArray->Length()`].
*/
static nsresult FindInsertionPoint(
const nsTArray<RangeData>* aElementArray, const nsINode* aPointNode,
int32_t aPointOffset,
nsresult (*aComparator)(const nsINode*, int32_t, const nsRange*,
int32_t*),
int32_t* aInsertionPoint);
bool HasEqualRangeBoundariesAt(const nsRange& aRange,
int32_t aRangeIndex) const;
/**
* Works on the same principle as GetRangesForIntervalArray, however
* instead this returns the indices into mRanges between which the
* overlapping ranges lie.
*
* @param aStartIndex will be less or equal than aEndIndex.
* @param aEndIndex can be in [-1, mRanges.Length()].
*/
nsresult GetIndicesForInterval(const nsINode* aBeginNode,
int32_t aBeginOffset, const nsINode* aEndNode,
int32_t aEndOffset, bool aAllowAdjacent,
int32_t& aStartIndex,
int32_t& aEndIndex) const;
RangeData* FindRangeData(nsRange* aRange);
static void UserSelectRangesToAdd(nsRange* aItem,
nsTArray<RefPtr<nsRange>>& rangesToAdd);
/**
* Preserves the sorting and disjunctiveness of mRanges.
*
* @param aOutIndex will point to the index of the added range, or if aRange
* is already contained, to the one containing it. Hence
* it'll always be in [0, mRanges.Length()).
*/
nsresult MaybeAddRangeAndTruncateOverlaps(nsRange* aRange,
int32_t* aOutIndex);
Document* GetDocument() const;
nsPIDOMWindowOuter* GetWindow() const;

View File

@ -136,7 +136,7 @@ void SelectionChangeEventDispatcher::OnSelectionChange(Document* aDoc,
root = root->GetParent();
}
target = root.forget();
target = std::move(root);
}
}

View File

@ -13,8 +13,7 @@ namespace dom {
SerializedStackHolder::SerializedStackHolder()
: mHolder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringNotSupported,
StructuredCloneHolder::StructuredCloneScope::
SameProcessDifferentThread) {}
StructuredCloneHolder::StructuredCloneScope::SameProcess) {}
void SerializedStackHolder::WriteStack(JSContext* aCx,
JS::HandleObject aStack) {

View File

@ -48,7 +48,7 @@ NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: DocumentFragment(std::move(aNodeInfo)),
DocumentOrShadowRoot(*this),
DocumentOrShadowRoot(this),
mMode(aMode),
mIsUAWidget(false) {
SetHost(aElement);
@ -113,7 +113,13 @@ nsresult ShadowRoot::Bind() {
MOZ_ASSERT(!IsInComposedDoc(), "Forgot to unbind?");
if (Host()->IsInComposedDoc()) {
SetIsConnected(true);
OwnerDoc()->AddComposedDocShadowRoot(*this);
Document* doc = OwnerDoc();
doc->AddComposedDocShadowRoot(*this);
// If our stylesheets somehow mutated when we were disconnected, we need to
// ensure that our style data gets flushed as appropriate.
if (mServoStyles && Servo_AuthorStyles_IsDirty(mServoStyles.get())) {
doc->RecordShadowStyleChange(*this);
}
}
BindContext context(*this);
@ -300,6 +306,11 @@ void ShadowRoot::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
if (mStyleRuleMap) {
mStyleRuleMap->RuleAdded(aSheet, aRule);
}
if (aRule.IsIncompleteImportRule()) {
return;
}
Servo_AuthorStyles_ForceDirty(mServoStyles.get());
ApplicableRulesChanged();
}
@ -327,12 +338,27 @@ void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule*) {
ApplicableRulesChanged();
}
void ShadowRoot::ImportRuleLoaded(CSSImportRule&, StyleSheet& aSheet) {
if (mStyleRuleMap) {
mStyleRuleMap->SheetAdded(aSheet);
}
if (!aSheet.IsApplicable()) {
return;
}
// TODO(emilio): Could handle it like a regular sheet insertion, I guess, to
// avoid throwing away the whole style data.
Servo_AuthorStyles_ForceDirty(mServoStyles.get());
ApplicableRulesChanged();
}
// We don't need to do anything else than forwarding to the document if
// necessary.
void ShadowRoot::StyleSheetCloned(StyleSheet& aSheet) {
void ShadowRoot::SheetCloned(StyleSheet& aSheet) {
if (Document* doc = GetComposedDoc()) {
if (PresShell* shell = doc->GetPresShell()) {
shell->StyleSet()->StyleSheetCloned(aSheet);
shell->StyleSet()->SheetCloned(aSheet);
}
}
}
@ -346,13 +372,23 @@ void ShadowRoot::ApplicableRulesChanged() {
void ShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
DocumentOrShadowRoot::InsertSheetAt(aIndex, aSheet);
if (aSheet.IsApplicable()) {
InsertSheetIntoAuthorData(aIndex, aSheet);
InsertSheetIntoAuthorData(aIndex, aSheet, mStyleSheets);
}
}
void ShadowRoot::InsertSheetIntoAuthorData(size_t aIndex, StyleSheet& aSheet) {
MOZ_ASSERT(SheetAt(aIndex) == &aSheet);
void ShadowRoot::InsertAdoptedSheetAt(size_t aIndex, StyleSheet& aSheet) {
DocumentOrShadowRoot::InsertAdoptedSheetAt(aIndex, aSheet);
if (aSheet.IsApplicable()) {
InsertSheetIntoAuthorData(aIndex, aSheet, mAdoptedStyleSheets);
}
}
void ShadowRoot::InsertSheetIntoAuthorData(
size_t aIndex, StyleSheet& aSheet,
const nsTArray<RefPtr<StyleSheet>>& aList) {
MOZ_ASSERT(aSheet.IsApplicable());
MOZ_ASSERT(aList[aIndex] == &aSheet);
MOZ_ASSERT(&aList == &mAdoptedStyleSheets || &aList == &mStyleSheets);
if (!mServoStyles) {
mServoStyles = Servo_AuthorStyles_Create().Consume();
@ -362,8 +398,8 @@ void ShadowRoot::InsertSheetIntoAuthorData(size_t aIndex, StyleSheet& aSheet) {
mStyleRuleMap->SheetAdded(aSheet);
}
for (size_t i = aIndex + 1; i < SheetCount(); ++i) {
StyleSheet* beforeSheet = SheetAt(i);
for (size_t i = aIndex + 1; i < aList.Length(); ++i) {
StyleSheet* beforeSheet = aList.ElementAt(i);
if (!beforeSheet->IsApplicable()) {
continue;
}
@ -374,15 +410,20 @@ void ShadowRoot::InsertSheetIntoAuthorData(size_t aIndex, StyleSheet& aSheet) {
return;
}
Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
if (mAdoptedStyleSheets.IsEmpty() || &aList == &mAdoptedStyleSheets) {
Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
} else {
Servo_AuthorStyles_InsertStyleSheetBefore(mServoStyles.get(), &aSheet,
mAdoptedStyleSheets.ElementAt(0));
}
ApplicableRulesChanged();
}
// FIXME(emilio): This needs to notify document observers and such,
// presumably.
void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet,
bool aApplicable) {
int32_t index = IndexOfSheet(aSheet);
void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
auto& sheetList = aSheet.IsConstructed() ? mAdoptedStyleSheets : mStyleSheets;
int32_t index = sheetList.IndexOf(&aSheet);
if (index < 0) {
// NOTE(emilio): @import sheets are handled in the relevant RuleAdded
// notification, which only notifies after the sheet is loaded.
@ -393,8 +434,8 @@ void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet,
"It'd better be an @import sheet");
return;
}
if (aApplicable) {
InsertSheetIntoAuthorData(size_t(index), aSheet);
if (aSheet.IsApplicable()) {
InsertSheetIntoAuthorData(size_t(index), aSheet, sheetList);
} else {
MOZ_ASSERT(mServoStyles);
if (mStyleRuleMap) {
@ -405,20 +446,31 @@ void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet,
}
}
void ShadowRoot::RemoveSheet(StyleSheet* aSheet) {
MOZ_ASSERT(aSheet);
RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(*aSheet);
MOZ_ASSERT(sheet);
if (sheet->IsApplicable()) {
void ShadowRoot::ClearAdoptedStyleSheets() {
for (const RefPtr<StyleSheet>& sheet : mAdoptedStyleSheets) {
RemoveSheetFromStyles(*sheet);
sheet->RemoveAdopter(*this);
}
mAdoptedStyleSheets.Clear();
}
void ShadowRoot::RemoveSheetFromStyles(StyleSheet& aSheet) {
if (aSheet.IsApplicable()) {
MOZ_ASSERT(mServoStyles);
if (mStyleRuleMap) {
mStyleRuleMap->SheetRemoved(*sheet);
mStyleRuleMap->SheetRemoved(aSheet);
}
Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), sheet);
Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), &aSheet);
ApplicableRulesChanged();
}
}
void ShadowRoot::RemoveSheet(StyleSheet& aSheet) {
RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(aSheet);
MOZ_ASSERT(sheet);
RemoveSheetFromStyles(*sheet);
}
void ShadowRoot::AddToIdTable(Element* aElement, nsAtom* aId) {
IdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
if (entry) {
@ -661,3 +713,29 @@ nsresult ShadowRoot::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
*aResult = nullptr;
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
// https://wicg.github.io/construct-stylesheets/#dom-documentorshadowroot-adoptedstylesheets
void ShadowRoot::SetAdoptedStyleSheets(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv) {
// Step 1 is a variable declaration
// 2.1 Check if all sheets are constructed, else throw NotAllowedError
// 2.2 Check if all sheets' constructor documents match the
// DocumentOrShadowRoot's node document, else throw NotAlloweError
EnsureAdoptedSheetsAreValid(aAdoptedStyleSheets, aRv);
if (aRv.Failed()) {
return;
}
// 3. Set the adopted style sheets to the new sheets
// TODO(nordzilla): There are optimizations that can be made here
// in the case of only appending new sheets.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1611236
ClearAdoptedStyleSheets();
mAdoptedStyleSheets.SetCapacity(aAdoptedStyleSheets.Length());
for (const OwningNonNull<StyleSheet>& sheet : aAdoptedStyleSheets) {
sheet->AddAdopter(*this);
AppendAdoptedStyleSheet(*sheet);
}
}

View File

@ -32,6 +32,7 @@ class Rule;
namespace dom {
class CSSImportRule;
class Element;
class HTMLInputElement;
@ -69,22 +70,21 @@ class ShadowRoot final : public DocumentFragment,
ShadowRootMode Mode() const { return mMode; }
bool IsClosed() const { return mMode == ShadowRootMode::Closed; }
void RemoveSheet(StyleSheet* aSheet);
void RemoveSheet(StyleSheet&);
void RemoveSheetFromStyles(StyleSheet&);
void RuleAdded(StyleSheet&, css::Rule&);
void RuleRemoved(StyleSheet&, css::Rule&);
void RuleChanged(StyleSheet&, css::Rule*);
void StyleSheetCloned(StyleSheet&);
void StyleSheetApplicableStateChanged(StyleSheet&, bool aApplicable);
StyleSheetList* StyleSheets() {
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
}
void ImportRuleLoaded(CSSImportRule&, StyleSheet&);
void SheetCloned(StyleSheet&);
void StyleSheetApplicableStateChanged(StyleSheet&);
/**
* Clones internal state, for example stylesheets, of aOther to 'this'.
*/
void CloneInternalDataFrom(ShadowRoot* aOther);
void InsertSheetAt(size_t aIndex, StyleSheet&);
void InsertAdoptedSheetAt(size_t aIndex, StyleSheet&);
// Calls UnbindFromTree for each of our kids, and also flags us as no longer
// being connected.
@ -101,12 +101,17 @@ class ShadowRoot final : public DocumentFragment,
nsresult Bind();
private:
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&);
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&,
const nsTArray<RefPtr<StyleSheet>>&);
void AppendStyleSheet(StyleSheet& aSheet) {
InsertSheetAt(SheetCount(), aSheet);
}
void AppendAdoptedStyleSheet(StyleSheet& aSheet) {
InsertAdoptedSheetAt(AdoptedSheetCount(), aSheet);
}
/**
* Represents the insertion point in a slot for a given node.
*/
@ -167,6 +172,11 @@ class ShadowRoot final : public DocumentFragment,
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
void NodeInfoChanged(Document* aOldDoc) override {
DocumentFragment::NodeInfoChanged(aOldDoc);
ClearAdoptedStyleSheets();
}
void AddToIdTable(Element* aElement, nsAtom* aId);
void RemoveFromIdTable(Element* aElement, nsAtom* aId);
@ -243,6 +253,12 @@ class ShadowRoot final : public DocumentFragment,
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
}
void SetAdoptedStyleSheets(
const Sequence<OwningNonNull<StyleSheet>>& aAdoptedStyleSheets,
ErrorResult& aRv);
void ClearAdoptedStyleSheets();
protected:
// FIXME(emilio): This will need to become more fine-grained.
void ApplicableRulesChanged();

View File

@ -69,10 +69,8 @@ already_AddRefed<StaticRange> StaticRange::Create(
const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, ErrorResult& aRv) {
RefPtr<StaticRange> staticRange = new StaticRange(aStartBoundary.Container());
aRv = staticRange->SetStartAndEnd(aStartBoundary, aEndBoundary);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
staticRange->DoSetRange(aStartBoundary, aEndBoundary, nullptr);
return staticRange.forget();
}
@ -82,7 +80,23 @@ void StaticRange::DoSetRange(const RangeBoundaryBase<SPT, SRT>& aStartBoundary,
nsINode* aRootNode) {
mStart = aStartBoundary;
mEnd = aEndBoundary;
mIsPositioned = mStart.IsSet();
MOZ_ASSERT(mStart.IsSet() == mEnd.IsSet());
mIsPositioned = mStart.IsSet() && mEnd.IsSet();
}
/* static */
already_AddRefed<StaticRange> StaticRange::Constructor(
const GlobalObject& global, const StaticRangeInit& init, ErrorResult& aRv) {
if (init.mStartContainer->NodeType() == nsINode::DOCUMENT_TYPE_NODE ||
init.mStartContainer->NodeType() == nsINode::ATTRIBUTE_NODE ||
init.mEndContainer->NodeType() == nsINode::DOCUMENT_TYPE_NODE ||
init.mEndContainer->NodeType() == nsINode::ATTRIBUTE_NODE) {
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
return nullptr;
}
return Create(init.mStartContainer, init.mStartOffset, init.mEndContainer,
init.mEndOffset, aRv);
}
JSObject* StaticRange::WrapObject(JSContext* aCx,

View File

@ -8,6 +8,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/RangeBoundary.h"
#include "mozilla/dom/AbstractRange.h"
#include "mozilla/dom/StaticRangeBinding.h"
#include "nsWrapperCache.h"
namespace mozilla {
@ -19,6 +20,10 @@ class StaticRange final : public AbstractRange {
StaticRange() = delete;
explicit StaticRange(const StaticRange& aOther) = delete;
static already_AddRefed<StaticRange> Constructor(const GlobalObject& global,
const StaticRangeInit& init,
ErrorResult& aRv);
/**
* Create() may return `StaticRange` instance which is initialized with
* given range or points. If it fails initializing new range with the

View File

@ -51,11 +51,14 @@ JSObject* StructuredCloneCallbacksRead(JSContext* aCx,
bool StructuredCloneCallbacksWrite(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj, void* aClosure) {
JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired,
void* aClosure) {
StructuredCloneHolderBase* holder =
static_cast<StructuredCloneHolderBase*>(aClosure);
MOZ_ASSERT(holder);
return holder->CustomWriteHandler(aCx, aWriter, aObj);
return holder->CustomWriteHandler(aCx, aWriter, aObj,
aSameProcessScopeRequired);
}
bool StructuredCloneCallbacksReadTransfer(
@ -94,11 +97,13 @@ void StructuredCloneCallbacksFreeTransfer(uint32_t aTag,
bool StructuredCloneCallbacksCanTransfer(JSContext* aCx,
JS::Handle<JSObject*> aObject,
bool* aSameProcessScopeRequired,
void* aClosure) {
StructuredCloneHolderBase* holder =
static_cast<StructuredCloneHolderBase*>(aClosure);
MOZ_ASSERT(holder);
return holder->CustomCanTransferHandler(aCx, aObject);
return holder->CustomCanTransferHandler(aCx, aObject,
aSameProcessScopeRequired);
}
void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId) {
@ -218,7 +223,8 @@ void StructuredCloneHolderBase::CustomFreeTransferHandler(
}
bool StructuredCloneHolderBase::CustomCanTransferHandler(
JSContext* aCx, JS::Handle<JSObject*> aObj) {
JSContext* aCx, JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired) {
return false;
}
@ -304,9 +310,8 @@ void StructuredCloneHolder::ReadFromBuffer(nsIGlobalObject* aGlobal,
mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
mGlobal = aGlobal;
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion,
mStructuredCloneScope, aValue, &sCallbacks,
this)) {
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, CloneScope(),
aValue, &sCallbacks, this)) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
@ -772,9 +777,8 @@ bool WriteFormData(JSStructuredCloneWriter* aWriter, FormData* aFormData,
JSObject* ReadWasmModule(JSContext* aCx, uint32_t aIndex,
StructuredCloneHolder* aHolder) {
MOZ_ASSERT(aHolder);
MOZ_ASSERT(
aHolder->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aHolder->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcess);
#ifdef FUZZING
if (aIndex >= aHolder->WasmModules().Length()) {
return nullptr;
@ -791,9 +795,8 @@ bool WriteWasmModule(JSStructuredCloneWriter* aWriter,
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aWasmModule);
MOZ_ASSERT(aHolder);
MOZ_ASSERT(
aHolder->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aHolder->CloneScope() ==
StructuredCloneHolder::StructuredCloneScope::SameProcess);
// We store the position of the wasmModule in the array as index.
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM,
@ -869,8 +872,7 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
}
if (aTag == SCTAG_DOM_IMAGEBITMAP &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
// Get the current global object.
// This can be null.
JS::RootedObject result(aCx);
@ -887,8 +889,7 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
}
if (aTag == SCTAG_DOM_WASM &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
return ReadWasmModule(aCx, aIndex, this);
}
@ -899,9 +900,9 @@ JSObject* StructuredCloneHolder::CustomReadHandler(
return ReadFullySerializableObjects(aCx, aReader, aTag);
}
bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) {
bool StructuredCloneHolder::CustomWriteHandler(
JSContext* aCx, JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj, bool* aSameProcessScopeRequired) {
if (!mSupportsCloning) {
return false;
}
@ -941,12 +942,20 @@ bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
}
// See if this is an ImageBitmap object.
if (mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
{
ImageBitmap* imageBitmap = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, &obj, imageBitmap))) {
return ImageBitmap::WriteStructuredClone(aWriter, GetSurfaces(),
imageBitmap);
if (imageBitmap->IsWriteOnly()) {
return false;
}
SameProcessScopeRequired(aSameProcessScopeRequired);
if (CloneScope() == StructuredCloneScope::SameProcess) {
return ImageBitmap::WriteStructuredClone(aWriter, GetSurfaces(),
imageBitmap);
}
return false;
}
}
@ -959,13 +968,15 @@ bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
}
// See if this is a WasmModule.
if (mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread &&
JS::IsWasmModuleObject(obj)) {
RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
MOZ_ASSERT(module);
if (JS::IsWasmModuleObject(obj)) {
SameProcessScopeRequired(aSameProcessScopeRequired);
if (CloneScope() == StructuredCloneScope::SameProcess) {
RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
MOZ_ASSERT(module);
return WriteWasmModule(aWriter, module, this);
return WriteWasmModule(aWriter, module, this);
}
return false;
}
{
@ -1015,8 +1026,7 @@ bool StructuredCloneHolder::CustomReadTransferHandler(
}
if (aTag == SCTAG_DOM_CANVAS &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@ -1035,8 +1045,7 @@ bool StructuredCloneHolder::CustomReadTransferHandler(
}
if (aTag == SCTAG_DOM_IMAGEBITMAP &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data = static_cast<ImageBitmapCloneData*>(aContent);
RefPtr<ImageBitmap> bitmap =
@ -1088,8 +1097,7 @@ bool StructuredCloneHolder::CustomWriteTransferHandler(
return true;
}
if (mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
if (CloneScope() == StructuredCloneScope::SameProcess) {
OffscreenCanvas* canvas = nullptr;
rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
if (NS_SUCCEEDED(rv)) {
@ -1113,6 +1121,7 @@ bool StructuredCloneHolder::CustomWriteTransferHandler(
rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(bitmap);
MOZ_ASSERT(!bitmap->IsWriteOnly());
*aExtraData = 0;
*aTag = SCTAG_DOM_IMAGEBITMAP;
@ -1153,8 +1162,7 @@ void StructuredCloneHolder::CustomFreeTransferHandler(
}
if (aTag == SCTAG_DOM_CANVAS &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@ -1163,8 +1171,7 @@ void StructuredCloneHolder::CustomFreeTransferHandler(
}
if (aTag == SCTAG_DOM_IMAGEBITMAP &&
mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
CloneScope() == StructuredCloneScope::SameProcess) {
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data = static_cast<ImageBitmapCloneData*>(aContent);
delete data;
@ -1173,7 +1180,8 @@ void StructuredCloneHolder::CustomFreeTransferHandler(
}
bool StructuredCloneHolder::CustomCanTransferHandler(
JSContext* aCx, JS::Handle<JSObject*> aObj) {
JSContext* aCx, JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired) {
if (!mSupportsTransferring) {
return false;
}
@ -1186,20 +1194,27 @@ bool StructuredCloneHolder::CustomCanTransferHandler(
if (NS_SUCCEEDED(rv)) {
return true;
}
}
if (mStructuredCloneScope ==
StructuredCloneScope::SameProcessDifferentThread) {
OffscreenCanvas* canvas = nullptr;
rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
if (NS_SUCCEEDED(rv)) {
return true;
{
OffscreenCanvas* canvas = nullptr;
nsresult rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
if (NS_SUCCEEDED(rv)) {
SameProcessScopeRequired(aSameProcessScopeRequired);
return CloneScope() == StructuredCloneScope::SameProcess;
}
}
{
ImageBitmap* bitmap = nullptr;
nsresult rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
if (NS_SUCCEEDED(rv)) {
if (bitmap->IsWriteOnly()) {
return false;
}
ImageBitmap* bitmap = nullptr;
rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
if (NS_SUCCEEDED(rv)) {
return true;
}
SameProcessScopeRequired(aSameProcessScopeRequired);
return CloneScope() == StructuredCloneScope::SameProcess;
}
}
@ -1220,5 +1235,14 @@ bool StructuredCloneHolder::TakeTransferredPortsAsSequence(
return true;
}
void StructuredCloneHolder::SameProcessScopeRequired(
bool* aSameProcessScopeRequired) {
MOZ_ASSERT(aSameProcessScopeRequired);
if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) {
mStructuredCloneScope = StructuredCloneScope::SameProcess;
*aSameProcessScopeRequired = true;
}
}
} // namespace dom
} // namespace mozilla

View File

@ -38,8 +38,7 @@ class StructuredCloneHolderBase {
typedef JS::StructuredCloneScope StructuredCloneScope;
StructuredCloneHolderBase(
StructuredCloneScope aScope =
StructuredCloneScope::SameProcessDifferentThread);
StructuredCloneScope aScope = StructuredCloneScope::SameProcess);
virtual ~StructuredCloneHolderBase();
// Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw
@ -56,7 +55,8 @@ class StructuredCloneHolderBase {
virtual bool CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) = 0;
JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired) = 0;
// This method has to be called when this object is not needed anymore.
// It will free memory and the buffer. This has to be called because
@ -86,7 +86,8 @@ class StructuredCloneHolderBase {
void* aContent, uint64_t aExtraData);
virtual bool CustomCanTransferHandler(JSContext* aCx,
JS::Handle<JSObject*> aObj);
JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired);
// These methods are what you should use to read/write data.
@ -189,7 +190,14 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
return mInputStreamArray;
}
StructuredCloneScope CloneScope() const { return mStructuredCloneScope; }
// This method returns the final scope. If the final scope is unknown,
// DifferentProcess is returned because it's the most restrictive one.
StructuredCloneScope CloneScope() const {
if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) {
return StructuredCloneScope::DifferentProcess;
}
return mStructuredCloneScope;
}
// The global object is set internally just during the Read(). This method
// can be used by read functions to retrieve it.
@ -226,7 +234,8 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
virtual bool CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) override;
JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired) override;
virtual bool CustomReadTransferHandler(
JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
@ -245,8 +254,9 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
void* aContent,
uint64_t aExtraData) override;
virtual bool CustomCanTransferHandler(JSContext* aCx,
JS::Handle<JSObject*> aObj) override;
virtual bool CustomCanTransferHandler(
JSContext* aCx, JS::Handle<JSObject*> aObj,
bool* aSameProcessScopeRequired) override;
// These 2 static methods are useful to read/write fully serializable objects.
// They can be used by custom StructuredCloneHolderBase classes to
@ -279,6 +289,8 @@ class StructuredCloneHolder : public StructuredCloneHolderBase {
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv);
void SameProcessScopeRequired(bool* aSameProcessScopeRequired);
bool mSupportsCloning;
bool mSupportsTransferring;

View File

@ -11,15 +11,15 @@ namespace dom {
already_AddRefed<Text> Text::SplitText(uint32_t aOffset, ErrorResult& aRv) {
nsAutoString cutText;
uint32_t length = TextLength();
const uint32_t length = TextLength();
if (aOffset > length) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
uint32_t cutStartOffset = aOffset;
uint32_t cutLength = length - aOffset;
const uint32_t cutStartOffset = aOffset;
const uint32_t cutLength = length - aOffset;
SubstringData(cutStartOffset, cutLength, cutText, aRv);
if (aRv.Failed()) {
return nullptr;

View File

@ -106,7 +106,7 @@ bool WindowNamedPropertiesHandler::getOwnPropDescriptor(
// global scope is still allowed, since |var| only looks up |own|
// properties. But unqualified shadowing will fail, per-spec.
JS::Rooted<JS::Value> v(aCx);
if (!ToJSValue(aCx, WindowProxyHolder(child.forget()), &v)) {
if (!ToJSValue(aCx, WindowProxyHolder(std::move(child)), &v)) {
return false;
}
FillPropertyDescriptor(aDesc, aProxy, 0, v);

View File

@ -31,7 +31,7 @@ class WindowProxyHolder {
explicit WindowProxyHolder(BrowsingContext* aBC) : mBrowsingContext(aBC) {
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
}
explicit WindowProxyHolder(already_AddRefed<BrowsingContext>&& aBC)
explicit WindowProxyHolder(RefPtr<BrowsingContext>&& aBC)
: mBrowsingContext(std::move(aBC)) {
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
}
@ -40,7 +40,7 @@ class WindowProxyHolder {
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
return *this;
}
WindowProxyHolder& operator=(already_AddRefed<BrowsingContext>&& aBC) {
WindowProxyHolder& operator=(RefPtr<BrowsingContext>&& aBC) {
mBrowsingContext = std::move(aBC);
MOZ_ASSERT(mBrowsingContext, "Don't set WindowProxyHolder to null.");
return *this;

View File

@ -0,0 +1,23 @@
<html>
<head>
<script>
function start() {
const xhr = new XMLHttpRequest();
const observer = new ResizeObserver(entries => {
xhr.open('GET', '', false);
xhr.send();
typeof entries[0].borderBoxSize;
typeof entries[0].contentRect;
typeof entries[0].borderBoxSize;
})
observer.observe(document.getElementById('list'), {});
window.close();
}
document.addEventListener('DOMContentLoaded', start);
</script>
</head>
<body>
<li class="" id="list">
</body>
</html>

View File

@ -1,6 +1,6 @@
<html class="reftest-wait">
<head>
<title>Crash [@ nsFocusManager::GetCommonAncestor], part 2</title>
<title>Crash [@ nsFocusManager::GetClosestCommonInclusiveAncestor], part 2</title>
</head>
<body>
<script>

View File

@ -251,3 +251,4 @@ load structured_clone_container_throws.html
load xhr_empty_datauri.html
load xhr_html_nullresponse.html
load xhr-with-pagehide-1.html
pref(layout.css.resizeobserver.enabled,true) load 1555786.html

View File

@ -32,9 +32,6 @@ DOM4_MSG_DEF(DataCloneError, "The object could not be cloned.", NS_ERROR_DOM_DAT
DOM4_MSG_DEF(InvalidPointerId, "Invalid pointer id.", NS_ERROR_DOM_INVALID_POINTER_ERR)
DOM4_MSG_DEF(NotAllowedError, "The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.", NS_ERROR_DOM_NOT_ALLOWED_ERR)
/* XXX Should be JavaScript native TypeError */
DOM4_MSG_DEF(TypeError, "The method parameter is missing or invalid.", NS_ERROR_TYPE_ERR)
/* StringEncoding API errors from http://wiki.whatwg.org/wiki/StringEncoding */
DOM4_MSG_DEF(EncodingError, "The given encoding is not supported.", NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR)

View File

@ -558,6 +558,8 @@ ContentPermissionRequestBase::ContentPermissionRequestBase(
return;
}
mPermissionHandler = doc->GetPermissionDelegateHandler();
mUserHadInteractedWithDocument = doc->UserHasInteracted();
nsDOMNavigationTiming* navTiming = doc->GetNavigationTiming();
@ -650,8 +652,25 @@ ContentPermissionRequestBase::CheckPromptPrefs() {
return PromptResult::Pending;
}
bool ContentPermissionRequestBase::CheckPermissionDelegate() {
// There is case that ContentPermissionRequestBase is constructed without
// window, then mPermissionHandler will be null. So we only check permission
// delegate if we have non-null mPermissionHandler
if (mPermissionHandler &&
!mPermissionHandler->HasPermissionDelegated(mType)) {
return false;
}
return true;
}
nsresult ContentPermissionRequestBase::ShowPrompt(
ContentPermissionRequestBase::PromptResult& aResult) {
if (!CheckPermissionDelegate()) {
aResult = PromptResult::Denied;
return NS_OK;
}
aResult = CheckPromptPrefs();
if (aResult != PromptResult::Pending) {

View File

@ -10,6 +10,7 @@
#include "nsIMutableArray.h"
#include "mozilla/dom/PContentPermissionRequestChild.h"
#include "mozilla/dom/ipc/IdType.h"
#include "PermissionDelegateHandler.h"
// Microsoft's API Name hackery sucks
// XXXbz Doing this in a header is a gigantic footgun. See
@ -137,6 +138,9 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
PromptResult CheckPromptPrefs();
// Check if the permission has an opportunity to request.
bool CheckPermissionDelegate();
enum class DelayedTaskType {
Allow,
Deny,
@ -155,6 +159,7 @@ class ContentPermissionRequestBase : public nsIContentPermissionRequest {
nsCOMPtr<nsIPrincipal> mTopLevelPrincipal;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
RefPtr<PermissionDelegateHandler> mPermissionHandler;
nsCString mPrefName;
nsCString mType;
bool mIsHandlingUserInput;

View File

@ -713,6 +713,8 @@ nsresult nsContentSink::ProcessStyleLinkFromHeader(
CORS_NONE,
aTitle,
aMedia,
/* integrity = */ EmptyString(),
/* nonce = */ EmptyString(),
aAlternate ? Loader::HasAlternateRel::Yes : Loader::HasAlternateRel::No,
Loader::IsInline::No,
Loader::IsExplicitlyEnabled::No,
@ -1442,7 +1444,8 @@ void nsContentSink::DropParserAndPerfHint(void) {
// actually broken.
// Drop our reference to the parser to get rid of a circular
// reference.
RefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
RefPtr<nsParserBase> kungFuDeathGrip = std::move(mParser);
mozilla::Unused << kungFuDeathGrip;
if (mDynamicLowerValue) {
// Reset the performance hint which was set to FALSE

View File

@ -329,16 +329,28 @@ mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
int32_t nsContentUtils::sInnerOrOuterWindowCount = 0;
uint32_t nsContentUtils::sInnerOrOuterWindowSerialCounter = 0;
template int32_t nsContentUtils::ComparePoints(
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary);
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RangeBoundary& aFirstBoundary,
const RawRangeBoundary& aSecondBoundary);
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RawRangeBoundary& aFirstBoundary,
const RangeBoundary& aSecondBoundary);
template Maybe<int32_t> nsContentUtils::ComparePoints(
const RawRangeBoundary& aFirstBoundary,
const RawRangeBoundary& aSecondBoundary);
template int32_t nsContentUtils::ComparePoints_Deprecated(
const RangeBoundary& aFirstBoundary, const RangeBoundary& aSecondBoundary,
bool* aDisconnected);
template int32_t nsContentUtils::ComparePoints(
template int32_t nsContentUtils::ComparePoints_Deprecated(
const RangeBoundary& aFirstBoundary,
const RawRangeBoundary& aSecondBoundary, bool* aDisconnected);
template int32_t nsContentUtils::ComparePoints(
template int32_t nsContentUtils::ComparePoints_Deprecated(
const RawRangeBoundary& aFirstBoundary,
const RangeBoundary& aSecondBoundary, bool* aDisconnected);
template int32_t nsContentUtils::ComparePoints(
template int32_t nsContentUtils::ComparePoints_Deprecated(
const RawRangeBoundary& aFirstBoundary,
const RawRangeBoundary& aSecondBoundary, bool* aDisconnected);
@ -1956,12 +1968,7 @@ bool nsContentUtils::InProlog(nsINode* aNode) {
bool nsContentUtils::IsCallerChrome() {
MOZ_ASSERT(NS_IsMainThread());
if (SubjectPrincipal() == sSystemPrincipal) {
return true;
}
// If the check failed, look for UniversalXPConnect on the cx compartment.
return xpc::IsUniversalXPConnectEnabled(GetCurrentJSContext());
return SubjectPrincipal() == sSystemPrincipal;
}
#ifdef FUZZING
@ -2248,8 +2255,8 @@ nsINode* nsContentUtils::Retarget(nsINode* aTargetA, nsINode* aTargetB) {
}
// static
nsresult nsContentUtils::GetAncestors(nsINode* aNode,
nsTArray<nsINode*>& aArray) {
nsresult nsContentUtils::GetInclusiveAncestors(nsINode* aNode,
nsTArray<nsINode*>& aArray) {
while (aNode) {
aArray.AppendElement(aNode);
aNode = aNode->GetParentNode();
@ -2258,7 +2265,7 @@ nsresult nsContentUtils::GetAncestors(nsINode* aNode,
}
// static
nsresult nsContentUtils::GetAncestorsAndOffsets(
nsresult nsContentUtils::GetInclusiveAncestorsAndOffsets(
nsINode* aNode, int32_t aOffset, nsTArray<nsIContent*>* aAncestorNodes,
nsTArray<int32_t>* aAncestorOffsets) {
NS_ENSURE_ARG_POINTER(aNode);
@ -2363,10 +2370,24 @@ bool nsContentUtils::PositionIsBefore(nsINode* aNode1, nsINode* aNode2,
}
/* static */
int32_t nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* aParent2, int32_t aOffset2,
bool* aDisconnected,
ComparePointsCache* aParent1Cache) {
Maybe<int32_t> nsContentUtils::ComparePoints(
const nsINode* aParent1, int32_t aOffset1, const nsINode* aParent2,
int32_t aOffset2, ComparePointsCache* aParent1Cache) {
bool disconnected{false};
const int32_t order = ComparePoints_Deprecated(
aParent1, aOffset1, aParent2, aOffset2, &disconnected, aParent1Cache);
if (disconnected) {
return Nothing();
}
return Some(order);
}
/* static */
int32_t nsContentUtils::ComparePoints_Deprecated(
const nsINode* aParent1, int32_t aOffset1, const nsINode* aParent2,
int32_t aOffset2, bool* aDisconnected, ComparePointsCache* aParent1Cache) {
if (aParent1 == aParent2) {
// XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
// of nsINode::ComputeIndexOf(), but this compares such invalid
@ -2374,9 +2395,9 @@ int32_t nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
return aOffset1 < aOffset2 ? -1 : aOffset1 > aOffset2 ? 1 : 0;
}
AutoTArray<nsINode*, 32> parents1, parents2;
nsINode* node1 = aParent1;
nsINode* node2 = aParent2;
AutoTArray<const nsINode*, 32> parents1, parents2;
const nsINode* node1 = aParent1;
const nsINode* node2 = aParent2;
do {
parents1.AppendElement(node1);
node1 = node1->GetParentNode();
@ -2399,11 +2420,11 @@ int32_t nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
}
// Find where the parent chains differ
nsINode* parent = parents1.ElementAt(pos1);
const nsINode* parent = parents1.ElementAt(pos1);
uint32_t len;
for (len = std::min(pos1, pos2); len > 0; --len) {
nsINode* child1 = parents1.ElementAt(--pos1);
nsINode* child2 = parents2.ElementAt(--pos2);
const nsINode* child1 = parents1.ElementAt(--pos1);
const nsINode* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
int32_t child1index = aParent1Cache
? aParent1Cache->ComputeIndexOf(parent, child1)
@ -2420,13 +2441,13 @@ int32_t nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
"should have run out of parent chain for one of the nodes");
if (!pos1) {
nsINode* child2 = parents2.ElementAt(--pos2);
const nsINode* child2 = parents2.ElementAt(--pos2);
// XXX aOffset1 may be -1 as mentioned above. So, why does this return
// it's *before* of the valid DOM point?
return aOffset1 <= parent->ComputeIndexOf(child2) ? -1 : 1;
}
nsINode* child1 = parents1.ElementAt(--pos1);
const nsINode* child1 = parents1.ElementAt(--pos1);
// XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
// *after* of the valid DOM point?
int32_t child1index = aParent1Cache
@ -2485,7 +2506,27 @@ nsINode* nsContentUtils::GetCommonAncestorUnderInteractiveContent(
/* static */
template <typename FPT, typename FRT, typename SPT, typename SRT>
int32_t nsContentUtils::ComparePoints(
Maybe<int32_t> nsContentUtils::ComparePoints(
const RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
const RangeBoundaryBase<SPT, SRT>& aSecondBoundary) {
if (!aFirstBoundary.IsSet() || !aSecondBoundary.IsSet()) {
return Nothing{};
}
bool disconnected{false};
const int32_t order =
ComparePoints_Deprecated(aFirstBoundary, aSecondBoundary, &disconnected);
if (disconnected) {
return Nothing{};
}
return Some(order);
}
/* static */
template <typename FPT, typename FRT, typename SPT, typename SRT>
int32_t nsContentUtils::ComparePoints_Deprecated(
const RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
const RangeBoundaryBase<SPT, SRT>& aSecondBoundary, bool* aDisconnected) {
if (NS_WARN_IF(!aFirstBoundary.IsSet()) ||
@ -2494,9 +2535,14 @@ int32_t nsContentUtils::ComparePoints(
}
// XXX Re-implement this without calling `Offset()` as far as possible,
// and the other overload should be an alias of this.
return ComparePoints(aFirstBoundary.Container(), aFirstBoundary.Offset(),
aSecondBoundary.Container(), aSecondBoundary.Offset(),
aDisconnected);
return ComparePoints_Deprecated(
aFirstBoundary.Container(),
*aFirstBoundary.Offset(
RangeBoundaryBase<FPT, FRT>::OffsetFilter::kValidOrInvalidOffsets),
aSecondBoundary.Container(),
*aSecondBoundary.Offset(
RangeBoundaryBase<SPT, SRT>::OffsetFilter::kValidOrInvalidOffsets),
aDisconnected);
}
inline bool IsCharInSet(const char* aSet, const char16_t aChar) {

View File

@ -372,12 +372,18 @@ class nsContentUtils {
static nsINode* Retarget(nsINode* aTargetA, nsINode* aTargetB);
/*
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*
* This method fills the |aArray| with all ancestor nodes of |aNode|
* including |aNode| at the zero index.
*
*/
static nsresult GetAncestors(nsINode* aNode, nsTArray<nsINode*>& aArray);
static nsresult GetInclusiveAncestors(nsINode* aNode,
nsTArray<nsINode*>& aArray);
/*
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*
* This method fills |aAncestorNodes| with all ancestor nodes of |aNode|
* including |aNode| (QI'd to nsIContent) at the zero index.
* For each ancestor, there is a corresponding element in |aAncestorOffsets|
@ -385,16 +391,19 @@ class nsContentUtils {
*
* This method just sucks.
*/
static nsresult GetAncestorsAndOffsets(nsINode* aNode, int32_t aOffset,
nsTArray<nsIContent*>* aAncestorNodes,
nsTArray<int32_t>* aAncestorOffsets);
static nsresult GetInclusiveAncestorsAndOffsets(
nsINode* aNode, int32_t aOffset, nsTArray<nsIContent*>* aAncestorNodes,
nsTArray<int32_t>* aAncestorOffsets);
/**
* Returns the common ancestor, if any, for two nodes.
* Returns the closest common inclusive ancestor
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) , if any,
* for two nodes.
*
* Returns null if the nodes are disconnected.
*/
static nsINode* GetCommonAncestor(nsINode* aNode1, nsINode* aNode2) {
static nsINode* GetClosestCommonInclusiveAncestor(nsINode* aNode1,
nsINode* aNode2) {
if (aNode1 == aNode2) {
return aNode1;
}
@ -444,7 +453,7 @@ class nsContentUtils {
int32_t* aNode2Index = nullptr);
struct ComparePointsCache {
int32_t ComputeIndexOf(nsINode* aParent, nsINode* aChild) {
int32_t ComputeIndexOf(const nsINode* aParent, const nsINode* aChild) {
if (aParent == mParent && aChild == mChild) {
return mIndex;
}
@ -456,11 +465,35 @@ class nsContentUtils {
}
private:
nsINode* mParent = nullptr;
nsINode* mChild = nullptr;
const nsINode* mParent = nullptr;
const nsINode* mChild = nullptr;
int32_t mIndex = 0;
};
/**
* Utility routine to compare two "points", where a point is a node/offset
* pair.
* Pass a cache object as aParent1Cache if you expect to repeatedly
* call this function with the same value as aParent1.
*
* XXX aOffset1 and aOffset2 should be uint32_t since valid offset value is
* between 0 - UINT32_MAX. However, these methods work even with
* negative offset values! E.g., when aOffset1 is -1 and aOffset is 0,
* these methods return -1. Some root callers depend on this behavior.
*
* @return -1 if point1 < point2,
* 1 if point1 > point2,
* 0 if point1 == point2.
* `Nothing` if the two nodes aren't in the same connected subtree.
*/
static Maybe<int32_t> ComparePoints(
const nsINode* aParent1, int32_t aOffset1, const nsINode* aParent2,
int32_t aOffset2, ComparePointsCache* aParent1Cache = nullptr);
template <typename FPT, typename FRT, typename SPT, typename SRT>
static Maybe<int32_t> ComparePoints(
const mozilla::RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
const mozilla::RangeBoundaryBase<SPT, SRT>& aSecondBoundary);
/**
* Utility routine to compare two "points", where a point is a
* node/offset pair
@ -480,12 +513,12 @@ class nsContentUtils {
* On the other hand, nsINode can have ATTRCHILD_ARRAY_MAX_CHILD_COUN
* (0x3FFFFF) at most. Therefore, they can be int32_t for now.
*/
static int32_t ComparePoints(nsINode* aParent1, int32_t aOffset1,
nsINode* aParent2, int32_t aOffset2,
bool* aDisconnected = nullptr,
ComparePointsCache* aParent1Cache = nullptr);
static int32_t ComparePoints_Deprecated(
const nsINode* aParent1, int32_t aOffset1, const nsINode* aParent2,
int32_t aOffset2, bool* aDisconnected = nullptr,
ComparePointsCache* aParent1Cache = nullptr);
template <typename FPT, typename FRT, typename SPT, typename SRT>
static int32_t ComparePoints(
static int32_t ComparePoints_Deprecated(
const mozilla::RangeBoundaryBase<FPT, FRT>& aFirstBoundary,
const mozilla::RangeBoundaryBase<SPT, SRT>& aSecondBoundary,
bool* aDisconnected = nullptr);

View File

@ -727,7 +727,7 @@ static bool IsSelectionInsideRuby(Selection* aSelection) {
;
for (auto i : IntegerRange(rangeCount)) {
nsRange* range = aSelection->GetRangeAt(i);
if (!IsInsideRuby(range->GetCommonAncestor())) {
if (!IsInsideRuby(range->GetClosestCommonInclusiveAncestor())) {
return false;
}
}

View File

@ -286,7 +286,7 @@ void nsMutationReceiver::ContentRemoved(nsIContent* aChild,
if (Observer()->GetReceiverFor(aChild, false, false) != orig) {
bool transientExists = false;
bool isNewEntry = false;
nsCOMArray<nsMutationReceiver>* transientReceivers =
const auto& transientReceivers =
Observer()->mTransientReceivers.LookupForAdd(aChild).OrInsert(
[&isNewEntry]() {
isNewEntry = true;
@ -699,7 +699,7 @@ void nsDOMMutationObserver::TakeRecords(
current->mNext.swap(next);
if (!mMergeAttributeRecords ||
!MergeableAttributeRecord(aRetVal.SafeLastElement(nullptr), current)) {
*aRetVal.AppendElement() = current.forget();
*aRetVal.AppendElement() = std::move(current);
}
current.swap(next);
}
@ -752,7 +752,7 @@ already_AddRefed<nsDOMMutationObserver> nsDOMMutationObserver::Constructor(
}
bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc());
RefPtr<nsDOMMutationObserver> observer =
new nsDOMMutationObserver(window.forget(), aCb, isChrome);
new nsDOMMutationObserver(std::move(window), aCb, isChrome);
return observer.forget();
}
@ -992,7 +992,7 @@ void nsAutoMutationBatch::Done() {
}
if (allObservers.Length()) {
nsCOMArray<nsMutationReceiver>* transientReceivers =
const auto& transientReceivers =
ob->mTransientReceivers.LookupForAdd(removed).OrInsert(
[]() { return new nsCOMArray<nsMutationReceiver>(); });
for (uint32_t k = 0; k < allObservers.Length(); ++k) {

View File

@ -429,9 +429,9 @@ class nsAnimationReceiver : public nsMutationReceiver {
class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
public:
nsDOMMutationObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
nsDOMMutationObserver(nsCOMPtr<nsPIDOMWindowInner>&& aOwner,
mozilla::dom::MutationCallback& aCb, bool aChrome)
: mOwner(aOwner),
: mOwner(std::move(aOwner)),
mLastPendingMutation(nullptr),
mPendingMutationCount(0),
mCallback(&aCb),
@ -487,11 +487,11 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
MOZ_ASSERT(record);
if (!mLastPendingMutation) {
MOZ_ASSERT(!mFirstPendingMutation);
mFirstPendingMutation = record.forget();
mFirstPendingMutation = std::move(record);
mLastPendingMutation = mFirstPendingMutation;
} else {
MOZ_ASSERT(mFirstPendingMutation);
mLastPendingMutation->mNext = record.forget();
mLastPendingMutation->mNext = std::move(record);
mLastPendingMutation = mLastPendingMutation->mNext;
}
++mPendingMutationCount;
@ -500,11 +500,11 @@ class nsDOMMutationObserver final : public nsISupports, public nsWrapperCache {
void ClearPendingRecords() {
// Break down the pending mutation record list so that cycle collector
// can delete the objects sooner.
RefPtr<nsDOMMutationRecord> current = mFirstPendingMutation.forget();
RefPtr<nsDOMMutationRecord> current = std::move(mFirstPendingMutation);
mLastPendingMutation = nullptr;
mPendingMutationCount = 0;
while (current) {
current = current->mNext.forget();
current = std::move(current->mNext);
}
}

View File

@ -2870,7 +2870,7 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId,
IDBOpenDBOptions options;
JS::Rooted<JS::Value> optionsVal(aCx, aOptions);
if (!options.Init(aCx, optionsVal)) {
return NS_ERROR_TYPE_ERR;
return NS_ERROR_UNEXPECTED;
}
quota::PersistenceType persistenceType =

View File

@ -8,7 +8,6 @@
* designed to be used as input to the C preprocessor *only*.
*/
DEPRECATED_OPERATION(EnablePrivilege)
DEPRECATED_OPERATION(MutationEvent)
DEPRECATED_OPERATION(Components)
DEPRECATED_OPERATION(NodeIteratorDetach)
@ -16,9 +15,6 @@ DEPRECATED_OPERATION(LenientThis)
DEPRECATED_OPERATION(MozGetAsFile)
DEPRECATED_OPERATION(UseOfCaptureEvents)
DEPRECATED_OPERATION(UseOfReleaseEvents)
DEPRECATED_OPERATION(UseOfDOM3LoadMethod)
DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod)
DEPRECATED_OPERATION(ShowModalDialog)
DEPRECATED_OPERATION(SyncXMLHttpRequest)
DEPRECATED_OPERATION(Window_Cc_ontrollers)
DEPRECATED_OPERATION(ImportXULIntoContent)
@ -26,7 +22,6 @@ DEPRECATED_OPERATION(NavigatorGetUserMedia)
DEPRECATED_OPERATION(WebrtcDeprecatedPrefix)
DEPRECATED_OPERATION(RTCPeerConnectionGetStreams)
DEPRECATED_OPERATION(AppCache)
DEPRECATED_OPERATION(AppCacheInsecure)
DEPRECATED_OPERATION(PrefixedImageSmoothingEnabled)
DEPRECATED_OPERATION(LenientSetter)
DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap)

View File

@ -174,23 +174,30 @@ class EncodingScope {
bool EncodingScope::IsLimited() const { return mSelection || mRange || mNode; }
struct RangeBoundaryPathsAndOffsets {
using ContainerPath = AutoTArray<nsIContent*, 8>;
using ContainerOffsets = AutoTArray<int32_t, 8>;
struct RangeBoundariesInclusiveAncestorsAndOffsets {
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*/
using InclusiveAncestors = AutoTArray<nsIContent*, 8>;
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*/
using InclusiveAncestorsOffsets = AutoTArray<int32_t, 8>;
// The first node is the range's boundary node, the following ones the
// ancestors.
ContainerPath mStartContainerPath;
InclusiveAncestors mInclusiveAncestorsOfStart;
// The first offset represents where at the boundary node the range starts.
// Each other offset is the index of the child relative to its parent.
ContainerOffsets mStartContainerOffsets;
InclusiveAncestorsOffsets mInclusiveAncestorsOffsetsOfStart;
// The first node is the range's boundary node, the following one the
// ancestors.
ContainerPath mEndContainerPath;
InclusiveAncestors mInclusiveAncestorsOfEnd;
// The first offset represents where at the boundary node the range ends.
// Each other offset is the index of the child relative to its parent.
ContainerOffsets mEndContainerOffsets;
InclusiveAncestorsOffsets mInclusiveAncestorsOffsetsOfEnd;
};
struct ContextInfoDepth {
@ -237,7 +244,8 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
// This serializes the content of aNode.
nsresult SerializeToStringIterative(nsINode* aNode);
nsresult SerializeRangeToString(nsRange* aRange);
nsresult SerializeRangeNodes(nsRange* aRange, nsINode* aNode, int32_t aDepth);
nsresult SerializeRangeNodes(const nsRange* aRange, nsINode* aNode,
int32_t aDepth);
nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray);
nsresult SerializeRangeContextEnd();
@ -312,7 +320,10 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
EncodingScope mEncodingScope;
nsCOMPtr<nsIContentSerializer> mSerializer;
Maybe<TextStreamer> mTextStreamer;
nsCOMPtr<nsINode> mCommonAncestorOfRange;
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*/
nsCOMPtr<nsINode> mClosestCommonInclusiveAncestorOfRange;
nsCOMPtr<nsIDocumentEncoderNodeFixup> mNodeFixup;
nsString mMimeType;
@ -322,8 +333,12 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
ContextInfoDepth mContextInfoDepth;
int32_t mStartRootIndex;
int32_t mEndRootIndex;
AutoTArray<nsINode*, 8> mCommonAncestors;
RangeBoundaryPathsAndOffsets mRangeBoundaryPathsAndOffsets;
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor.
*/
AutoTArray<nsINode*, 8> mCommonInclusiveAncestors;
RangeBoundariesInclusiveAncestorsAndOffsets
mRangeBoundariesInclusiveAncestorsAndOffsets;
AutoTArray<AutoTArray<nsINode*, 8>, 8> mRangeContexts;
// Whether the serializer cares about being notified to scan elements to
// keep track of whether they are preformatted. This stores the out
@ -349,7 +364,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(nsDocumentEncoder, mDocument,
mEncodingScope.mSelection, mEncodingScope.mRange,
mEncodingScope.mNode, mSerializer,
mCommonAncestorOfRange)
mClosestCommonInclusiveAncestorOfRange)
nsDocumentEncoder::nsDocumentEncoder()
: mEncoding(nullptr), mIsCopying(false), mCachedBuffer(nullptr) {
@ -367,9 +382,9 @@ void nsDocumentEncoder::Initialize(bool aClearCachedSerializer) {
mHaltRangeHint = false;
mDisableContextSerialize = false;
mEncodingScope = {};
mCommonAncestorOfRange = nullptr;
mClosestCommonInclusiveAncestorOfRange = nullptr;
mNodeFixup = nullptr;
mRangeBoundaryPathsAndOffsets = {};
mRangeBoundariesInclusiveAncestorsAndOffsets = {};
if (aClearCachedSerializer) {
mSerializer = nullptr;
}
@ -432,9 +447,10 @@ nsresult nsDocumentEncoder::SerializeSelection() {
!ParentIsTR(content)) {
if (!prevNode) {
// Went from a non-<tr> to a <tr>
mCommonAncestors.Clear();
nsContentUtils::GetAncestors(node->GetParentNode(), mCommonAncestors);
rv = SerializeRangeContextStart(mCommonAncestors);
mCommonInclusiveAncestors.Clear();
nsContentUtils::GetInclusiveAncestors(node->GetParentNode(),
mCommonInclusiveAncestors);
rv = SerializeRangeContextStart(mCommonInclusiveAncestors);
NS_ENSURE_SUCCESS(rv, rv);
// Don't let SerializeRangeToString serialize the context again
mDisableContextSerialize = true;
@ -813,7 +829,7 @@ nsresult nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode) {
static bool IsTextNode(nsINode* aNode) { return aNode && aNode->IsText(); }
nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
nsresult nsDocumentEncoder::SerializeRangeNodes(const nsRange* const aRange,
nsINode* const aNode,
const int32_t aDepth) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
@ -828,17 +844,18 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
// get start and end nodes for this recursion level
nsCOMPtr<nsIContent> startNode, endNode;
{
auto& startContainerPath =
mRangeBoundaryPathsAndOffsets.mStartContainerPath;
auto& endContainerPath = mRangeBoundaryPathsAndOffsets.mEndContainerPath;
auto& inclusiveAncestorsOfStart =
mRangeBoundariesInclusiveAncestorsAndOffsets.mInclusiveAncestorsOfStart;
auto& inclusiveAncestorsOfEnd =
mRangeBoundariesInclusiveAncestorsAndOffsets.mInclusiveAncestorsOfEnd;
int32_t start = mStartRootIndex - aDepth;
if (start >= 0 && (uint32_t)start <= startContainerPath.Length()) {
startNode = startContainerPath[start];
if (start >= 0 && (uint32_t)start <= inclusiveAncestorsOfStart.Length()) {
startNode = inclusiveAncestorsOfStart[start];
}
int32_t end = mEndRootIndex - aDepth;
if (end >= 0 && (uint32_t)end <= endContainerPath.Length()) {
endNode = endContainerPath[end];
if (end >= 0 && (uint32_t)end <= inclusiveAncestorsOfEnd.Length()) {
endNode = inclusiveAncestorsOfEnd[end];
}
}
@ -864,7 +881,7 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
rv = SerializeNodeEnd(*aNode);
NS_ENSURE_SUCCESS(rv, rv);
} else {
if (aNode != mCommonAncestorOfRange) {
if (aNode != mClosestCommonInclusiveAncestorOfRange) {
if (IncludeInContext(aNode)) {
// halt the incrementing of mContextInfoDepth. This is
// so paste client will include this node in paste.
@ -882,18 +899,21 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
NS_ENSURE_SUCCESS(rv, rv);
}
const auto& startContainerOffsets =
mRangeBoundaryPathsAndOffsets.mStartContainerOffsets;
const auto& endContainerOffsets =
mRangeBoundaryPathsAndOffsets.mEndContainerOffsets;
const auto& inclusiveAncestorsOffsetsOfStart =
mRangeBoundariesInclusiveAncestorsAndOffsets
.mInclusiveAncestorsOffsetsOfStart;
const auto& inclusiveAncestorsOffsetsOfEnd =
mRangeBoundariesInclusiveAncestorsAndOffsets
.mInclusiveAncestorsOffsetsOfEnd;
// do some calculations that will tell us which children of this
// node are in the range.
int32_t startOffset = 0, endOffset = -1;
if (startNode == content && mStartRootIndex >= aDepth) {
startOffset = startContainerOffsets[mStartRootIndex - aDepth];
startOffset =
inclusiveAncestorsOffsetsOfStart[mStartRootIndex - aDepth];
}
if (endNode == content && mEndRootIndex >= aDepth) {
endOffset = endContainerOffsets[mEndRootIndex - aDepth];
endOffset = inclusiveAncestorsOffsetsOfEnd[mEndRootIndex - aDepth];
}
// generated content will cause offset values of -1 to be returned.
uint32_t childCount = content->GetChildCount();
@ -904,7 +924,7 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
else {
// if we are at the "tip" of the selection, endOffset is fine.
// otherwise, we need to add one. This is because of the semantics
// of the offset list created by GetAncestorsAndOffsets(). The
// of the offset list created by GetInclusiveAncestorsAndOffsets(). The
// intermediate points on the list use the endOffset of the
// location of the ancestor, rather than just past it. So we need
// to add one here in order to include it in the children we serialize.
@ -937,7 +957,7 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
}
// serialize the end of this node
if (aNode != mCommonAncestorOfRange) {
if (aNode != mClosestCommonInclusiveAncestorOfRange) {
rv = SerializeNodeEnd(*aNode);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -999,9 +1019,10 @@ nsresult nsDocumentEncoder::SerializeRangeContextEnd() {
nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange) {
if (!aRange || aRange->Collapsed()) return NS_OK;
mCommonAncestorOfRange = aRange->GetCommonAncestor();
mClosestCommonInclusiveAncestorOfRange =
aRange->GetClosestCommonInclusiveAncestor();
if (!mCommonAncestorOfRange) {
if (!mClosestCommonInclusiveAncestorOfRange) {
return NS_OK;
}
@ -1014,30 +1035,37 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange) {
int32_t endOffset = aRange->EndOffset();
mContextInfoDepth = {};
mCommonAncestors.Clear();
mCommonInclusiveAncestors.Clear();
mRangeBoundaryPathsAndOffsets = {};
auto& startContainerPath = mRangeBoundaryPathsAndOffsets.mStartContainerPath;
auto& startContainerOffsets =
mRangeBoundaryPathsAndOffsets.mStartContainerOffsets;
auto& endContainerPath = mRangeBoundaryPathsAndOffsets.mEndContainerPath;
auto& endContainerOffsets =
mRangeBoundaryPathsAndOffsets.mEndContainerOffsets;
mRangeBoundariesInclusiveAncestorsAndOffsets = {};
auto& inclusiveAncestorsOfStart =
mRangeBoundariesInclusiveAncestorsAndOffsets.mInclusiveAncestorsOfStart;
auto& inclusiveAncestorsOffsetsOfStart =
mRangeBoundariesInclusiveAncestorsAndOffsets
.mInclusiveAncestorsOffsetsOfStart;
auto& inclusiveAncestorsOfEnd =
mRangeBoundariesInclusiveAncestorsAndOffsets.mInclusiveAncestorsOfEnd;
auto& inclusiveAncestorsOffsetsOfEnd =
mRangeBoundariesInclusiveAncestorsAndOffsets
.mInclusiveAncestorsOffsetsOfEnd;
nsContentUtils::GetAncestors(mCommonAncestorOfRange, mCommonAncestors);
nsContentUtils::GetAncestorsAndOffsets(
startContainer, startOffset, &startContainerPath, &startContainerOffsets);
nsContentUtils::GetAncestorsAndOffsets(
endContainer, endOffset, &endContainerPath, &endContainerOffsets);
nsContentUtils::GetInclusiveAncestors(mClosestCommonInclusiveAncestorOfRange,
mCommonInclusiveAncestors);
nsContentUtils::GetInclusiveAncestorsAndOffsets(
startContainer, startOffset, &inclusiveAncestorsOfStart,
&inclusiveAncestorsOffsetsOfStart);
nsContentUtils::GetInclusiveAncestorsAndOffsets(
endContainer, endOffset, &inclusiveAncestorsOfEnd,
&inclusiveAncestorsOffsetsOfEnd);
nsCOMPtr<nsIContent> commonContent =
do_QueryInterface(mCommonAncestorOfRange);
mStartRootIndex = startContainerPath.IndexOf(commonContent);
mEndRootIndex = endContainerPath.IndexOf(commonContent);
do_QueryInterface(mClosestCommonInclusiveAncestorOfRange);
mStartRootIndex = inclusiveAncestorsOfStart.IndexOf(commonContent);
mEndRootIndex = inclusiveAncestorsOfEnd.IndexOf(commonContent);
nsresult rv = NS_OK;
rv = SerializeRangeContextStart(mCommonAncestors);
rv = SerializeRangeContextStart(mCommonInclusiveAncestors);
NS_ENSURE_SUCCESS(rv, rv);
if (startContainer == endContainer && IsTextNode(startContainer)) {
@ -1057,7 +1085,7 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange) {
rv = SerializeNodeEnd(*startContainer);
NS_ENSURE_SUCCESS(rv, rv);
} else {
rv = SerializeRangeNodes(aRange, mCommonAncestorOfRange, 0);
rv = SerializeRangeNodes(aRange, mClosestCommonInclusiveAncestorOfRange, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = SerializeRangeContextEnd();
@ -1315,7 +1343,7 @@ nsHTMLCopyEncoder::SetSelection(Selection* aSelection) {
// selection, then go through the flattened tree and serialize the selected
// nodes", effectively serializing the composed tree.
RefPtr<nsRange> range = aSelection->GetRangeAt(0);
nsINode* commonParent = range->GetCommonAncestor();
nsINode* commonParent = range->GetClosestCommonInclusiveAncestor();
for (nsCOMPtr<nsIContent> selContent(do_QueryInterface(commonParent));
selContent; selContent = selContent->GetParent()) {
@ -1404,13 +1432,15 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
&mNeedsPreformatScanning, aContextString);
// leaf of ancestors might be text node. If so discard it.
int32_t count = mCommonAncestors.Length();
int32_t count = mCommonInclusiveAncestors.Length();
int32_t i;
nsCOMPtr<nsINode> node;
if (count > 0) node = mCommonAncestors.ElementAt(0);
if (count > 0) {
node = mCommonInclusiveAncestors.ElementAt(0);
}
if (node && IsTextNode(node)) {
mCommonAncestors.RemoveElementAt(0);
mCommonInclusiveAncestors.RemoveElementAt(0);
if (mContextInfoDepth.mStart) {
--mContextInfoDepth.mStart;
}
@ -1422,13 +1452,13 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
i = count;
while (i > 0) {
node = mCommonAncestors.ElementAt(--i);
node = mCommonInclusiveAncestors.ElementAt(--i);
rv = SerializeNodeStart(*node, 0, -1);
NS_ENSURE_SUCCESS(rv, rv);
}
// i = 0; guaranteed by above
while (i < count) {
node = mCommonAncestors.ElementAt(i++);
node = mCommonInclusiveAncestors.ElementAt(i++);
rv = SerializeNodeEnd(*node);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1470,7 +1500,7 @@ nsresult nsHTMLCopyEncoder::PromoteRange(nsRange* inRange) {
uint32_t startOffset = inRange->StartOffset();
nsCOMPtr<nsINode> endNode = inRange->GetEndContainer();
uint32_t endOffset = inRange->EndOffset();
nsCOMPtr<nsINode> common = inRange->GetCommonAncestor();
nsCOMPtr<nsINode> common = inRange->GetClosestCommonInclusiveAncestor();
nsCOMPtr<nsINode> opStartNode;
nsCOMPtr<nsINode> opEndNode;

View File

@ -910,7 +910,7 @@ nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow) {
// window, or an ancestor of the focused window. Either way, the focus is no
// longer valid, so it needs to be updated.
RefPtr<Element> oldFocusedElement = mFocusedElement.forget();
RefPtr<Element> oldFocusedElement = std::move(mFocusedElement);
nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
RefPtr<PresShell> presShell = focusedDocShell->GetPresShell();

View File

@ -40,6 +40,7 @@
#include "mozilla/dom/VisualViewport.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Result.h"
#if defined(MOZ_WIDGET_ANDROID)
# include "mozilla/dom/WindowOrientationObserver.h"
#endif
@ -4489,24 +4490,19 @@ Storage* nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) {
if (!mDoc) {
access = StorageAccess::eDeny;
} else if (!StoragePartitioningEnabled(access, mDoc->CookieSettings())) {
nsCOMPtr<nsIURI> uri;
Unused << mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
static const char* kPrefName =
"privacy.restrict3rdpartystorage.partitionedHosts";
if (!uri || !nsContentUtils::IsURIInPrefList(uri, kPrefName)) {
bool isInList = false;
mDoc->NodePrincipal()->IsURIInPrefList(kPrefName, &isInList);
if (!isInList) {
access = StorageAccess::eDeny;
}
}
}
if (access == StorageAccess::eDeny) {
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) != 0) {
// Only raise the exception if we are denying storage access due to
// sandbox restrictions. If we're denying storage access due to other
// reasons (e.g. cookie policy enforcement), withhold raising the
// exception in an effort to achieve more web compatibility.
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
}
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
@ -5422,10 +5418,11 @@ Maybe<ClientState> nsGlobalWindowInner::GetClientState() const {
MOZ_ASSERT(NS_IsMainThread());
Maybe<ClientState> clientState;
if (mClientSource) {
ClientState state;
nsresult rv = mClientSource->SnapshotState(&state);
if (NS_SUCCEEDED(rv)) {
clientState.emplace(state);
Result<ClientState, ErrorResult> res = mClientSource->SnapshotState();
if (res.isOk()) {
clientState.emplace(res.unwrap());
} else {
res.unwrapErr().SuppressException();
}
}
return clientState;
@ -5481,7 +5478,7 @@ RefPtr<ServiceWorker> nsGlobalWindowInner::GetOrCreateServiceWorker(
return;
}
ref = sw.forget();
ref = std::move(sw);
*aDoneOut = true;
});
@ -5489,7 +5486,7 @@ RefPtr<ServiceWorker> nsGlobalWindowInner::GetOrCreateServiceWorker(
ref = ServiceWorker::Create(this, aDescriptor);
}
return ref.forget();
return ref;
}
RefPtr<mozilla::dom::ServiceWorkerRegistration>
@ -5504,10 +5501,10 @@ nsGlobalWindowInner::GetServiceWorkerRegistration(
return;
}
ref = swr.forget();
ref = std::move(swr);
*aDoneOut = true;
});
return ref.forget();
return ref;
}
RefPtr<ServiceWorkerRegistration>
@ -5519,7 +5516,7 @@ nsGlobalWindowInner::GetOrCreateServiceWorkerRegistration(
if (!ref) {
ref = ServiceWorkerRegistration::CreateForMainThread(this, aDescriptor);
}
return ref.forget();
return ref;
}
nsresult nsGlobalWindowInner::FireDelayedDOMEvents() {
@ -6608,7 +6605,7 @@ already_AddRefed<nsWindowRoot> nsGlobalWindowInner::GetWindowRoot(
FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter, (), aError, nullptr);
}
void nsGlobalWindowInner::SetCursor(const nsAString& aCursor,
void nsGlobalWindowInner::SetCursor(const nsACString& aCursor,
ErrorResult& aError) {
FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, );
}
@ -6749,7 +6746,7 @@ void nsGlobalWindowInner::GetSidebar(OwningExternalOrWindowProxy& aResult,
RefPtr<BrowsingContext> domWindow =
GetChildWindow(NS_LITERAL_STRING("sidebar"));
if (domWindow) {
aResult.SetAsWindowProxy() = domWindow.forget();
aResult.SetAsWindowProxy() = std::move(domWindow);
return;
}

View File

@ -906,7 +906,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
void GetAttention(mozilla::ErrorResult& aError);
void GetAttentionWithCycleCount(int32_t aCycleCount,
mozilla::ErrorResult& aError);
void SetCursor(const nsAString& aCursor, mozilla::ErrorResult& aError);
void SetCursor(const nsACString& aCursor, mozilla::ErrorResult& aError);
void Maximize();
void Minimize();
void Restore();
@ -922,13 +922,6 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
void DidRefresh() override;
void GetDialogArgumentsOuter(JSContext* aCx,
JS::MutableHandle<JS::Value> aRetval,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
void GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
void GetReturnValueOuter(JSContext* aCx,
JS::MutableHandle<JS::Value> aReturnValue,
nsIPrincipal& aSubjectPrincipal,

View File

@ -1724,14 +1724,6 @@ static bool TreatAsRemoteXUL(nsIPrincipal* aPrincipal) {
!Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul", false);
}
static bool EnablePrivilege(JSContext* cx, unsigned argc, JS::Value* vp) {
Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED, true);
return xpc::EnableUniversalXPConnect(cx);
}
static const JSFunctionSpec EnablePrivilegeSpec[] = {
JS_FN("enablePrivilege", EnablePrivilege, 1, 0), JS_FS_END};
static bool InitializeLegacyNetscapeObject(JSContext* aCx,
JS::Handle<JSObject*> aGlobal) {
JSAutoRealm ar(aCx, aGlobal);
@ -1744,21 +1736,7 @@ static bool InitializeLegacyNetscapeObject(JSContext* aCx,
obj = JS_DefineObject(aCx, obj, "security", nullptr);
NS_ENSURE_TRUE(obj, false);
// We hide enablePrivilege behind a pref because it has been altered in a
// way that makes it fundamentally insecure to use in production. Mozilla
// uses this pref during automated testing to support legacy test code that
// uses enablePrivilege. If you're not doing test automation, you _must_ not
// flip this pref, or you will be exposing all your users to security
// vulnerabilities.
if (!xpc::IsInAutomation()) {
return true;
}
/* Define PrivilegeManager object with the necessary "static" methods. */
obj = JS_DefineObject(aCx, obj, "PrivilegeManager", nullptr);
NS_ENSURE_TRUE(obj, false);
return JS_DefineFunctions(aCx, obj, EnablePrivilegeSpec);
return true;
}
struct MOZ_STACK_CLASS CompartmentFinderState {
@ -2715,13 +2693,6 @@ void nsGlobalWindowOuter::PoisonOuterWindowProxy(JSObject* aObject) {
nsresult nsGlobalWindowOuter::SetArguments(nsIArray* aArguments) {
nsresult rv;
// Historically, we've used the same machinery to handle openDialog arguments
// (exposed via window.arguments) and showModalDialog arguments (exposed via
// window.dialogArguments), even though the former is XUL-only and uses an
// XPCOM array while the latter is web-exposed and uses an arbitrary JS value.
// Moreover, per-spec |dialogArguments| is a property of the browsing context
// (outer), whereas |arguments| lives on the inner.
//
// We've now mostly separated them, but the difference is still opaque to
// nsWindowWatcher (the caller of SetArguments in this little back-and-forth
// embedding waltz we do here).
@ -6089,7 +6060,6 @@ void nsGlobalWindowOuter::PostMessageMozOuter(JSContext* aCx,
return;
}
if (mDoc &&
StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
!DocGroup::TryToLoadIframesInBackground()) {
@ -7542,20 +7512,13 @@ nsIDOMWindowUtils* nsGlobalWindowOuter::WindowUtils() {
// Note: This call will lock the cursor, it will not change as it moves.
// To unlock, the cursor must be set back to Auto.
void nsGlobalWindowOuter::SetCursorOuter(const nsAString& aCursor,
void nsGlobalWindowOuter::SetCursorOuter(const nsACString& aCursor,
ErrorResult& aError) {
StyleCursorKind cursor;
if (aCursor.EqualsLiteral("auto")) {
cursor = StyleCursorKind::Auto;
} else {
// TODO(emilio): Use Servo for this instead.
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
int32_t c;
if (!nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, c)) {
return;
}
cursor = static_cast<StyleCursorKind>(c);
auto cursor = StyleCursorKind::Auto;
if (!Servo_CursorKind_Parse(&aCursor, &cursor)) {
// FIXME: It's a bit weird that this doesn't throw but stuff below does, but
// matches previous behavior so...
return;
}
RefPtr<nsPresContext> presContext;

View File

@ -651,15 +651,8 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
// fact chrome.
nsIBrowserDOMWindow* GetBrowserDOMWindowOuter();
void SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow);
void SetCursorOuter(const nsAString& aCursor, mozilla::ErrorResult& aError);
void SetCursorOuter(const nsACString& aCursor, mozilla::ErrorResult& aError);
void GetDialogArgumentsOuter(JSContext* aCx,
JS::MutableHandle<JS::Value> aRetval,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
void GetDialogArguments(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& aError);
void GetReturnValueOuter(JSContext* aCx,
JS::MutableHandle<JS::Value> aReturnValue,
nsIPrincipal& aSubjectPrincipal,

View File

@ -45,8 +45,8 @@ struct CharacterDataChangeInfo {
/**
* The offset such that mChangeEnd - mChangeStart is equal to the length of
* the text we removed. If this was a pure insert or append, this is equal to
* mChangeStart.
* the text we removed. If this was a pure insert, append or a result of
* `splitText()` this is equal to mChangeStart.
*/
uint32_t mChangeEnd;

View File

@ -31,10 +31,12 @@
#include "mozilla/dom/DocumentType.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Link.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/SVGUseElement.h"
#include "mozilla/dom/ScriptSettings.h"
@ -80,6 +82,7 @@
#include "nsObjectLoadingContent.h"
#include "nsPIDOMWindow.h"
#include "nsPresContext.h"
#include "nsRange.h"
#include "nsString.h"
#include "nsStyleConsts.h"
#include "nsSVGUtils.h"
@ -193,6 +196,15 @@ nsINode::~nsINode() {
MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
}
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
void nsINode::AssertInvariantsOnNodeInfoChange() {
MOZ_DIAGNOSTIC_ASSERT(!IsInComposedDoc());
if (nsCOMPtr<Link> link = do_QueryInterface(this)) {
MOZ_DIAGNOSTIC_ASSERT(!link->HasPendingLinkUpdate());
}
}
#endif
void* nsINode::GetProperty(const nsAtom* aPropertyName,
nsresult* aStatus) const {
if (!HasProperties()) { // a fast HasFlag() test
@ -230,6 +242,145 @@ nsIContentSecurityPolicy* nsINode::GetCsp() const {
nsINode::nsSlots* nsINode::CreateSlots() { return new nsSlots(); }
static const nsINode* GetClosestCommonInclusiveAncestorForRangeInSelection(
const nsINode* aNode) {
while (aNode &&
!aNode->IsClosestCommonInclusiveAncestorForRangeInSelection()) {
if (!aNode
->IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection()) {
return nullptr;
}
aNode = aNode->GetParentNode();
}
return aNode;
}
/**
* A Comparator suitable for mozilla::BinarySearchIf for searching a collection
* of nsRange* for an overlap of (mNode, mStartOffset) .. (mNode, mEndOffset).
*/
class IsItemInRangeComparator {
public:
// @param aStartOffset has to be less or equal to aEndOffset.
IsItemInRangeComparator(const nsINode& aNode, const uint32_t aStartOffset,
const uint32_t aEndOffset,
nsContentUtils::ComparePointsCache* aCache)
: mNode(aNode),
mStartOffset(aStartOffset),
mEndOffset(aEndOffset),
mCache(aCache) {
MOZ_ASSERT(aStartOffset <= aEndOffset);
}
int operator()(const nsRange* const aRange) const {
int32_t cmp = nsContentUtils::ComparePoints_Deprecated(
&mNode, static_cast<int32_t>(mEndOffset), aRange->GetStartContainer(),
static_cast<int32_t>(aRange->StartOffset()), nullptr, mCache);
if (cmp == 1) {
cmp = nsContentUtils::ComparePoints_Deprecated(
&mNode, static_cast<int32_t>(mStartOffset), aRange->GetEndContainer(),
static_cast<int32_t>(aRange->EndOffset()), nullptr, mCache);
if (cmp == -1) {
return 0;
}
return 1;
}
return -1;
}
private:
const nsINode& mNode;
const uint32_t mStartOffset;
const uint32_t mEndOffset;
nsContentUtils::ComparePointsCache* mCache;
};
bool nsINode::IsSelected(const uint32_t aStartOffset,
const uint32_t aEndOffset) const {
MOZ_ASSERT(aStartOffset <= aEndOffset);
const nsINode* n = GetClosestCommonInclusiveAncestorForRangeInSelection(this);
NS_ASSERTION(n || !IsSelectionDescendant(), "orphan selection descendant");
// Collect the selection objects for potential ranges.
nsTHashtable<nsPtrHashKey<Selection>> ancestorSelections;
Selection* prevSelection = nullptr;
for (; n; n = GetClosestCommonInclusiveAncestorForRangeInSelection(
n->GetParentNode())) {
const LinkedList<nsRange>* ranges =
n->GetExistingClosestCommonInclusiveAncestorRanges();
if (!ranges) {
continue;
}
for (const nsRange* range : *ranges) {
MOZ_ASSERT(range->IsInSelection(),
"Why is this range registeed with a node?");
// Looks like that IsInSelection() assert fails sometimes...
if (range->IsInSelection()) {
Selection* selection = range->GetSelection();
if (prevSelection != selection) {
prevSelection = selection;
ancestorSelections.PutEntry(selection);
}
}
}
}
nsContentUtils::ComparePointsCache cache;
IsItemInRangeComparator comparator{*this, aStartOffset, aEndOffset, &cache};
for (auto iter = ancestorSelections.ConstIter(); !iter.Done(); iter.Next()) {
Selection* selection = iter.Get()->GetKey();
// Binary search the sorted ranges in this selection.
// (Selection::GetRangeAt returns its ranges ordered).
size_t low = 0;
size_t high = selection->RangeCount();
while (high != low) {
size_t middle = low + (high - low) / 2;
const nsRange* const range = selection->GetRangeAt(middle);
int result = comparator(range);
if (result == 0) {
if (!range->Collapsed()) {
return true;
}
const nsRange* middlePlus1;
const nsRange* middleMinus1;
// if node end > start of middle+1, result = 1
if (middle + 1 < high &&
(middlePlus1 = selection->GetRangeAt(middle + 1)) &&
nsContentUtils::ComparePoints_Deprecated(
this, static_cast<int32_t>(aEndOffset),
middlePlus1->GetStartContainer(),
static_cast<int32_t>(middlePlus1->StartOffset()), nullptr,
&cache) > 0) {
result = 1;
// if node start < end of middle - 1, result = -1
} else if (middle >= 1 &&
(middleMinus1 = selection->GetRangeAt(middle - 1)) &&
nsContentUtils::ComparePoints_Deprecated(
this, static_cast<int32_t>(aStartOffset),
middleMinus1->GetEndContainer(),
static_cast<int32_t>(middleMinus1->EndOffset()), nullptr,
&cache) < 0) {
result = -1;
} else {
break;
}
}
if (result < 0) {
high = middle;
} else {
low = middle + 1;
}
}
}
return false;
}
nsIContent* nsINode::GetTextEditorRootContent(TextEditor** aTextEditor) {
if (aTextEditor) {
*aTextEditor = nullptr;
@ -1509,10 +1660,10 @@ void nsINode::DisconnectChild(nsIContent* aKid) {
aKid->mPreviousOrLastSibling = nullptr;
if (previousSibling) {
previousSibling->mNextSibling = aKid->mNextSibling.forget();
previousSibling->mNextSibling = std::move(aKid->mNextSibling);
} else {
// aKid is the first child in the list
mFirstChild = aKid->mNextSibling.forget();
mFirstChild = std::move(aKid->mNextSibling);
}
--mChildCount;
@ -2597,10 +2748,9 @@ const RawServoSelectorList* nsINode::ParseSelectorList(
if (list) {
if (!*list) {
// Invalid selector.
aRv.ThrowDOMException(
NS_ERROR_DOM_SYNTAX_ERR,
NS_LITERAL_CSTRING("'") + NS_ConvertUTF16toUTF8(aSelectorString) +
NS_LITERAL_CSTRING("' is not a valid selector"));
aRv.ThrowSyntaxError(NS_LITERAL_CSTRING("'") +
NS_ConvertUTF16toUTF8(aSelectorString) +
NS_LITERAL_CSTRING("' is not a valid selector"));
return nullptr;
}
@ -2618,9 +2768,8 @@ const RawServoSelectorList* nsINode::ParseSelectorList(
// Now make sure we throw an exception if the selector was invalid.
if (!ret) {
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
NS_LITERAL_CSTRING("'") + selectorString +
NS_LITERAL_CSTRING("' is not a valid selector"));
aRv.ThrowSyntaxError(NS_LITERAL_CSTRING("'") + selectorString +
NS_LITERAL_CSTRING("' is not a valid selector"));
}
return ret;
@ -2746,7 +2895,7 @@ JSObject* nsINode::WrapObject(JSContext* aCx,
}
already_AddRefed<nsINode> nsINode::CloneNode(bool aDeep, ErrorResult& aError) {
return Clone(aDeep, nullptr, nullptr, aError);
return Clone(aDeep, nullptr, aError);
}
nsDOMAttributeMap* nsINode::GetAttributes() {
@ -2817,8 +2966,7 @@ void nsINode::AddAnimationObserverUnlessExists(
already_AddRefed<nsINode> nsINode::CloneAndAdopt(
nsINode* aNode, bool aClone, bool aDeep,
nsNodeInfoManager* aNewNodeInfoManager,
JS::Handle<JSObject*> aReparentScope,
nsCOMArray<nsINode>* aNodesWithProperties, nsINode* aParent,
JS::Handle<JSObject*> aReparentScope, nsINode* aParent,
ErrorResult& aError) {
MOZ_ASSERT((!aClone && aNewNodeInfoManager) || !aReparentScope,
"If cloning or not getting a new nodeinfo we shouldn't rewrap");
@ -2912,61 +3060,72 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
}
} else if (nodeInfoManager) {
Document* oldDoc = aNode->OwnerDoc();
Document* newDoc = nodeInfoManager->GetDocument();
MOZ_ASSERT(newDoc);
bool wasRegistered = false;
if (elem) {
oldDoc->ClearBoxObjectFor(elem);
wasRegistered = oldDoc->UnregisterActivityObserver(elem);
}
const bool hadProperties = aNode->HasProperties();
if (hadProperties) {
// NOTE: We want this to happen before NodeInfoChanged so that
// NodeInfoChanged can use node properties normally.
//
// When this fails, it removes all properties for the node anyway, so no
// extra error handling needed.
Unused << oldDoc->PropertyTable().TransferOrDeleteAllPropertiesFor(
aNode, newDoc->PropertyTable());
}
aNode->mNodeInfo.swap(newNodeInfo);
aNode->NodeInfoChanged(oldDoc);
MOZ_ASSERT(newDoc != oldDoc);
if (elem) {
elem->NodeInfoChanged(oldDoc);
// Adopted callback must be enqueued whenever a nodes
// shadow-including inclusive descendants that is custom.
CustomElementData* data = elem->GetCustomElementData();
if (data && data->mState == CustomElementData::State::eCustom) {
LifecycleAdoptedCallbackArgs args = {oldDoc, newDoc};
nsContentUtils::EnqueueLifecycleCallback(Document::eAdopted, elem,
nullptr, &args);
}
}
Document* newDoc = aNode->OwnerDoc();
if (newDoc) {
if (elem) {
// Adopted callback must be enqueued whenever a nodes
// shadow-including inclusive descendants that is custom.
CustomElementData* data = elem->GetCustomElementData();
if (data && data->mState == CustomElementData::State::eCustom) {
LifecycleAdoptedCallbackArgs args = {oldDoc, newDoc};
nsContentUtils::EnqueueLifecycleCallback(Document::eAdopted, elem,
nullptr, &args);
// XXX what if oldDoc is null, we don't know if this should be
// registered or not! Can that really happen?
if (wasRegistered) {
newDoc->RegisterActivityObserver(aNode->AsElement());
}
if (nsPIDOMWindowInner* window = newDoc->GetInnerWindow()) {
EventListenerManager* elm = aNode->GetExistingListenerManager();
if (elm) {
window->SetMutationListeners(elm->MutationListenerBits());
if (elm->MayHavePaintEventListener()) {
window->SetHasPaintEventListeners();
}
}
// XXX what if oldDoc is null, we don't know if this should be
// registered or not! Can that really happen?
if (wasRegistered) {
newDoc->RegisterActivityObserver(aNode->AsElement());
}
if (nsPIDOMWindowInner* window = newDoc->GetInnerWindow()) {
EventListenerManager* elm = aNode->GetExistingListenerManager();
if (elm) {
window->SetMutationListeners(elm->MutationListenerBits());
if (elm->MayHavePaintEventListener()) {
window->SetHasPaintEventListeners();
}
if (elm->MayHaveTouchEventListener()) {
window->SetHasTouchEventListeners();
}
if (elm->MayHaveMouseEnterLeaveEventListener()) {
window->SetHasMouseEnterLeaveEventListeners();
}
if (elm->MayHavePointerEnterLeaveEventListener()) {
window->SetHasPointerEnterLeaveEventListeners();
}
if (elm->MayHaveSelectionChangeEventListener()) {
window->SetHasSelectionChangeEventListeners();
}
if (elm->MayHaveTouchEventListener()) {
window->SetHasTouchEventListeners();
}
if (elm->MayHaveMouseEnterLeaveEventListener()) {
window->SetHasMouseEnterLeaveEventListeners();
}
if (elm->MayHavePointerEnterLeaveEventListener()) {
window->SetHasPointerEnterLeaveEventListeners();
}
if (elm->MayHaveSelectionChangeEventListener()) {
window->SetHasSelectionChangeEventListeners();
}
}
}
if (wasRegistered && oldDoc != newDoc) {
if (wasRegistered) {
nsIContent* content = aNode->AsContent();
if (auto mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
if (auto* mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
mediaElem->NotifyOwnerDocumentActivityChanged();
}
nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(
@ -2988,11 +3147,11 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
}
}
if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) {
if (oldDoc->MayHaveDOMMutationObservers()) {
newDoc->SetMayHaveDOMMutationObservers();
}
if (oldDoc != newDoc && oldDoc->MayHaveAnimationObservers()) {
if (oldDoc->MayHaveAnimationObservers()) {
newDoc->SetMayHaveAnimationObservers();
}
@ -3009,14 +3168,18 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
UpdateReflectorGlobal(cx, wrapper, aError);
if (aError.Failed()) {
if (wasRegistered) {
aNode->OwnerDoc()->UnregisterActivityObserver(aNode->AsElement());
newDoc->UnregisterActivityObserver(aNode->AsElement());
}
if (hadProperties) {
// NOTE: When it fails it removes all properties for the node
// anyway, so no extra error handling needed.
Unused << newDoc->PropertyTable().TransferOrDeleteAllPropertiesFor(
aNode, oldDoc->PropertyTable());
}
aNode->mNodeInfo.swap(newNodeInfo);
if (elem) {
elem->NodeInfoChanged(newDoc);
}
aNode->NodeInfoChanged(newDoc);
if (wasRegistered) {
aNode->OwnerDoc()->RegisterActivityObserver(aNode->AsElement());
oldDoc->RegisterActivityObserver(aNode->AsElement());
}
return nullptr;
}
@ -3024,22 +3187,13 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
}
}
if (aNodesWithProperties && aNode->HasProperties()) {
bool ok = aNodesWithProperties->AppendObject(aNode);
MOZ_RELEASE_ASSERT(ok, "Out of memory");
if (aClone) {
ok = aNodesWithProperties->AppendObject(clone);
MOZ_RELEASE_ASSERT(ok, "Out of memory");
}
}
if (aDeep && (!aClone || !aNode->IsAttr())) {
// aNode's children.
for (nsIContent* cloneChild = aNode->GetFirstChild(); cloneChild;
cloneChild = cloneChild->GetNextSibling()) {
nsCOMPtr<nsINode> child =
CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
aReparentScope, aNodesWithProperties, clone, aError);
aReparentScope, clone, aError);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
@ -3058,9 +3212,9 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
newShadowRoot->CloneInternalDataFrom(originalShadowRoot);
for (nsIContent* origChild = originalShadowRoot->GetFirstChild();
origChild; origChild = origChild->GetNextSibling()) {
nsCOMPtr<nsINode> child = CloneAndAdopt(
origChild, aClone, aDeep, nodeInfoManager, aReparentScope,
aNodesWithProperties, newShadowRoot, aError);
nsCOMPtr<nsINode> child =
CloneAndAdopt(origChild, aClone, aDeep, nodeInfoManager,
aReparentScope, newShadowRoot, aError);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
@ -3071,7 +3225,7 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
if (ShadowRoot* shadowRoot = aNode->AsElement()->GetShadowRoot()) {
nsCOMPtr<nsINode> child =
CloneAndAdopt(shadowRoot, aClone, aDeep, nodeInfoManager,
aReparentScope, aNodesWithProperties, clone, aError);
aReparentScope, clone, aError);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
@ -3093,9 +3247,9 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
for (nsIContent* cloneChild = origContent->GetFirstChild(); cloneChild;
cloneChild = cloneChild->GetNextSibling()) {
nsCOMPtr<nsINode> child = CloneAndAdopt(
cloneChild, aClone, aDeep, ownerNodeInfoManager, aReparentScope,
aNodesWithProperties, cloneContent, aError);
nsCOMPtr<nsINode> child =
CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager,
aReparentScope, cloneContent, aError);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
@ -3107,39 +3261,41 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
void nsINode::Adopt(nsNodeInfoManager* aNewNodeInfoManager,
JS::Handle<JSObject*> aReparentScope,
nsCOMArray<nsINode>& aNodesWithProperties,
mozilla::ErrorResult& aError) {
if (aNewNodeInfoManager) {
mozilla::dom::Document* afterAdoptDoc = aNewNodeInfoManager->GetDocument();
mozilla::dom::Document* beforeAdoptDoc = OwnerDoc();
Document* beforeAdoptDoc = OwnerDoc();
Document* afterAdoptDoc = aNewNodeInfoManager->GetDocument();
if (afterAdoptDoc && beforeAdoptDoc &&
(afterAdoptDoc->GetDocGroup() != beforeAdoptDoc->GetDocGroup())) {
MOZ_ASSERT(beforeAdoptDoc);
MOZ_ASSERT(afterAdoptDoc);
MOZ_ASSERT(beforeAdoptDoc != afterAdoptDoc);
if (afterAdoptDoc->GetDocGroup() != beforeAdoptDoc->GetDocGroup()) {
// This is a temporary solution for Bug 1590526 to only limit
// the restriction to chrome level documents because web extensions
// rely on content to content node adoption.
if (nsContentUtils::IsChromeDoc(afterAdoptDoc) ||
nsContentUtils::IsChromeDoc(beforeAdoptDoc)) {
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
return aError.ThrowSecurityError(
"Adopting nodes across docgroups in chrome documents "
"is unsupported");
}
}
}
// Just need to store the return value of CloneAndAdopt in a
// temporary nsCOMPtr to make sure we release it.
nsCOMPtr<nsINode> node =
CloneAndAdopt(this, false, true, aNewNodeInfoManager, aReparentScope,
&aNodesWithProperties, nullptr, aError);
nsCOMPtr<nsINode> node = CloneAndAdopt(this, false, true, aNewNodeInfoManager,
aReparentScope, nullptr, aError);
nsMutationGuard::DidMutate();
}
already_AddRefed<nsINode> nsINode::Clone(
bool aDeep, nsNodeInfoManager* aNewNodeInfoManager,
nsCOMArray<nsINode>* aNodesWithProperties, mozilla::ErrorResult& aError) {
return CloneAndAdopt(this, true, aDeep, aNewNodeInfoManager, nullptr,
aNodesWithProperties, nullptr, aError);
already_AddRefed<nsINode> nsINode::Clone(bool aDeep,
nsNodeInfoManager* aNewNodeInfoManager,
ErrorResult& aError) {
return CloneAndAdopt(this, true, aDeep, aNewNodeInfoManager, nullptr, nullptr,
aError);
}
void nsINode::GenerateXPath(nsAString& aResult) {

View File

@ -277,6 +277,9 @@ class nsNodeWeakReference final : public nsIWeakReference {
* of nsIContent children and provides access to them.
*/
class nsINode : public mozilla::dom::EventTarget {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
void AssertInvariantsOnNodeInfoChange();
#endif
public:
typedef mozilla::dom::BoxQuadOptions BoxQuadOptions;
typedef mozilla::dom::ConvertCoordinateOptions ConvertCoordinateOptions;
@ -682,6 +685,23 @@ class nsINode : public mozilla::dom::EventTarget {
*/
inline mozilla::dom::NodeInfo* NodeInfo() const { return mNodeInfo; }
/**
* Called when we have been adopted, and the information of the
* node has been changed.
*
* The new document can be reached via OwnerDoc().
*
* If you override this method,
* please call up to the parent NodeInfoChanged.
*
* If you change this, change also the similar method in Link.
*/
virtual void NodeInfoChanged(Document* aOldDoc) {
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
AssertInvariantsOnNodeInfoChange();
#endif
}
inline bool IsInNamespace(int32_t aNamespace) const {
return mNodeInfo->NamespaceID() == aNamespace;
}
@ -1064,8 +1084,6 @@ class nsINode : public mozilla::dom::EventTarget {
* If aClone is true the nodes will be cloned. If aNewNodeInfoManager is
* not null, it is used to create new nodeinfos for the nodes. Also reparents
* the XPConnect wrappers for the nodes into aReparentScope if non-null.
* aNodesWithProperties will be filled with all the nodes that have
* properties.
*
* @param aNode Node to adopt/clone.
* @param aClone If true the node will be cloned and the cloned node will
@ -1078,11 +1096,6 @@ class nsINode : public mozilla::dom::EventTarget {
* shouldn't be changed.
* @param aReparentScope Scope into which wrappers should be reparented, or
* null if no reparenting should be done.
* @param aNodesWithProperties All nodes (from amongst aNode and its
* descendants) with properties. If aClone is
* true every node will be followed by its
* clone. Null can be passed to prevent this from
* being populated.
* @param aParent If aClone is true the cloned node will be appended to
* aParent's children. May be null. If not null then aNode
* must be an nsIContent.
@ -1095,8 +1108,7 @@ class nsINode : public mozilla::dom::EventTarget {
static already_AddRefed<nsINode> CloneAndAdopt(
nsINode* aNode, bool aClone, bool aDeep,
nsNodeInfoManager* aNewNodeInfoManager,
JS::Handle<JSObject*> aReparentScope,
nsCOMArray<nsINode>* aNodesWithProperties, nsINode* aParent,
JS::Handle<JSObject*> aReparentScope, nsINode* aParent,
mozilla::ErrorResult& aError);
public:
@ -1104,8 +1116,7 @@ class nsINode : public mozilla::dom::EventTarget {
* Walks the node, its attributes and descendant nodes. If aNewNodeInfoManager
* is not null, it is used to create new nodeinfos for the nodes. Also
* reparents the XPConnect wrappers for the nodes into aReparentScope if
* non-null. aNodesWithProperties will be filled with all the nodes that have
* properties.
* non-null.
*
* @param aNewNodeInfoManager The nodeinfo manager to use to create new
* nodeinfos for the node and its attributes and
@ -1113,20 +1124,16 @@ class nsINode : public mozilla::dom::EventTarget {
* shouldn't be changed.
* @param aReparentScope New scope for the wrappers, or null if no reparenting
* should be done.
* @param aNodesWithProperties All nodes (from amongst the node and its
* descendants) with properties.
* @param aError The error, if any.
*/
void Adopt(nsNodeInfoManager* aNewNodeInfoManager,
JS::Handle<JSObject*> aReparentScope,
nsCOMArray<nsINode>& aNodesWithProperties,
mozilla::ErrorResult& aError);
/**
* Clones the node, its attributes and, if aDeep is true, its descendant nodes
* If aNewNodeInfoManager is not null, it is used to create new nodeinfos for
* the clones. aNodesWithProperties will be filled with all the nodes that
* have properties, and every node in it will be followed by its clone.
* the clones.
*
* @param aDeep If true the function will be called recursively on
* descendants of the node
@ -1134,17 +1141,12 @@ class nsINode : public mozilla::dom::EventTarget {
* nodeinfos for the node and its attributes and
* descendants. May be null if the nodeinfos
* shouldn't be changed.
* @param aNodesWithProperties All nodes (from amongst the node and its
* descendants) with properties. Every node will
* be followed by its clone. Null can be passed to
* prevent this from being used.
* @param aError The error, if any.
*
* @return The newly created node. Null in error conditions.
*/
already_AddRefed<nsINode> Clone(bool aDeep,
nsNodeInfoManager* aNewNodeInfoManager,
nsCOMArray<nsINode>* aNodesWithProperties,
mozilla::ErrorResult& aError);
/**
@ -1191,11 +1193,14 @@ class nsINode : public mozilla::dom::EventTarget {
/**
* A set of ranges which are in the selection and which have this node as
* their endpoints' common ancestor. This is a UniquePtr instead of just a
* LinkedList, because that prevents us from pushing DOMSlots up to the next
* allocation bucket size, at the cost of some complexity.
* their endpoints' closest common inclusive ancestor
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor). This is
* a UniquePtr instead of just a LinkedList, because that prevents us from
* pushing DOMSlots up to the next allocation bucket size, at the cost of
* some complexity.
*/
mozilla::UniquePtr<mozilla::LinkedList<nsRange>> mCommonAncestorRanges;
mozilla::UniquePtr<mozilla::LinkedList<nsRange>>
mClosestCommonInclusiveAncestorRanges;
};
/**
@ -1294,16 +1299,30 @@ class nsINode : public mozilla::dom::EventTarget {
inline bool IsRootOfChromeAccessOnlySubtree() const;
/**
* Returns true if |this| node is the common ancestor of the start/end
* nodes of a Range in a Selection or a descendant of such a common ancestor.
* This node is definitely not selected when |false| is returned, but it may
* or may not be selected when |true| is returned.
* Returns true if |this| node is the closest common inclusive ancestor
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the
* start/end nodes of a Range in a Selection or a descendant of such a common
* ancestor. This node is definitely not selected when |false| is returned,
* but it may or may not be selected when |true| is returned.
*/
bool IsSelectionDescendant() const {
return IsDescendantOfCommonAncestorForRangeInSelection() ||
IsCommonAncestorForRangeInSelection();
return IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() ||
IsClosestCommonInclusiveAncestorForRangeInSelection();
}
/**
* Return true if any part of (this, aStartOffset) .. (this, aEndOffset)
* overlaps any nsRange in
* GetClosestCommonInclusiveAncestorForRangeInSelection ranges (i.e.
* where this is a descendant of a range's common inclusive ancestor node).
* If a nsRange starts in (this, aEndOffset) or if it ends in
* (this, aStartOffset) then it is non-overlapping and the result is false
* for that nsRange. Collapsed ranges always counts as non-overlapping.
*
* @param aStartOffset has to be less or equal to aEndOffset.
*/
bool IsSelected(uint32_t aStartOffset, uint32_t aEndOffset) const;
/**
* Get the root content of an editor. So, this node must be a descendant of
* an editor. Note that this should be only used for getting input or textarea
@ -1539,11 +1558,11 @@ class nsINode : public mozilla::dom::EventTarget {
ElementHasPart,
// Set if the element might have a contenteditable attribute set.
ElementMayHaveContentEditableAttr,
// Set if the node is the common ancestor of the start/end nodes of a Range
// that is in a Selection.
NodeIsCommonAncestorForRangeInSelection,
// Set if the node is the closest common inclusive ancestor of the start/end
// nodes of a Range that is in a Selection.
NodeIsClosestCommonInclusiveAncestorForRangeInSelection,
// Set if the node is a descendant of a node with the above bit set.
NodeIsDescendantOfCommonAncestorForRangeInSelection,
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection,
// Set if CanSkipInCC check has been done for this subtree root.
NodeIsCCMarkedRoot,
// Maybe set if this node is in black subtree.
@ -1637,23 +1656,44 @@ class nsINode : public mozilla::dom::EventTarget {
bool MayHaveContentEditableAttr() const {
return GetBoolFlag(ElementMayHaveContentEditableAttr);
}
bool IsCommonAncestorForRangeInSelection() const {
return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
bool IsClosestCommonInclusiveAncestorForRangeInSelection() const {
return GetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
}
void SetCommonAncestorForRangeInSelection() {
SetBoolFlag(NodeIsCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void SetClosestCommonInclusiveAncestorForRangeInSelection() {
SetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
}
void ClearCommonAncestorForRangeInSelection() {
ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void ClearClosestCommonInclusiveAncestorForRangeInSelection() {
ClearBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection);
}
bool IsDescendantOfCommonAncestorForRangeInSelection() const {
return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
bool IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() const {
return GetBoolFlag(
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
}
void SetDescendantOfCommonAncestorForRangeInSelection() {
SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
SetBoolFlag(
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
}
void ClearDescendantOfCommonAncestorForRangeInSelection() {
ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() {
ClearBoolFlag(
NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection);
}
void SetCCMarkedRoot(bool aValue) { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
@ -1912,23 +1952,34 @@ class nsINode : public mozilla::dom::EventTarget {
const ConvertCoordinateOptions& aOptions, CallerType aCallerType,
ErrorResult& aRv);
const mozilla::LinkedList<nsRange>* GetExistingCommonAncestorRanges() const {
/**
* See nsSlots::mClosestCommonInclusiveAncestorRanges.
*/
const mozilla::LinkedList<nsRange>*
GetExistingClosestCommonInclusiveAncestorRanges() const {
if (!HasSlots()) {
return nullptr;
}
return GetExistingSlots()->mCommonAncestorRanges.get();
return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get();
}
mozilla::LinkedList<nsRange>* GetExistingCommonAncestorRanges() {
/**
* See nsSlots::mClosestCommonInclusiveAncestorRanges.
*/
mozilla::LinkedList<nsRange>*
GetExistingClosestCommonInclusiveAncestorRanges() {
if (!HasSlots()) {
return nullptr;
}
return GetExistingSlots()->mCommonAncestorRanges.get();
return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get();
}
/**
* See nsSlots::mClosestCommonInclusiveAncestorRanges.
*/
mozilla::UniquePtr<mozilla::LinkedList<nsRange>>&
GetCommonAncestorRangesPtr() {
return Slots()->mCommonAncestorRanges;
GetClosestCommonInclusiveAncestorRangesPtr() {
return Slots()->mClosestCommonInclusiveAncestorRanges;
}
nsIWeakReference* GetExistingWeakReference() {

View File

@ -96,6 +96,7 @@ class nsIStyleSheetLinkingElement : public nsISupports {
nsString mTitle;
nsString mMedia;
nsString mIntegrity;
nsString mNonce;
bool mHasAlternateRel;
bool mIsInline;
@ -106,7 +107,10 @@ class nsIStyleSheetLinkingElement : public nsISupports {
already_AddRefed<nsIPrincipal> aTriggeringPrincipal,
already_AddRefed<nsIReferrerInfo> aReferrerInfo,
mozilla::CORSMode, const nsAString& aTitle,
const nsAString& aMedia, HasAlternateRel, IsInline,
const nsAString& aMedia,
const nsAString& aIntegrity,
const nsAString& aNonce,
HasAlternateRel, IsInline,
IsExplicitlyEnabled);
~SheetInfo();

View File

@ -8,7 +8,6 @@
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsAtom.h"
#include "mozilla/dom/Document.h"
#include "nsStringFwd.h"
#include "nsTArray.h"

File diff suppressed because it is too large Load Diff

View File

@ -110,7 +110,7 @@ class nsRange final : public mozilla::dom::AbstractRange,
* Mark this range as being generated or not.
* Currently it is used for marking ranges that are created when splitting up
* a range to exclude a -moz-user-select:none region.
* @see Selection::AddItem
* @see Selection::AddRangesForSelectableNodes
* @see ExcludeNonSelectableNodes
*/
void SetIsGenerated(bool aIsGenerated) { mIsGenerated = aIsGenerated; }
@ -215,10 +215,7 @@ class nsRange final : public mozilla::dom::AbstractRange,
int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther,
ErrorResult& aErr);
int16_t ComparePoint(nsINode& aContainer, uint32_t aOffset,
ErrorResult& aErr) {
return ComparePoint(RawRangeBoundary(&aContainer, aOffset), aErr);
}
int16_t ComparePoint(const RawRangeBoundary& aPoint, ErrorResult& aErr);
ErrorResult& aErr) const;
void DeleteContents(ErrorResult& aRv);
already_AddRefed<mozilla::dom::DocumentFragment> ExtractContents(
ErrorResult& aErr);
@ -227,15 +224,12 @@ class nsRange final : public mozilla::dom::AbstractRange,
aRv.Throw(NS_ERROR_NOT_INITIALIZED);
return nullptr;
}
return GetCommonAncestor();
return GetClosestCommonInclusiveAncestor();
}
void InsertNode(nsINode& aNode, ErrorResult& aErr);
bool IntersectsNode(nsINode& aNode, ErrorResult& aRv);
bool IsPointInRange(nsINode& aContainer, uint32_t aOffset,
ErrorResult& aErr) {
return IsPointInRange(RawRangeBoundary(&aContainer, aOffset), aErr);
}
bool IsPointInRange(const RawRangeBoundary& aPoint, ErrorResult& aErr);
ErrorResult& aErr) const;
void ToString(nsAString& aReturn, ErrorResult& aErr);
void Detach();
@ -304,18 +298,28 @@ class nsRange final : public mozilla::dom::AbstractRange,
*/
bool CanAccess(const nsINode&) const;
public:
/**
* Return true if any part of (aNode, aStartOffset) .. (aNode, aEndOffset)
* overlaps any nsRange in aNode's GetNextRangeCommonAncestor ranges (i.e.
* where aNode is a descendant of a range's common ancestor node).
* If a nsRange starts in (aNode, aEndOffset) or if it ends in
* (aNode, aStartOffset) then it is non-overlapping and the result is false
* for that nsRange. Collapsed ranges always counts as non-overlapping.
*/
static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
uint32_t aEndOffset);
void AdjustNextRefsOnCharacterDataSplit(const nsIContent& aContent,
const CharacterDataChangeInfo& aInfo);
struct RangeBoundariesAndRoot {
RawRangeBoundary mStart;
RawRangeBoundary mEnd;
nsINode* mRoot = nullptr;
};
/**
* @param aContent Must be non-nullptr.
*/
RangeBoundariesAndRoot DetermineNewRangeBoundariesAndRootOnCharacterDataMerge(
nsIContent* aContent, const CharacterDataChangeInfo& aInfo) const;
// @return true iff the range is positioned, aContainer belongs to the same
// document as the range, aContainer is a DOCUMENT_TYPE_NODE and
// aOffset doesn't exceed aContainer's length.
bool IsPointComparableToRange(const nsINode& aContainer, uint32_t aOffset,
ErrorResult& aErrorResult) const;
public:
/**
* This helper function gets rects and correlated text for the given range.
* @param aTextList optional where nullptr = don't retrieve text
@ -347,8 +351,15 @@ class nsRange final : public mozilla::dom::AbstractRange,
typedef nsTHashtable<nsPtrHashKey<nsRange>> RangeHashTable;
protected:
void RegisterCommonAncestor(nsINode* aNode);
void UnregisterCommonAncestor(nsINode* aNode, bool aIsUnlinking);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void RegisterClosestCommonInclusiveAncestor(nsINode* aNode);
/**
* https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
*/
void UnregisterClosestCommonInclusiveAncestor(nsINode* aNode,
bool aIsUnlinking);
/**
* DoSetRange() is called when `AbstractRange::SetStartAndEndInternal()` sets
@ -373,20 +384,16 @@ class nsRange final : public mozilla::dom::AbstractRange,
nsINode* aRootNode, bool aNotInsertedYet = false);
/**
* For a range for which IsInSelection() is true, return the common ancestor
* For a range for which IsInSelection() is true, return the closest common
* inclusive ancestor
* (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor)
* for the range, which we had to compute when the common ancestor changed or
* IsInSelection became true, so we could register with it. That is, it's a
* faster version of GetCommonAncestor that only works for ranges in a
* Selection. The method will assert and the behavior is undefined if called
* on a range where IsInSelection() is false.
* IsInSelection became true, so we could register with it. That is, it's a
* faster version of GetClosestCommonInclusiveAncestor that only works for
* ranges in a Selection. The method will assert and the behavior is undefined
* if called on a range where IsInSelection() is false.
*/
nsINode* GetRegisteredCommonAncestor();
// Helper to IsNodeSelected.
static bool IsNodeInSortedRanges(nsINode* aNode, uint32_t aStartOffset,
uint32_t aEndOffset,
const nsTArray<const nsRange*>& aRanges,
size_t aRangeStart, size_t aRangeEnd);
nsINode* GetRegisteredClosestCommonInclusiveAncestor();
// Assume that this is guaranteed that this is held by the caller when
// this is used. (Note that we cannot use AutoRestore for mCalledByJS
@ -413,7 +420,7 @@ class nsRange final : public mozilla::dom::AbstractRange,
return;
}
sIsNested = true;
mCommonAncestor = mRange->GetRegisteredCommonAncestor();
mCommonAncestor = mRange->GetRegisteredClosestCommonInclusiveAncestor();
}
~AutoInvalidateSelection();
nsRange* mRange;
@ -422,10 +429,10 @@ class nsRange final : public mozilla::dom::AbstractRange,
};
nsCOMPtr<nsINode> mRoot;
// mRegisteredCommonAncestor is only non-null when the range
// IsInSelection(). It's kept alive via mStartContainer/mEndContainer,
// mRegisteredClosestCommonInclusiveAncestor is only non-null when the range
// IsInSelection(). It's kept alive via mStart/mEnd,
// because we update it any time those could become disconnected from it.
nsINode* MOZ_NON_OWNING_REF mRegisteredCommonAncestor;
nsINode* MOZ_NON_OWNING_REF mRegisteredClosestCommonInclusiveAncestor;
mozilla::WeakPtr<mozilla::dom::Selection> mSelection;
// These raw pointers are used to remember a child that is about

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