Commit 0c74fc90 authored by Jeremy Roman's avatar Jeremy Roman Committed by Commit Bot

Make it possible to condition an element type on context features.

Any such tag name would need to also set noTypeHelpers: true and
provide its own specializations that check something besides the
tag name, since such an element could still end up in a document
where it is disabled through node adoption.

Bug: 1040627
Change-Id: Ib53554f673e2a7b375e82abde1b8e29c380c39c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1994520Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734491}
parent 60c7d82b
......@@ -83,7 +83,8 @@ void V8HTMLConstructor::HtmlConstructor(
} else {
// Customized built-in element
// 5. If local name is not valid for interface, throw TypeError
if (htmlElementTypeForTag(local_name) != element_interface_name) {
if (htmlElementTypeForTag(local_name, window->document()) !=
element_interface_name) {
V8ThrowException::ThrowTypeError(isolate,
"Illegal constructor: localName does "
"not match the HTML element interface");
......
......@@ -30,7 +30,7 @@ static {{namespace}}FunctionMap* g_{{namespace|lower}}_constructors = nullptr;
static {{namespace}}Element* {{namespace}}{{tag.name.to_upper_camel_case()}}Constructor(
Document& document, const CreateElementFlags flags) {
{% if tag.runtimeEnabled %}
if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled())
if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled(&document))
return MakeGarbageCollected<{{fallback_interface}}>({{cpp_namespace}}::{{tag|symbol}}Tag, document);
{% endif %}
return MakeGarbageCollected<{{tag.interface}}>(
......
......@@ -30,9 +30,13 @@ HTMLTypeMap CreateHTMLTypeMap() {
return html_type_map;
}
HTMLElementType htmlElementTypeForTag(const AtomicString& tagName) {
static const HTMLTypeMap& GetHTMLTypeMap() {
DEFINE_STATIC_LOCAL(const HTMLTypeMap, html_type_map, (CreateHTMLTypeMap()));
return html_type_map;
}
HTMLElementType htmlElementTypeForTag(const AtomicString& tagName, const Document* document) {
const auto& html_type_map = GetHTMLTypeMap();
auto it = html_type_map.find(tagName);
if (it == html_type_map.end())
return HTMLElementType::kHTMLUnknownElement;
......@@ -40,7 +44,7 @@ HTMLElementType htmlElementTypeForTag(const AtomicString& tagName) {
{% for tag in tags|sort %}
{% if tag.runtimeEnabled %}
if (tagName == "{{tag.name}}") {
if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled()) {
if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled(document)) {
return HTMLElementType::kHTMLUnknownElement;
}
}
......@@ -48,5 +52,9 @@ HTMLElementType htmlElementTypeForTag(const AtomicString& tagName) {
{% endfor %}
return it->value;
}
bool IsKnownBuiltinTagName(const AtomicString& tag_name) {
return GetHTMLTypeMap().Contains(tag_name);
}
{% endif %}
} // namespace blink
......@@ -11,6 +11,9 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
class Document;
// Type checking.
{% for tag in tags|sort if not tag.multipleTagNames and not tag.noTypeHelpers %}
class {{tag.interface}};
......@@ -26,6 +29,9 @@ template <>
struct DowncastTraits<{{tag.interface}}> {
static bool AllowFrom(const Element& element) {
{% if tag.runtimeEnabled %}
// If the following line doesn't compile, your feature may vary by context,
// in which case you'll need to write your own type helpers that can
// distinguish elements without relying solely on tag name.
if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled())
return false;
{% endif %}
......@@ -50,9 +56,11 @@ enum class HTMLElementType {
// The corresponding HTMLElement type for the tag name will be returned
// Do NOT use this function with SVG tag names and SVGElements
// If tagName is an undefined html tag name HTMLUnknownElement is returned
HTMLElementType htmlElementTypeForTag(const AtomicString& tagName);
HTMLElementType htmlElementTypeForTag(const AtomicString& tagName, const Document*);
bool IsKnownBuiltinTagName(const AtomicString& tag_name);
{% endif %}
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_{{namespace|upper}}_ELEMENT_TYPE_HELPERS_H_
\ No newline at end of file
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_{{namespace|upper}}_ELEMENT_TYPE_HELPERS_H_
......@@ -56,8 +56,7 @@ Vector<AtomicString>& CustomElement::EmbedderCustomElementNames() {
void CustomElement::AddEmbedderCustomElementName(const AtomicString& name) {
DCHECK_EQ(name, name.LowerASCII());
DCHECK(Document::IsValidName(name)) << name;
DCHECK_EQ(HTMLElementType::kHTMLUnknownElement, htmlElementTypeForTag(name))
<< name;
DCHECK(!IsKnownBuiltinTagName(name)) << name;
DCHECK(!IsValidName(name, false)) << name;
if (EmbedderCustomElementNames().Contains(name))
......@@ -69,8 +68,7 @@ void CustomElement::AddEmbedderCustomElementNameForTesting(
const AtomicString& name,
ExceptionState& exception_state) {
if (name != name.LowerASCII() || !Document::IsValidName(name) ||
HTMLElementType::kHTMLUnknownElement != htmlElementTypeForTag(name) ||
IsValidName(name, false)) {
IsKnownBuiltinTagName(name) || IsValidName(name, false)) {
exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
"Name cannot be used");
return;
......@@ -105,14 +103,16 @@ bool CustomElement::ShouldCreateCustomElement(const QualifiedName& tag_name) {
}
bool CustomElement::ShouldCreateCustomizedBuiltinElement(
const AtomicString& local_name) {
return htmlElementTypeForTag(local_name) !=
const AtomicString& local_name,
const Document& document) {
return htmlElementTypeForTag(local_name, &document) !=
HTMLElementType::kHTMLUnknownElement;
}
bool CustomElement::ShouldCreateCustomizedBuiltinElement(
const QualifiedName& tag_name) {
return ShouldCreateCustomizedBuiltinElement(tag_name.LocalName()) &&
const QualifiedName& tag_name,
const Document& document) {
return ShouldCreateCustomizedBuiltinElement(tag_name.LocalName(), document) &&
tag_name.NamespaceURI() == html_names::xhtmlNamespaceURI;
}
......
......@@ -77,8 +77,10 @@ class CORE_EXPORT CustomElement {
static bool ShouldCreateCustomElement(const AtomicString& local_name);
static bool ShouldCreateCustomElement(const QualifiedName&);
static bool ShouldCreateCustomizedBuiltinElement(
const AtomicString& local_name);
static bool ShouldCreateCustomizedBuiltinElement(const QualifiedName&);
const AtomicString& local_name,
const Document&);
static bool ShouldCreateCustomizedBuiltinElement(const QualifiedName&,
const Document&);
// Look up a definition, and create an autonomous custom element if
// it's found.
......
......@@ -123,8 +123,9 @@ HTMLElement* CustomElementDefinition::CreateElement(
Document& document,
const QualifiedName& tag_name,
CreateElementFlags flags) {
DCHECK(CustomElement::ShouldCreateCustomElement(tag_name) ||
CustomElement::ShouldCreateCustomizedBuiltinElement(tag_name))
DCHECK(
CustomElement::ShouldCreateCustomElement(tag_name) ||
CustomElement::ShouldCreateCustomizedBuiltinElement(tag_name, document))
<< tag_name;
// 5. If definition is non-null, and definition’s name is not equal to
......
......@@ -150,7 +150,7 @@ CustomElementDefinition* CustomElementRegistry::DefineInternal(
if (ThrowIfValidName(AtomicString(options->extends()), exception_state))
return nullptr;
// 7.2. If element interface is undefined element, throw exception
if (htmlElementTypeForTag(extends) ==
if (htmlElementTypeForTag(extends, owner_->document()) ==
HTMLElementType::kHTMLUnknownElement) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotSupportedError,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment