mirror of
https://github.com/Feodor2/Mypal68.git
synced 2025-06-18 14:55:44 -04:00
layout update for the further update
This commit is contained in:
parent
af8ad28b05
commit
b179cc258f
@ -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();
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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",
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
]
|
||||
];
|
||||
|
@ -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; }
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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 observer’s 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 targetRect’s area.
|
||||
int64_t targetArea =
|
||||
(int64_t)targetRect.Width() * (int64_t)targetRect.Height();
|
||||
// 2.6. Let intersectionArea be intersectionRect’s 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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;
|
||||
|
@ -136,7 +136,7 @@ void SelectionChangeEventDispatcher::OnSelectionChange(Document* aDoc,
|
||||
root = root->GetParent();
|
||||
}
|
||||
|
||||
target = root.forget();
|
||||
target = std::move(root);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
23
dom/base/crashtests/1555786.html
Normal file
23
dom/base/crashtests/1555786.html
Normal 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>
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 node’s
|
||||
// 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 node’s
|
||||
// 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) {
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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
@ -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
Loading…
Reference in New Issue
Block a user