From 7d493da919b53d9c012a73806fc91305776276eb Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Wed, 7 Dec 2022 15:57:04 -0800 Subject: [PATCH] Add support for and honor attributes https://bugs.webkit.org/show_bug.cgi?id=248855 rdar://problem/103056552 Reviewed by Antoine Quint. * LayoutTests/model-element/model-element-source-expected.txt: * LayoutTests/model-element/model-element-source.html: * Source/WebCore/Modules/model-element/HTMLModelElement.cpp: (WebCore::isSupportedModelType): (WebCore::HTMLModelElement::selectModelSource const): (WebCore::HTMLModelElement::sourcesChanged): (WebCore::HTMLModelElement::parseAttribute): (WebCore::HTMLModelElement::isURLAttribute const): (WebCore::HTMLModelElement::attributeChanged): Deleted. * Source/WebCore/Modules/model-element/HTMLModelElement.h: * Source/WebCore/Modules/model-element/HTMLModelElement.idl: Canonical link: https://commits.webkit.org/257518@main --- .../model-element-source-expected.txt | 12 +++ .../model-element/model-element-source.html | 86 ++++++++++++++++++- .../model-element/HTMLModelElement.cpp | 56 ++++++++---- .../Modules/model-element/HTMLModelElement.h | 4 +- .../model-element/HTMLModelElement.idl | 1 + 5 files changed, 141 insertions(+), 18 deletions(-) diff --git a/LayoutTests/model-element/model-element-source-expected.txt b/LayoutTests/model-element/model-element-source-expected.txt index caf700bcab81..69f2456aeb74 100644 --- a/LayoutTests/model-element/model-element-source-expected.txt +++ b/LayoutTests/model-element/model-element-source-expected.txt @@ -9,4 +9,16 @@ PASS Removing the changes the currentSrc property. PASS currentSrc returns the src value for the first element. PASS Removing a element updates currentSrc. PASS Adding a before the current updates currentSrc. +PASS The HTMLModelElement interface has a src property. +PASS HTMLModelElement src property reflects src attribute value as a resolved URL. +PASS src attribute reflects HTMLModelElement src property. +PASS Changing the src attribute of a changes the currentSrc property. +PASS A non-empty src attribute takes precedence over a child. +PASS An empty src attribute does not take precedence over a child. +PASS Removing a src attribute selects the first matching child. +PASS The first with a supported type is selected. +PASS Changing a to a supported type causes it to be selected. +PASS Changing a to an unsupported type causes it not to be selected. +PASS An inserted with an unsupported type is not selected. +PASS An inserted with a supported type is selected. diff --git a/LayoutTests/model-element/model-element-source.html b/LayoutTests/model-element/model-element-source.html index 9ff76628ed0c..98b5ced009ad 100644 --- a/LayoutTests/model-element/model-element-source.html +++ b/LayoutTests/model-element/model-element-source.html @@ -2,9 +2,11 @@ diff --git a/Source/WebCore/Modules/model-element/HTMLModelElement.cpp b/Source/WebCore/Modules/model-element/HTMLModelElement.cpp index 4a72e70ccb8c..ef246f09d826 100644 --- a/Source/WebCore/Modules/model-element/HTMLModelElement.cpp +++ b/Source/WebCore/Modules/model-element/HTMLModelElement.cpp @@ -48,6 +48,7 @@ #include "JSHTMLModelElementCamera.h" #include "LayoutRect.h" #include "LayoutSize.h" +#include "MIMETypeRegistry.h" #include "Model.h" #include "ModelPlayer.h" #include "ModelPlayerProvider.h" @@ -100,23 +101,37 @@ RefPtr HTMLModelElement::model() const return m_model; } -void HTMLModelElement::sourcesChanged() +static bool isSupportedModelType(const AtomString& type) { - if (!document().hasBrowsingContext()) { - setSourceURL(URL { }); - return; - } + return type.isEmpty() || MIMETypeRegistry::isSupportedModelMIMEType(type); +} + +URL HTMLModelElement::selectModelSource() const +{ + // FIXME: This should probably work more like media element resource + // selection, where if a element fails to load, an error event + // is dispatched to it, and we continue to try subsequent s. + + if (!document().hasBrowsingContext()) + return { }; + + if (auto src = getNonEmptyURLAttribute(srcAttr); src.isValid()) + return src; for (auto& element : childrenOfType(*this)) { - // FIXME: for now we use the first valid URL without looking at the mime-type. - auto url = element.getNonEmptyURLAttribute(HTMLNames::srcAttr); - if (url.isValid()) { - setSourceURL(url); - return; - } + if (!isSupportedModelType(element.attributeWithoutSynchronization(typeAttr))) + continue; + + if (auto src = element.getNonEmptyURLAttribute(srcAttr); src.isValid()) + return src; } - setSourceURL(URL { }); + return { }; +} + +void HTMLModelElement::sourcesChanged() +{ + setSourceURL(selectModelSource()); } void HTMLModelElement::setSourceURL(const URL& url) @@ -366,11 +381,15 @@ bool HTMLModelElement::isInteractive() const return hasAttributeWithoutSynchronization(HTMLNames::interactiveAttr); } -void HTMLModelElement::attributeChanged(const QualifiedName& name, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason reason) +void HTMLModelElement::parseAttribute(const QualifiedName& name, const AtomString& value) { - HTMLElement::attributeChanged(name, oldValue, newValue, reason); - if (m_modelPlayer && name == HTMLNames::interactiveAttr) - m_modelPlayer->setInteractionEnabled(isInteractive()); + if (name == srcAttr) + sourcesChanged(); + else if (name == interactiveAttr) { + if (m_modelPlayer) + m_modelPlayer->setInteractionEnabled(isInteractive()); + } else + HTMLElement::parseAttribute(name, value); } void HTMLModelElement::defaultEventHandler(Event& event) @@ -699,6 +718,11 @@ bool HTMLModelElement::hasPresentationalHintsForAttribute(const QualifiedName& n return HTMLElement::hasPresentationalHintsForAttribute(name); } +bool HTMLModelElement::isURLAttribute(const Attribute& attribute) const +{ + return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute); +} + } #endif // ENABLE(MODEL_ELEMENT) diff --git a/Source/WebCore/Modules/model-element/HTMLModelElement.h b/Source/WebCore/Modules/model-element/HTMLModelElement.h index 3cd617ddd5e9..a5fcc5528434 100644 --- a/Source/WebCore/Modules/model-element/HTMLModelElement.h +++ b/Source/WebCore/Modules/model-element/HTMLModelElement.h @@ -120,6 +120,7 @@ class HTMLModelElement final : public HTMLElement, private CachedRawResourceClie private: HTMLModelElement(const QualifiedName&, Document&); + URL selectModelSource() const; void setSourceURL(const URL&); void modelDidChange(); void createModelPlayer(); @@ -132,7 +133,8 @@ class HTMLModelElement final : public HTMLElement, private CachedRawResourceClie // DOM overrides. void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final; - void attributeChanged(const QualifiedName&, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason) final; + bool isURLAttribute(const Attribute&) const final; + void parseAttribute(const QualifiedName&, const AtomString&) final; // StyledElement bool hasPresentationalHintsForAttribute(const QualifiedName&) const final; diff --git a/Source/WebCore/Modules/model-element/HTMLModelElement.idl b/Source/WebCore/Modules/model-element/HTMLModelElement.idl index da0fe79f96a5..01006faf847f 100644 --- a/Source/WebCore/Modules/model-element/HTMLModelElement.idl +++ b/Source/WebCore/Modules/model-element/HTMLModelElement.idl @@ -32,6 +32,7 @@ ] interface HTMLModelElement : HTMLElement { [CEReactions=NotNeeded, Reflect] attribute unsigned long width; [CEReactions=NotNeeded, Reflect] attribute unsigned long height; + [CEReactions=NotNeeded, Reflect, URL] attribute USVString src; [URL] readonly attribute USVString currentSrc; readonly attribute boolean complete;