diff --git a/Source/WebCore/html/HTMLAttachmentElement.cpp b/Source/WebCore/html/HTMLAttachmentElement.cpp
index 1accd1c79b42..ad3b37422f99 100644
--- a/Source/WebCore/html/HTMLAttachmentElement.cpp
+++ b/Source/WebCore/html/HTMLAttachmentElement.cpp
@@ -114,6 +114,18 @@ static const AtomString& attachmentPreviewIdentifier()
return identifier;
}
+static const AtomString& attachmentProgressIdentifier()
+{
+ static MainThreadNeverDestroyed identifier("attachment-progress"_s);
+ return identifier;
+}
+
+static const AtomString& attachmentProgressCircleIdentifier()
+{
+ static MainThreadNeverDestroyed identifier("attachment-progress-circle"_s);
+ return identifier;
+}
+
static const AtomString& attachmentInformationAreaIdentifier()
{
static MainThreadNeverDestroyed identifier("attachment-information-area"_s);
@@ -226,6 +238,11 @@ void HTMLAttachmentElement::ensureModernShadowTree(ShadowRoot& root)
m_innerLegacyAttachment->setIdAttribute(attachmentPreviewIdentifier());
previewArea->appendChild(*m_innerLegacyAttachment);
+ m_progressElement = createContainedElement(previewArea, attachmentProgressIdentifier());
+ updateProgress(attributeWithoutSynchronization(progressAttr));
+
+ createContainedElement(*m_progressElement, attachmentProgressCircleIdentifier());
+
auto informationArea = createContainedElement(*m_containerElement, attachmentInformationAreaIdentifier());
m_informationBlock = createContainedElement(informationArea, attachmentInformationBlockIdentifier());
@@ -275,6 +292,21 @@ class AttachmentSaveEventListener final : public EventListener {
WeakPtr m_attachment;
};
+void HTMLAttachmentElement::updateProgress(const AtomString& progress)
+{
+ if (!m_progressElement)
+ return;
+
+ bool validProgress = false;
+ float value = progress.toFloat(&validProgress);
+ if (validProgress && std::isfinite(value)) {
+ m_progressElement->setAttributeWithoutSynchronization(styleAttr, makeAtomString("--progress: ", (value < 0.0) ? "0"_s : (value > 1.0) ? "1"_s : progress));
+ return;
+ }
+
+ m_progressElement->setAttributeWithoutSynchronization(styleAttr, "display: none;"_s);
+}
+
void HTMLAttachmentElement::updateSaveButton(bool show)
{
if (!show) {
@@ -425,10 +457,12 @@ RefPtr HTMLAttachmentElement::enclosingImageElement() const
void HTMLAttachmentElement::parseAttribute(const QualifiedName& name, const AtomString& value)
{
- if (name == actionAttr || name == progressAttr || name == subtitleAttr() || name == titleAttr || name == typeAttr) {
+ if (name == actionAttr || name == subtitleAttr() || name == titleAttr || name == typeAttr) {
if (m_innerLegacyAttachment)
m_innerLegacyAttachment->setAttributeWithoutSynchronization(name, value);
invalidateRendering();
+ } else if (name == progressAttr && m_implementation == Implementation::Legacy) {
+ invalidateRendering();
}
HTMLElement::parseAttribute(name, value);
@@ -442,7 +476,9 @@ void HTMLAttachmentElement::parseAttribute(const QualifiedName& name, const Atom
} else if (name == subtitleAttr()) {
if (m_subtitleElement)
m_subtitleElement->setTextContent(String(value.string()));
- } else if (name == saveAttr())
+ } else if (name == progressAttr)
+ updateProgress(value);
+ else if (name == saveAttr())
updateSaveButton(!value.isNull());
#if ENABLE(SERVICE_CONTROLS)
diff --git a/Source/WebCore/html/HTMLAttachmentElement.h b/Source/WebCore/html/HTMLAttachmentElement.h
index e90c5ba7321b..e76d993b7ef1 100644
--- a/Source/WebCore/html/HTMLAttachmentElement.h
+++ b/Source/WebCore/html/HTMLAttachmentElement.h
@@ -98,6 +98,7 @@ class HTMLAttachmentElement final : public HTMLElement {
void didAddUserAgentShadowRoot(ShadowRoot&) final;
void ensureModernShadowTree(ShadowRoot&);
+ void updateProgress(const AtomString&);
void updateSaveButton(bool);
RenderPtr createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
@@ -126,6 +127,7 @@ class HTMLAttachmentElement final : public HTMLElement {
RefPtr m_innerLegacyAttachment;
RefPtr m_containerElement;
+ RefPtr m_progressElement;
RefPtr m_informationBlock;
RefPtr m_actionTextElement;
RefPtr m_titleElement;
diff --git a/Source/WebCore/html/shadow/attachmentElementShadow.css b/Source/WebCore/html/shadow/attachmentElementShadow.css
index f98b63688614..a307439a56bc 100644
--- a/Source/WebCore/html/shadow/attachmentElementShadow.css
+++ b/Source/WebCore/html/shadow/attachmentElementShadow.css
@@ -80,6 +80,25 @@ attachment#attachment-preview {
overflow: hidden;
}
+div#attachment-progress {
+ grid-row: 1;
+ grid-column: 1;
+ width: 100%;
+ aspect-ratio: 1;
+ border-radius: 50%;
+ color: -apple-system-secondary-label;
+ background: conic-gradient(currentcolor calc(var(--progress) * 100%), transparent 0);
+}
+
+/* FIXME: Move the border into attachment-progress above, and remove this div, when rdar://107621207 is fixed (currently it produces artifacts at the edges). */
+div#attachment-progress-circle {
+ width: 100%;
+ aspect-ratio: 1;
+ border-radius: 50%;
+ border: 4px solid currentcolor;
+ box-sizing: border-box;
+}
+
div#attachment-information-area {
grid-row: 1;
grid-column: 2;