diff --git a/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt
index 52242ff5f0a2..56069ed1a1dd 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/trusted-types/block-Document-execCommand-expected.txt
@@ -1,5 +1,6 @@
+CONSOLE MESSAGE: This requires a TrustedHTML value else it violates the following Content Security Policy directive: "require-trusted-types-for 'script'"
-FAIL Document.execCommand("insertHTML") throws. assert_throws_js: function "_ => document.execCommand(command, false, "Hello World")" did not throw
+PASS Document.execCommand("insertHTML") throws.
PASS Document.execCommand("insertHTML") works with a TrustedHTML argument.
PASS Document.execCommand("paste") works as usual."
PASS Document.execCommand("paste") works with a TrustedHTML argument.
diff --git a/Source/WebCore/dom/Document+HTML.idl b/Source/WebCore/dom/Document+HTML.idl
index d9fe8ab2add8..602ceb7309f6 100644
--- a/Source/WebCore/dom/Document+HTML.idl
+++ b/Source/WebCore/dom/Document+HTML.idl
@@ -68,7 +68,7 @@ partial interface Document {
[ImplementedAs=windowProxy] readonly attribute WindowProxy? defaultView;
boolean hasFocus();
[CEReactions=Needed] attribute DOMString designMode;
- [CEReactions=Needed] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
+ [CEReactions=Needed] boolean execCommand(DOMString commandId, optional boolean showUI = false, optional (DOMString or TrustedHTML) value = "");
boolean queryCommandEnabled(DOMString commandId);
boolean queryCommandIndeterm(DOMString commandId);
boolean queryCommandState(DOMString commandId);
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index e3fc31129fd3..6e3f29790c6c 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -272,6 +272,7 @@
#include "TouchAction.h"
#include "TransformSource.h"
#include "TreeWalker.h"
+#include "TrustedType.h"
#include "TypedElementDescendantIteratorInlines.h"
#include "UndoManager.h"
#include "UserGestureIndicator.h"
@@ -6895,13 +6896,27 @@ static Editor::Command command(Document* document, const String& commandName, bo
userInterface ? EditorCommandSource::DOMWithUserInterface : EditorCommandSource::DOM);
}
-ExceptionOr Document::execCommand(const String& commandName, bool userInterface, const String& value)
+ExceptionOr Document::execCommand(const String& commandName, bool userInterface, const std::variant>& value)
{
if (UNLIKELY(!isHTMLDocument() && !isXHTMLDocument()))
return Exception { ExceptionCode::InvalidStateError, "execCommand is only supported on HTML documents."_s };
+ auto stringValueHolder = WTF::switchOn(value,
+ [&commandName, this](const String& str) -> ExceptionOr {
+ if (commandName != "insertHTML"_s)
+ return String(str);
+ return trustedTypeCompliantString(TrustedType::TrustedHTML, *scriptExecutionContext(), str, "Document execCommand"_s);
+ },
+ [](const RefPtr& trustedHtml) -> ExceptionOr {
+ return trustedHtml->toString();
+ }
+ );
+
+ if (stringValueHolder.hasException())
+ return stringValueHolder.releaseException();
+
EventQueueScope eventQueueScope;
- return command(this, commandName, userInterface).execute(value);
+ return command(this, commandName, userInterface).execute(stringValueHolder.releaseReturnValue());
}
ExceptionOr Document::queryCommandEnabled(const String& commandName)
diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h
index 9476aaf98f81..e33017edd227 100644
--- a/Source/WebCore/dom/Document.h
+++ b/Source/WebCore/dom/Document.h
@@ -46,6 +46,7 @@
#include "Supplementable.h"
#include "Timer.h"
#include "TreeScope.h"
+#include "TrustedHTML.h"
#include "URLKeepingBlobAlive.h"
#include "UserActionElementSet.h"
#include "ViewportArguments.h"
@@ -1197,7 +1198,7 @@ class Document
inline CheckedRef checkedMarkers(); // Defined in DocumentInlines.h.
inline CheckedRef checkedMarkers() const; // Defined in DocumentInlines.h.
- WEBCORE_EXPORT ExceptionOr execCommand(const String& command, bool userInterface = false, const String& value = String());
+ WEBCORE_EXPORT ExceptionOr execCommand(const String& command, bool userInterface = false, const std::variant>& value = String());
WEBCORE_EXPORT ExceptionOr queryCommandEnabled(const String& command);
WEBCORE_EXPORT ExceptionOr queryCommandIndeterm(const String& command);
WEBCORE_EXPORT ExceptionOr queryCommandState(const String& command);
diff --git a/Source/WebCore/dom/TrustedHTML.h b/Source/WebCore/dom/TrustedHTML.h
index 76a6b777b3c0..8dfdcdedfeb6 100644
--- a/Source/WebCore/dom/TrustedHTML.h
+++ b/Source/WebCore/dom/TrustedHTML.h
@@ -31,7 +31,7 @@
namespace WebCore {
-class TrustedHTML : public ScriptWrappable, public RefCounted {
+class WEBCORE_EXPORT TrustedHTML : public ScriptWrappable, public RefCounted {
WTF_MAKE_ISO_ALLOCATED(TrustedHTML);
public:
static Ref create(const String& data);