mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1712140 - Part 3: Add support for parsing and building Declarative ShadowDOMs. r=dom-core,webidl,saschanaz,hsivonen
Differential Revision: https://phabricator.services.mozilla.com/D193675
This commit is contained in:
parent
c52d383fb0
commit
8c1befaa95
@ -1392,6 +1392,7 @@ Document::Document(const char* aContentType)
|
||||
mHasUserInteractionTimerScheduled(false),
|
||||
mShouldResistFingerprinting(false),
|
||||
mCloningForSVGUse(false),
|
||||
mAllowDeclarativeShadowRoots(false),
|
||||
mXMLDeclarationBits(0),
|
||||
mOnloadBlockCount(0),
|
||||
mWriteLevel(0),
|
||||
@ -18931,4 +18932,13 @@ RadioGroupContainer& Document::OwnedRadioGroupContainer() {
|
||||
return *mRadioGroupContainer;
|
||||
}
|
||||
|
||||
void Document::SetAllowDeclarativeShadowRoots(
|
||||
bool aAllowDeclarativeShadowRoots) {
|
||||
mAllowDeclarativeShadowRoots = aAllowDeclarativeShadowRoots;
|
||||
}
|
||||
|
||||
bool Document::AllowsDeclarativeShadowRoots() const {
|
||||
return mAllowDeclarativeShadowRoots;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -3858,6 +3858,9 @@ class Document : public nsINode,
|
||||
*/
|
||||
bool AllowsL10n() const;
|
||||
|
||||
void SetAllowDeclarativeShadowRoots(bool aAllowDeclarativeShadowRoots);
|
||||
bool AllowsDeclarativeShadowRoots() const;
|
||||
|
||||
protected:
|
||||
RefPtr<DocumentL10n> mDocumentL10n;
|
||||
|
||||
@ -4820,6 +4823,8 @@ class Document : public nsINode,
|
||||
// Whether we're cloning the contents of an SVG use element.
|
||||
bool mCloningForSVGUse : 1;
|
||||
|
||||
bool mAllowDeclarativeShadowRoots : 1;
|
||||
|
||||
// The fingerprinting protections overrides for this document. The value will
|
||||
// override the default enabled fingerprinting protections for this document.
|
||||
// This will only get populated if these is one that comes from the local
|
||||
|
@ -239,6 +239,9 @@ class ShadowRoot final : public DocumentFragment, public DocumentOrShadowRoot {
|
||||
void SetIsDeclarative(Declarative aIsDeclarative) {
|
||||
mIsDeclarative = aIsDeclarative;
|
||||
}
|
||||
void SetIsDeclarative(bool aIsDeclarative) {
|
||||
mIsDeclarative = aIsDeclarative ? Declarative::Yes : Declarative::No;
|
||||
}
|
||||
|
||||
bool IsClonable() const { return mIsClonable == Clonable::Yes; }
|
||||
|
||||
|
@ -5376,6 +5376,34 @@ bool AllowsUnsanitizedContentForAboutNewTab(nsIPrincipal* aPrincipal) {
|
||||
return aboutModuleFlags & nsIAboutModule::ALLOW_UNSANITIZED_CONTENT;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void nsContentUtils::SetHTMLUnsafe(FragmentOrElement* aTarget,
|
||||
Element* aContext,
|
||||
const nsAString& aSource) {
|
||||
MOZ_ASSERT(!sFragmentParsingActive, "Re-entrant fragment parsing attempted.");
|
||||
mozilla::AutoRestore<bool> guard(sFragmentParsingActive);
|
||||
sFragmentParsingActive = true;
|
||||
if (!sHTMLFragmentParser) {
|
||||
NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
|
||||
// Now sHTMLFragmentParser owns the object
|
||||
}
|
||||
|
||||
nsAtom* contextLocalName = aContext->NodeInfo()->NameAtom();
|
||||
int32_t contextNameSpaceID = aContext->GetNameSpaceID();
|
||||
|
||||
RefPtr<Document> doc = aTarget->OwnerDoc();
|
||||
RefPtr<DocumentFragment> fragment = doc->CreateDocumentFragment();
|
||||
nsresult rv = sHTMLFragmentParser->ParseFragment(
|
||||
aSource, fragment, contextLocalName, contextNameSpaceID,
|
||||
fragment->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks,
|
||||
true, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to parse fragment for SetHTMLUnsafe");
|
||||
}
|
||||
|
||||
aTarget->ReplaceChildren(fragment, IgnoreErrors());
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult nsContentUtils::ParseFragmentHTML(
|
||||
const nsAString& aSourceBuffer, nsIContent* aTargetNode,
|
||||
@ -5431,7 +5459,7 @@ nsresult nsContentUtils::ParseFragmentHTML(
|
||||
|
||||
nsresult rv = sHTMLFragmentParser->ParseFragment(
|
||||
aSourceBuffer, target, aContextLocalName, aContextNamespace, aQuirks,
|
||||
aPreventScriptExecution);
|
||||
aPreventScriptExecution, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (fragment) {
|
||||
@ -11270,6 +11298,25 @@ template bool nsContentUtils::AddElementToListByTreeOrder(
|
||||
nsTArray<RefPtr<HTMLInputElement>>& aList, HTMLInputElement* aChild,
|
||||
nsIContent* aAncestor);
|
||||
|
||||
nsIContent* nsContentUtils::AttachDeclarativeShadowRoot(nsIContent* aHost,
|
||||
ShadowRootMode aMode,
|
||||
bool aDelegatesFocus) {
|
||||
RefPtr<Element> host = mozilla::dom::Element::FromNodeOrNull(aHost);
|
||||
if (!host) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ShadowRootInit init;
|
||||
init.mMode = aMode;
|
||||
init.mDelegatesFocus = aDelegatesFocus;
|
||||
init.mSlotAssignment = SlotAssignmentMode::Named;
|
||||
init.mClonable = true;
|
||||
|
||||
RefPtr shadowRoot = host->AttachShadow(init, IgnoreErrors(),
|
||||
Element::ShadowRootDeclarative::Yes);
|
||||
return shadowRoot;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
std::ostream& operator<<(std::ostream& aOut,
|
||||
const PreventDefaultResult aPreventDefaultResult) {
|
||||
|
@ -176,6 +176,7 @@ class DOMArena;
|
||||
class Element;
|
||||
class Event;
|
||||
class EventTarget;
|
||||
class FragmentOrElement;
|
||||
class HTMLElement;
|
||||
class HTMLInputElement;
|
||||
class IPCTransferable;
|
||||
@ -187,6 +188,7 @@ class MessageBroadcaster;
|
||||
class NodeInfo;
|
||||
class OwningFileOrUSVStringOrFormData;
|
||||
class Selection;
|
||||
enum class ShadowRootMode : uint8_t;
|
||||
struct StructuredSerializeOptions;
|
||||
class WorkerPrivate;
|
||||
enum class ElementCallbackType;
|
||||
@ -1802,6 +1804,9 @@ class nsContentUtils {
|
||||
bool aPreventScriptExecution,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static void SetHTMLUnsafe(mozilla::dom::FragmentOrElement* aTarget,
|
||||
Element* aContext, const nsAString& aSource);
|
||||
/**
|
||||
* Invoke the fragment parsing algorithm (innerHTML) using the HTML parser.
|
||||
*
|
||||
@ -3457,6 +3462,11 @@ class nsContentUtils {
|
||||
nsIContent* aContent2,
|
||||
const nsIContent* aCommonAncestor);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
static nsIContent* AttachDeclarativeShadowRoot(
|
||||
nsIContent* aHost, mozilla::dom::ShadowRootMode aMode,
|
||||
bool aDelegatesFocus);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "mozilla/dom/DebuggerNotificationBinding.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ElementBinding.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
@ -3614,6 +3615,38 @@ already_AddRefed<nsINode> nsINode::CloneAndAdopt(
|
||||
}
|
||||
}
|
||||
|
||||
if (aClone && aNode->IsElement() &&
|
||||
!nodeInfo->GetDocument()->IsStaticDocument()) {
|
||||
// Clone the Shadow DOM
|
||||
ShadowRoot* originalShadowRoot = aNode->AsElement()->GetShadowRoot();
|
||||
if (originalShadowRoot && originalShadowRoot->IsClonable()) {
|
||||
ShadowRootInit init;
|
||||
init.mMode = originalShadowRoot->Mode();
|
||||
init.mDelegatesFocus = originalShadowRoot->DelegatesFocus();
|
||||
init.mSlotAssignment = originalShadowRoot->SlotAssignment();
|
||||
init.mClonable = true;
|
||||
|
||||
RefPtr<ShadowRoot> newShadowRoot =
|
||||
clone->AsElement()->AttachShadow(init, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
newShadowRoot->SetIsDeclarative(originalShadowRoot->IsDeclarative());
|
||||
|
||||
if (aDeep) {
|
||||
for (nsIContent* origChild = originalShadowRoot->GetFirstChild();
|
||||
origChild; origChild = origChild->GetNextSibling()) {
|
||||
nsCOMPtr<nsINode> child =
|
||||
CloneAndAdopt(origChild, aClone, aDeep, nodeInfoManager,
|
||||
aReparentScope, newShadowRoot, aError);
|
||||
if (NS_WARN_IF(aError.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cloning template element.
|
||||
if (aDeep && aClone && aNode->IsTemplateElement()) {
|
||||
DocumentFragment* origContent =
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include "mozilla/dom/HTMLTemplateElementBinding.h"
|
||||
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/NameSpaceConstants.h"
|
||||
#include "mozilla/dom/ShadowRootBinding.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsAtom.h"
|
||||
@ -16,6 +19,13 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Template)
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
static constexpr nsAttrValue::EnumTable kShadowRootModeTable[] = {
|
||||
{"open", ShadowRootMode::Open},
|
||||
{"closed", ShadowRootMode::Closed},
|
||||
{nullptr, {}}};
|
||||
|
||||
const nsAttrValue::EnumTable* kShadowRootModeDefault = &kShadowRootModeTable[2];
|
||||
|
||||
HTMLTemplateElement::HTMLTemplateElement(
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
|
||||
: nsGenericHTMLElement(std::move(aNodeInfo)) {
|
||||
@ -31,7 +41,7 @@ HTMLTemplateElement::HTMLTemplateElement(
|
||||
}
|
||||
|
||||
HTMLTemplateElement::~HTMLTemplateElement() {
|
||||
if (mContent) {
|
||||
if (mContent && mContent->GetHost() == this) {
|
||||
mContent->SetHost(nullptr);
|
||||
}
|
||||
}
|
||||
@ -44,7 +54,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLTemplateElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLTemplateElement,
|
||||
nsGenericHTMLElement)
|
||||
if (tmp->mContent) {
|
||||
tmp->mContent->SetHost(nullptr);
|
||||
if (tmp->mContent->GetHost() == tmp) {
|
||||
tmp->mContent->SetHost(nullptr);
|
||||
}
|
||||
tmp->mContent = nullptr;
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
@ -61,4 +73,33 @@ JSObject* HTMLTemplateElement::WrapNode(JSContext* aCx,
|
||||
return HTMLTemplateElement_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void HTMLTemplateElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
bool aNotify) {
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::shadowrootmode &&
|
||||
aValue && aValue->Type() == nsAttrValue::ValueType::eEnum &&
|
||||
!mShadowRootMode.isSome()) {
|
||||
mShadowRootMode.emplace(
|
||||
static_cast<ShadowRootMode>(aValue->GetEnumValue()));
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue,
|
||||
aMaybeScriptedPrincipal, aNotify);
|
||||
}
|
||||
|
||||
bool HTMLTemplateElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) {
|
||||
if (aNamespaceID == kNameSpaceID_None &&
|
||||
aAttribute == nsGkAtoms::shadowrootmode) {
|
||||
return aResult.ParseEnumValue(aValue, kShadowRootModeTable, false, nullptr);
|
||||
}
|
||||
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aMaybeScriptedPrincipal, aResult);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -8,8 +8,11 @@
|
||||
#define mozilla_dom_HTMLTemplateElement_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/ShadowRootBinding.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
@ -26,9 +29,35 @@ class HTMLTemplateElement final : public nsGenericHTMLElement {
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTemplateElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
bool aNotify) override;
|
||||
|
||||
bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) override;
|
||||
|
||||
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
|
||||
DocumentFragment* Content() { return mContent; }
|
||||
void SetContent(DocumentFragment* aContent) { mContent = aContent; }
|
||||
|
||||
void GetShadowRootMode(nsAString& aResult) const {
|
||||
GetEnumAttr(nsGkAtoms::shadowrootmode, nullptr, aResult);
|
||||
}
|
||||
void SetShadowRootMode(const nsAString& aValue) {
|
||||
SetHTMLAttr(nsGkAtoms::shadowrootmode, aValue);
|
||||
}
|
||||
|
||||
bool ShadowRootDelegatesFocus() {
|
||||
return GetBoolAttr(nsGkAtoms::shadowrootdelegatesfocus);
|
||||
}
|
||||
void SetShadowRootDelegatesFocus(bool aValue) {
|
||||
SetHTMLBoolAttr(nsGkAtoms::shadowrootdelegatesfocus, aValue,
|
||||
IgnoredErrorResult());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTemplateElement();
|
||||
@ -37,6 +66,7 @@ class HTMLTemplateElement final : public nsGenericHTMLElement {
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
RefPtr<DocumentFragment> mContent;
|
||||
Maybe<ShadowRootMode> mShadowRootMode;
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -3,7 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html
|
||||
* https://html.spec.whatwg.org/multipage/scripting.html#the-template-element
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
@ -13,5 +13,7 @@
|
||||
interface HTMLTemplateElement : HTMLElement {
|
||||
[HTMLConstructor] constructor();
|
||||
|
||||
readonly attribute DocumentFragment content;
|
||||
readonly attribute DocumentFragment content;
|
||||
[CEReactions] attribute DOMString shadowRootMode;
|
||||
[CEReactions] attribute boolean shadowRootDelegatesFocus;
|
||||
};
|
||||
|
@ -314,6 +314,7 @@ nsresult nsContentDLF::CreateDocument(
|
||||
nsCOMPtr<nsIDocumentViewer> viewer = NS_NewDocumentViewer();
|
||||
|
||||
doc->SetContainer(static_cast<nsDocShell*>(aContainer));
|
||||
doc->SetAllowDeclarativeShadowRoots(true);
|
||||
|
||||
// Initialize the document to begin loading the data. An
|
||||
// nsIStreamListener connected to the parser is returned in
|
||||
|
@ -434,6 +434,8 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
|
||||
private boolean forceNoQuirks = false;
|
||||
|
||||
private boolean allowDeclarativeShadowRoots = false;
|
||||
|
||||
// [NOCPP[
|
||||
|
||||
private boolean reportingDoctype = true;
|
||||
@ -2958,6 +2960,20 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
|| (("http://www.w3.org/1998/Math/MathML" == ns) && (stackNode.getGroup() == MI_MO_MN_MS_MTEXT));
|
||||
}
|
||||
|
||||
private T getDeclarativeShadowRoot(T currentNode, T templateNode, HtmlAttributes attributes) {
|
||||
if (!isAllowDeclarativeShadowRoots()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String shadowRootMode = attributes.getValue(AttributeName.SHADOWROOTMODE);
|
||||
if (shadowRootMode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean shadowRootDelegatesFocus = attributes.contains(AttributeName.SHADOWROOTDELEGATESFOCUS);
|
||||
return getShadowRootFromHost(currentNode, templateNode, shadowRootMode, shadowRootDelegatesFocus);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>
|
||||
@ -5302,9 +5318,17 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
T elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode
|
||||
// CPPONLY: , htmlCreator(elementName.getHtmlCreator())
|
||||
);
|
||||
appendElement(elt, currentNode);
|
||||
if (ElementName.TEMPLATE == elementName) {
|
||||
elt = getDocumentFragmentForTemplate(elt);
|
||||
T root = getDeclarativeShadowRoot(currentNode, elt, attributes);
|
||||
if (root != null) {
|
||||
setDocumentFragmentForTemplate(elt, root);
|
||||
elt = root;
|
||||
} else {
|
||||
appendElement(elt, currentNode);
|
||||
elt = getDocumentFragmentForTemplate(elt);
|
||||
}
|
||||
} else {
|
||||
appendElement(elt, currentNode);
|
||||
}
|
||||
StackNode<T> node = createStackNode(elementName, elt
|
||||
// [NOCPP[
|
||||
@ -5391,6 +5415,13 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
return template;
|
||||
}
|
||||
|
||||
void setDocumentFragmentForTemplate(T template, T fragment) {
|
||||
}
|
||||
|
||||
T getShadowRootFromHost(T host, T template, String shadowRootMode, boolean shadowRootDelegatesFocus) {
|
||||
return null;
|
||||
}
|
||||
|
||||
T getFormPointerForContext(T context) {
|
||||
return null;
|
||||
}
|
||||
@ -5509,6 +5540,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
} else {
|
||||
T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
|
||||
elt = createElement("http://www.w3.org/1999/xhtml", name,
|
||||
|
||||
attributes, formOwner, currentNode
|
||||
// CPPONLY: , htmlCreator(elementName.getHtmlCreator())
|
||||
);
|
||||
@ -5893,6 +5925,14 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
this.setForceNoQuirks(isSrcdocDocument);
|
||||
}
|
||||
|
||||
public boolean isAllowDeclarativeShadowRoots() {
|
||||
return allowDeclarativeShadowRoots;
|
||||
}
|
||||
|
||||
public void setAllowDeclarativeShadowRoots(boolean allow) {
|
||||
allowDeclarativeShadowRoots = allow;
|
||||
}
|
||||
|
||||
// [NOCPP[
|
||||
|
||||
public void setNamePolicy(XmlViolationPolicy namePolicy) {
|
||||
|
@ -678,6 +678,8 @@ void nsHtml5Parser::StartTokenizer(bool aScriptingEnabled) {
|
||||
|
||||
mTreeBuilder->SetPreventScriptExecution(!aScriptingEnabled);
|
||||
mTreeBuilder->setScriptingEnabled(aScriptingEnabled);
|
||||
mTreeBuilder->setAllowDeclarativeShadowRoots(
|
||||
mExecutor->GetDocument()->AllowsDeclarativeShadowRoots());
|
||||
mTokenizer->start();
|
||||
}
|
||||
|
||||
|
@ -1125,6 +1125,8 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest) {
|
||||
mTreeBuilder->setScriptingEnabled(scriptingEnabled);
|
||||
mTreeBuilder->SetPreventScriptExecution(
|
||||
!((mMode == NORMAL) && scriptingEnabled));
|
||||
mTreeBuilder->setAllowDeclarativeShadowRoots(
|
||||
mExecutor->GetDocument()->AllowsDeclarativeShadowRoots());
|
||||
mTokenizer->start();
|
||||
mExecutor->Start();
|
||||
mExecutor->StartReadingFromStage();
|
||||
|
@ -24,12 +24,10 @@ nsHtml5StringParser::nsHtml5StringParser()
|
||||
|
||||
nsHtml5StringParser::~nsHtml5StringParser() {}
|
||||
|
||||
nsresult nsHtml5StringParser::ParseFragment(const nsAString& aSourceBuffer,
|
||||
nsIContent* aTargetNode,
|
||||
nsAtom* aContextLocalName,
|
||||
int32_t aContextNamespace,
|
||||
bool aQuirks,
|
||||
bool aPreventScriptExecution) {
|
||||
nsresult nsHtml5StringParser::ParseFragment(
|
||||
const nsAString& aSourceBuffer, nsIContent* aTargetNode,
|
||||
nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks,
|
||||
bool aPreventScriptExecution, bool aAllowDeclarativeShadowRoots) {
|
||||
NS_ENSURE_TRUE(aSourceBuffer.Length() <= INT32_MAX, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
Document* doc = aTargetNode->OwnerDoc();
|
||||
@ -52,7 +50,7 @@ nsresult nsHtml5StringParser::ParseFragment(const nsAString& aSourceBuffer,
|
||||
|
||||
mTreeBuilder->SetPreventScriptExecution(aPreventScriptExecution);
|
||||
|
||||
return Tokenize(aSourceBuffer, doc, true);
|
||||
return Tokenize(aSourceBuffer, doc, true, aAllowDeclarativeShadowRoots);
|
||||
}
|
||||
|
||||
nsresult nsHtml5StringParser::ParseDocument(
|
||||
@ -67,12 +65,14 @@ nsresult nsHtml5StringParser::ParseDocument(
|
||||
mTreeBuilder->SetPreventScriptExecution(true);
|
||||
|
||||
return Tokenize(aSourceBuffer, aTargetDoc,
|
||||
aScriptingEnabledForNoscriptParsing);
|
||||
aScriptingEnabledForNoscriptParsing,
|
||||
aTargetDoc->AllowsDeclarativeShadowRoots());
|
||||
}
|
||||
|
||||
nsresult nsHtml5StringParser::Tokenize(
|
||||
const nsAString& aSourceBuffer, Document* aDocument,
|
||||
bool aScriptingEnabledForNoscriptParsing) {
|
||||
nsresult nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
|
||||
Document* aDocument,
|
||||
bool aScriptingEnabledForNoscriptParsing,
|
||||
bool aDeclarativeShadowRootsAllowed) {
|
||||
nsIURI* uri = aDocument->GetDocumentURI();
|
||||
|
||||
mBuilder->Init(aDocument, uri, nullptr, nullptr);
|
||||
@ -85,6 +85,7 @@ nsresult nsHtml5StringParser::Tokenize(
|
||||
|
||||
mTreeBuilder->setScriptingEnabled(aScriptingEnabledForNoscriptParsing);
|
||||
mTreeBuilder->setIsSrcdocDocument(aDocument->IsSrcdocDocument());
|
||||
mTreeBuilder->setAllowDeclarativeShadowRoots(aDeclarativeShadowRootsAllowed);
|
||||
mBuilder->Start();
|
||||
mTokenizer->start();
|
||||
if (!aSourceBuffer.IsEmpty()) {
|
||||
|
@ -41,11 +41,14 @@ class nsHtml5StringParser : public nsParserBase {
|
||||
* @param aPreventScriptExecution true to prevent scripts from executing;
|
||||
* don't set to false when parsing into a target node that has been bound
|
||||
* to tree.
|
||||
* @param aAllowDeclarativeShadowRoots allow the creation of declarative
|
||||
* shadow roots.
|
||||
*/
|
||||
nsresult ParseFragment(const nsAString& aSourceBuffer,
|
||||
nsIContent* aTargetNode, nsAtom* aContextLocalName,
|
||||
int32_t aContextNamespace, bool aQuirks,
|
||||
bool aPreventScriptExecution);
|
||||
bool aPreventScriptExecution,
|
||||
bool aAllowDeclarativeShadowRoots);
|
||||
|
||||
/**
|
||||
* Parse an entire HTML document from a source string.
|
||||
@ -61,7 +64,8 @@ class nsHtml5StringParser : public nsParserBase {
|
||||
|
||||
nsresult Tokenize(const nsAString& aSourceBuffer,
|
||||
mozilla::dom::Document* aDocument,
|
||||
bool aScriptingEnabledForNoscriptParsing);
|
||||
bool aScriptingEnabledForNoscriptParsing,
|
||||
bool aDeclarativeShadowRootsAllowed);
|
||||
|
||||
/**
|
||||
* The tree operation executor
|
||||
|
@ -2093,6 +2093,23 @@ bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
|
||||
(stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
|
||||
}
|
||||
|
||||
nsIContentHandle* nsHtml5TreeBuilder::getDeclarativeShadowRoot(
|
||||
nsIContentHandle* currentNode, nsIContentHandle* templateNode,
|
||||
nsHtml5HtmlAttributes* attributes) {
|
||||
if (!isAllowDeclarativeShadowRoots()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsHtml5String shadowRootMode =
|
||||
attributes->getValue(nsHtml5AttributeName::ATTR_SHADOWROOTMODE);
|
||||
if (!shadowRootMode) {
|
||||
return nullptr;
|
||||
}
|
||||
bool shadowRootDelegatesFocus =
|
||||
attributes->contains(nsHtml5AttributeName::ATTR_SHADOWROOTDELEGATESFOCUS);
|
||||
return getShadowRootFromHost(currentNode, templateNode, shadowRootMode,
|
||||
shadowRootDelegatesFocus);
|
||||
}
|
||||
|
||||
nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
|
||||
nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
|
||||
int32_t charsetState = CHARSET_INITIAL;
|
||||
@ -4218,9 +4235,18 @@ void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(
|
||||
nsIContentHandle* elt =
|
||||
createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
|
||||
currentNode, htmlCreator(elementName->getHtmlCreator()));
|
||||
appendElement(elt, currentNode);
|
||||
if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
|
||||
elt = getDocumentFragmentForTemplate(elt);
|
||||
nsIContentHandle* root =
|
||||
getDeclarativeShadowRoot(currentNode, elt, attributes);
|
||||
if (root) {
|
||||
setDocumentFragmentForTemplate(elt, root);
|
||||
elt = root;
|
||||
} else {
|
||||
appendElement(elt, currentNode);
|
||||
elt = getDocumentFragmentForTemplate(elt);
|
||||
}
|
||||
} else {
|
||||
appendElement(elt, currentNode);
|
||||
}
|
||||
nsHtml5StackNode* node = createStackNode(elementName, elt);
|
||||
push(node);
|
||||
@ -4482,6 +4508,14 @@ void nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) {
|
||||
this->setForceNoQuirks(isSrcdocDocument);
|
||||
}
|
||||
|
||||
bool nsHtml5TreeBuilder::isAllowDeclarativeShadowRoots() {
|
||||
return allowDeclarativeShadowRoots;
|
||||
}
|
||||
|
||||
void nsHtml5TreeBuilder::setAllowDeclarativeShadowRoots(bool allow) {
|
||||
allowDeclarativeShadowRoots = allow;
|
||||
}
|
||||
|
||||
void nsHtml5TreeBuilder::flushCharacters() {
|
||||
if (charBufferLen > 0) {
|
||||
if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) &&
|
||||
|
@ -314,6 +314,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
|
||||
private:
|
||||
bool quirks;
|
||||
bool forceNoQuirks;
|
||||
bool allowDeclarativeShadowRoots;
|
||||
inline nsHtml5ContentCreatorFunction htmlCreator(
|
||||
mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
|
||||
nsHtml5ContentCreatorFunction creator;
|
||||
@ -353,6 +354,9 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
|
||||
bool isTemplateContents();
|
||||
bool isTemplateModeStackEmpty();
|
||||
bool isSpecialParentInForeign(nsHtml5StackNode* stackNode);
|
||||
nsIContentHandle* getDeclarativeShadowRoot(nsIContentHandle* currentNode,
|
||||
nsIContentHandle* templateNode,
|
||||
nsHtml5HtmlAttributes* attributes);
|
||||
|
||||
public:
|
||||
static nsHtml5String extractCharsetFromContent(nsHtml5String attributeValue,
|
||||
@ -556,6 +560,8 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
|
||||
void setScriptingEnabled(bool scriptingEnabled);
|
||||
void setForceNoQuirks(bool forceNoQuirks);
|
||||
void setIsSrcdocDocument(bool isSrcdocDocument);
|
||||
bool isAllowDeclarativeShadowRoots();
|
||||
void setAllowDeclarativeShadowRoots(bool allow);
|
||||
void flushCharacters();
|
||||
|
||||
private:
|
||||
|
@ -7,9 +7,12 @@
|
||||
#include "ErrorList.h"
|
||||
#include "nsError.h"
|
||||
#include "nsHtml5AttributeName.h"
|
||||
#include "nsHtml5HtmlAttributes.h"
|
||||
#include "nsHtml5String.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/dom/FetchPriority.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/ShadowRootBinding.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
@ -1636,6 +1639,53 @@ nsIContentHandle* nsHtml5TreeBuilder::getDocumentFragmentForTemplate(
|
||||
return fragHandle;
|
||||
}
|
||||
|
||||
void nsHtml5TreeBuilder::setDocumentFragmentForTemplate(
|
||||
nsIContentHandle* aTemplate, nsIContentHandle* aFragment) {
|
||||
if (mBuilder) {
|
||||
nsHtml5TreeOperation::SetDocumentFragmentForTemplate(
|
||||
static_cast<nsIContent*>(aTemplate),
|
||||
static_cast<nsIContent*>(aFragment));
|
||||
return;
|
||||
}
|
||||
|
||||
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
|
||||
if (MOZ_UNLIKELY(!treeOp)) {
|
||||
MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
opSetDocumentFragmentForTemplate operation(aTemplate, aFragment);
|
||||
treeOp->Init(mozilla::AsVariant(operation));
|
||||
}
|
||||
|
||||
nsIContentHandle* nsHtml5TreeBuilder::getShadowRootFromHost(
|
||||
nsIContentHandle* aHost, nsIContentHandle* aTemplateNode,
|
||||
nsHtml5String aShadowRootMode, bool aShadowRootDelegatesFocus) {
|
||||
ShadowRootMode mode;
|
||||
if (aShadowRootMode.LowerCaseEqualsASCII("open")) {
|
||||
mode = ShadowRootMode::Open;
|
||||
} else if (aShadowRootMode.LowerCaseEqualsASCII("closed")) {
|
||||
mode = ShadowRootMode::Closed;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mBuilder) {
|
||||
return nsContentUtils::AttachDeclarativeShadowRoot(
|
||||
static_cast<nsIContent*>(aHost), mode, aShadowRootDelegatesFocus);
|
||||
}
|
||||
|
||||
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
|
||||
if (MOZ_UNLIKELY(!treeOp)) {
|
||||
MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
nsIContentHandle* fragHandle = AllocateContentHandle();
|
||||
opGetShadowRootFromHost operation(aHost, fragHandle, aTemplateNode, mode,
|
||||
aShadowRootDelegatesFocus);
|
||||
treeOp->Init(mozilla::AsVariant(operation));
|
||||
return fragHandle;
|
||||
}
|
||||
|
||||
nsIContentHandle* nsHtml5TreeBuilder::getFormPointerForContext(
|
||||
nsIContentHandle* aContext) {
|
||||
MOZ_ASSERT(mBuilder, "Must have builder.");
|
||||
|
@ -58,6 +58,13 @@ bool mActive;
|
||||
void documentMode(nsHtml5DocumentMode m);
|
||||
|
||||
nsIContentHandle* getDocumentFragmentForTemplate(nsIContentHandle* aTemplate);
|
||||
void setDocumentFragmentForTemplate(nsIContentHandle* aTemplate,
|
||||
nsIContentHandle* aFragment);
|
||||
|
||||
nsIContentHandle* getShadowRootFromHost(nsIContentHandle* aHost,
|
||||
nsIContentHandle* aTemplateNode,
|
||||
nsHtml5String aShadowRootMode,
|
||||
bool aShadowRootDelegatesFocus);
|
||||
|
||||
nsIContentHandle* getFormPointerForContext(nsIContentHandle* aContext);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/dom/Comment.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/LinkStyle.h"
|
||||
@ -18,12 +19,14 @@
|
||||
#include "mozilla/dom/HTMLImageElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/MutationObservers.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/Text.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDocElementCreatedNotificationRunner.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsHtml5AutoPauseUpdate.h"
|
||||
#include "nsHtml5DocumentMode.h"
|
||||
#include "nsHtml5HtmlAttributes.h"
|
||||
@ -135,6 +138,10 @@ nsHtml5TreeOperation::~nsHtml5TreeOperation() {
|
||||
|
||||
void operator()(const opGetDocumentFragmentForTemplate& aOperation) {}
|
||||
|
||||
void operator()(const opSetDocumentFragmentForTemplate& aOperation) {}
|
||||
|
||||
void operator()(const opGetShadowRootFromHost& aOperation) {}
|
||||
|
||||
void operator()(const opGetFosterParent& aOperation) {}
|
||||
|
||||
void operator()(const opMarkAsBroken& aOperation) {}
|
||||
@ -694,6 +701,12 @@ nsIContent* nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
|
||||
return tempElem->Content();
|
||||
}
|
||||
|
||||
void nsHtml5TreeOperation::SetDocumentFragmentForTemplate(
|
||||
nsIContent* aNode, nsIContent* aDocumentFragment) {
|
||||
auto* tempElem = static_cast<HTMLTemplateElement*>(aNode);
|
||||
tempElem->SetContent(static_cast<DocumentFragment*>(aDocumentFragment));
|
||||
}
|
||||
|
||||
nsIContent* nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable,
|
||||
nsIContent* aStackParent) {
|
||||
nsIContent* tableParent = aTable->GetParent();
|
||||
@ -894,6 +907,31 @@ nsresult nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult operator()(const opSetDocumentFragmentForTemplate& aOperation) {
|
||||
SetDocumentFragmentForTemplate(*aOperation.mTemplate,
|
||||
*aOperation.mFragment);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult operator()(const opGetShadowRootFromHost& aOperation) {
|
||||
nsIContent* root = nsContentUtils::AttachDeclarativeShadowRoot(
|
||||
*aOperation.mHost, aOperation.mShadowRootMode,
|
||||
aOperation.mShadowRootDelegatesFocus);
|
||||
if (root) {
|
||||
*aOperation.mFragHandle = root;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We failed to attach a new shadow root, so instead attach a template
|
||||
// element and return its content.
|
||||
nsHtml5TreeOperation::Append(*aOperation.mTemplateNode, *aOperation.mHost,
|
||||
mBuilder);
|
||||
*aOperation.mFragHandle =
|
||||
static_cast<HTMLTemplateElement*>(*aOperation.mTemplateNode)
|
||||
->Content();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult operator()(const opGetFosterParent& aOperation) {
|
||||
nsIContent* table = *(aOperation.mTable);
|
||||
nsIContent* stackParent = *(aOperation.mStackParent);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nsHtml5DocumentMode.h"
|
||||
#include "nsHtml5HtmlAttributes.h"
|
||||
#include "mozilla/dom/FromParser.h"
|
||||
#include "mozilla/dom/ShadowRootBinding.h"
|
||||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/Variant.h"
|
||||
#include "nsCharsetSource.h"
|
||||
@ -264,6 +265,37 @@ struct opGetDocumentFragmentForTemplate {
|
||||
}
|
||||
};
|
||||
|
||||
struct opSetDocumentFragmentForTemplate {
|
||||
nsIContent** mTemplate;
|
||||
nsIContent** mFragment;
|
||||
|
||||
explicit opSetDocumentFragmentForTemplate(nsIContentHandle* aTemplate,
|
||||
nsIContentHandle* aFragment) {
|
||||
mTemplate = static_cast<nsIContent**>(aTemplate);
|
||||
mFragment = static_cast<nsIContent**>(aFragment);
|
||||
}
|
||||
};
|
||||
|
||||
struct opGetShadowRootFromHost {
|
||||
nsIContent** mHost;
|
||||
nsIContent** mFragHandle;
|
||||
nsIContent** mTemplateNode;
|
||||
mozilla::dom::ShadowRootMode mShadowRootMode;
|
||||
bool mShadowRootDelegatesFocus;
|
||||
|
||||
explicit opGetShadowRootFromHost(nsIContentHandle* aHost,
|
||||
nsIContentHandle* aFragHandle,
|
||||
nsIContentHandle* aTemplateNode,
|
||||
mozilla::dom::ShadowRootMode aShadowRootMode,
|
||||
bool aShadowRootDelegatesFocus) {
|
||||
mHost = static_cast<nsIContent**>(aHost);
|
||||
mFragHandle = static_cast<nsIContent**>(aFragHandle);
|
||||
mTemplateNode = static_cast<nsIContent**>(aTemplateNode);
|
||||
mShadowRootMode = aShadowRootMode;
|
||||
mShadowRootDelegatesFocus = aShadowRootDelegatesFocus;
|
||||
}
|
||||
};
|
||||
|
||||
struct opGetFosterParent {
|
||||
nsIContent** mTable;
|
||||
nsIContent** mStackParent;
|
||||
@ -492,7 +524,8 @@ typedef mozilla::Variant<
|
||||
opCreateHTMLElement, opCreateSVGElement, opCreateMathMLElement,
|
||||
opSetFormElement, opAppendText, opFosterParentText, opAppendComment,
|
||||
opAppendCommentToDocument, opAppendDoctypeToDocument,
|
||||
opGetDocumentFragmentForTemplate, opGetFosterParent,
|
||||
opGetDocumentFragmentForTemplate, opSetDocumentFragmentForTemplate,
|
||||
opGetShadowRootFromHost, opGetFosterParent,
|
||||
// Gecko-specific on-pop ops
|
||||
opMarkAsBroken, opRunScriptThatMayDocumentWriteOrBlock,
|
||||
opRunScriptThatCannotDocumentWriteOrBlock, opPreventScriptExecution,
|
||||
@ -587,6 +620,8 @@ class nsHtml5TreeOperation final {
|
||||
nsHtml5DocumentBuilder* aBuilder);
|
||||
|
||||
static nsIContent* GetDocumentFragmentForTemplate(nsIContent* aNode);
|
||||
static void SetDocumentFragmentForTemplate(nsIContent* aNode,
|
||||
nsIContent* aDocumentFragment);
|
||||
|
||||
static nsIContent* GetFosterParent(nsIContent* aTable,
|
||||
nsIContent* aStackParent);
|
||||
|
Loading…
Reference in New Issue
Block a user