Diff
Modified: trunk/LayoutTests/ChangeLog (290518 => 290519)
--- trunk/LayoutTests/ChangeLog 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/LayoutTests/ChangeLog 2022-02-25 19:26:27 UTC (rev 290519)
@@ -1,3 +1,22 @@
+2022-02-25 Alex Christensen <[email protected]>
+
+ Re-add YouTubePluginReplacement, removed in r285252
+ https://bugs.webkit.org/show_bug.cgi?id=237182
+
+ Reviewed by Chris Dumez.
+
+ * TestExpectations:
+ * platform/ios-wk2/TestExpectations:
+ * platform/win/TestExpectations:
+ * security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement-expected.txt: Copied from LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement-expected.txt.
+ * security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html: Copied from LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html.
+ * security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement-expected.txt: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement-expected.txt.
+ * security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html.
+ * security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-expected.txt: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-expected.txt.
+ * security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type-expected.txt: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type-expected.txt.
+ * security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html.
+ * security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html: Copied from LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html.
+
2022-02-25 J Pascoe <[email protected]>
[WebAuthn] Use default pubKeyCredParams if empty in makeCredential
Modified: trunk/LayoutTests/TestExpectations (290518 => 290519)
--- trunk/LayoutTests/TestExpectations 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/LayoutTests/TestExpectations 2022-02-25 19:26:27 UTC (rev 290519)
@@ -5157,6 +5157,10 @@
imported/blink/http/tests/plugins [ Skip ]
imported/blink/plugins [ Skip ]
js/dom/reflect-set-onto-dom.html [ Skip ]
+security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html [ Skip ]
+security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html [ Skip ]
+security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html [ Skip ]
+security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html [ Skip ]
userscripts/user-script-plugin-document.html [ Skip ]
# This is marked as passing on WK2.
Modified: trunk/LayoutTests/platform/ios-wk2/TestExpectations (290518 => 290519)
--- trunk/LayoutTests/platform/ios-wk2/TestExpectations 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/LayoutTests/platform/ios-wk2/TestExpectations 2022-02-25 19:26:27 UTC (rev 290519)
@@ -2021,6 +2021,8 @@
webkit.org/b/214955 fast/parser/xml-colon-entity.html [ Failure ]
+webkit.org/b/223750 [ Debug ] security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html [ Pass Crash ]
+
webkit.org/b/155196 security/contentSecurityPolicy/video-with-file-url-allowed-by-media-src-star-with-AllowContentSecurityPolicySourceStarToMatchAnyProtocol-enabled.html [ Pass ImageOnlyFailure ]
webkit.org/b/155196 security/contentSecurityPolicy/video-with-file-url-allowed-by-media-src-star.html [ Pass ImageOnlyFailure ]
Modified: trunk/LayoutTests/platform/win/TestExpectations (290518 => 290519)
--- trunk/LayoutTests/platform/win/TestExpectations 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/LayoutTests/platform/win/TestExpectations 2022-02-25 19:26:27 UTC (rev 290519)
@@ -3474,6 +3474,7 @@
pageoverlay/overlay-installation.html [ Failure ]
pageoverlay/overlay-large-document-scrolled.html [ Failure ]
pageoverlay/overlay-large-document.html [ Failure ]
+security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html [ Failure ]
storage/indexeddb/modern/blob-cursor.html [ Failure ]
streams/readable-byte-stream-controller.html [ Failure ]
streams/readable-byte-stream-controller-worker.html [ Failure ]
Added: trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement-expected.txt (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement-expected.txt (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement-expected.txt 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Refused to load https://www.youtube.com/v/UF8uR6Z6KLc because it does not appear in the object-src directive of the Content Security Policy.
+
Added: trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="object-src 'none'">
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+if (window.internals)
+ window.internals.settings.setYouTubeFlashPluginReplacementEnabled(true);
+
+function done()
+{
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+document.addEventListener("securitypolicyviolation", done, false);
+</script>
+</head>
+<body>
+<object width="425" height="350" classid=""
+ codebase=""
+ <embed width="425" height="350" type="application/x-shockwave-flash" src=""
+</object>
+</body>
+</html>
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement-expected.txt (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement-expected.txt (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement-expected.txt 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,2 @@
+Blocked access to external URL https://www.youtube.com/embed/UF8uR6Z6KLc
+
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="plugin-types application/x-shockwave-flash">
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+if (window.internals)
+ window.internals.settings.setYouTubeFlashPluginReplacementEnabled(true);
+
+// Waiting at least 100ms seems to ensure that YouTube plugin replacement has loaded.
+window.setTimeout(function () {
+ if (window.testRunner)
+ testRunner.notifyDone();
+}, 100);
+</script>
+</head>
+<body>
+<object width="425" height="350" classid=""
+ codebase=""
+ <embed width="425" height="350" type="application/x-shockwave-flash" src=""
+</object>
+</body>
+</html>
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-expected.txt (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-expected.txt (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-expected.txt 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Refused to load https://www.youtube.com/v/UF8uR6Z6KLc because its MIME type does not appear in the plugin-types directive of the Content Security Policy.
+
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type-expected.txt (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type-expected.txt (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type-expected.txt 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,2 @@
+CONSOLE MESSAGE: Refused to load https://www.youtube.com/v/UF8uR6Z6KLc because its MIME type does not appear in the plugin-types directive of the Content Security Policy.
+
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="plugin-types text/html">
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+if (window.internals)
+ window.internals.settings.setYouTubeFlashPluginReplacementEnabled(true);
+
+function done()
+{
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+document.addEventListener("securitypolicyviolation", done, false);
+</script>
+</head>
+<body>
+<object width="425" height="350" classid=""
+ codebase=""
+ <embed width="425" height="350" src=""
+</object>
+</body>
+</html>
Added: trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html (0 => 290519)
--- trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html (rev 0)
+++ trunk/LayoutTests/security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="plugin-types text/html">
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+if (window.internals)
+ window.internals.settings.setYouTubeFlashPluginReplacementEnabled(true);
+
+function done()
+{
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+document.addEventListener("securitypolicyviolation", done, false);
+</script>
+</head>
+<body>
+<object width="425" height="350" classid=""
+ codebase=""
+ <embed width="425" height="350" type="application/x-shockwave-flash" src=""
+</object>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (290518 => 290519)
--- trunk/Source/WebCore/ChangeLog 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/ChangeLog 2022-02-25 19:26:27 UTC (rev 290519)
@@ -1,3 +1,44 @@
+2022-02-25 Alex Christensen <[email protected]>
+
+ Re-add YouTubePluginReplacement, removed in r285252
+ https://bugs.webkit.org/show_bug.cgi?id=237182
+ <rdar://89148022>
+
+ Reviewed by Chris Dumez.
+
+ Tests: security/contentSecurityPolicy/object-src-none-blocks-youtube-plugin-replacement.html
+ security/contentSecurityPolicy/plugins-types-allows-youtube-plugin-replacement.html
+ security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement-without-mime-type.html
+ security/contentSecurityPolicy/plugins-types-blocks-youtube-plugin-replacement.html
+
+ Its removal broke webpages that work in Chrome and Firefox, so back it comes.
+
+ * Headers.cmake:
+ * Modules/plugins: Copied from Source/WebCore/Modules/plugins.
+ * SourcesCocoa.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * bindings/js/JSPluginElementFunctions.cpp:
+ (WebCore::pluginScriptObject):
+ * bindings/scripts/CodeGeneratorJS.pm:
+ (GenerateImplementation):
+ * bindings/scripts/test/JS/JSTestPluginInterface.cpp:
+ (WebCore::JSTestPluginInterface::visitChildrenImpl):
+ * html/HTMLPlugInElement.cpp:
+ (WebCore::HTMLPlugInElement::createElementRenderer):
+ (WebCore::HTMLPlugInElement::didAddUserAgentShadowRoot):
+ (WebCore::registrar):
+ (WebCore::pluginReplacementForType):
+ (WebCore::HTMLPlugInElement::requestObject):
+ (WebCore::HTMLPlugInElement::scriptObjectForPluginReplacement):
+ * html/HTMLPlugInElement.h:
+ (WebCore::HTMLPlugInElement::pluginReplacementScriptObject):
+ * html/shadow/ShadowPseudoIds.cpp:
+ (WebCore::ShadowPseudoIds::webkitPluginReplacement):
+ * html/shadow/ShadowPseudoIds.h:
+ * html/shadow/YouTubeEmbedShadowElement.cpp:
+ * html/shadow/YouTubeEmbedShadowElement.h:
+ * page/Settings.yaml:
+
2022-02-25 J Pascoe <[email protected]>
[WebAuthn] Use default pubKeyCredParams if empty in makeCredential
https://bugs.webkit.org/show_bug.cgi?id=237109
Modified: trunk/Source/WebCore/Headers.cmake (290518 => 290519)
--- trunk/Source/WebCore/Headers.cmake 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/Headers.cmake 2022-02-25 19:26:27 UTC (rev 290519)
@@ -298,6 +298,9 @@
Modules/permissions/PermissionObserver.h
Modules/permissions/PermissionState.h
+ Modules/plugins/PluginReplacement.h
+ Modules/plugins/YouTubePluginReplacement.h
+
Modules/push-api/PushCrypto.h
Modules/push-api/PushDatabase.h
Modules/push-api/PushMessageCrypto.h
Added: trunk/Source/WebCore/Modules/plugins/PluginReplacement.h (0 => 290519)
--- trunk/Source/WebCore/Modules/plugins/PluginReplacement.h (rev 0)
+++ trunk/Source/WebCore/Modules/plugins/PluginReplacement.h 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "RenderPtr.h"
+#include <_javascript_Core/JSCJSValue.h>
+#include <_javascript_Core/JSCJSValueInlines.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+class JSObject;
+}
+
+namespace WebCore {
+
+class HTMLPlugInElement;
+class RenderElement;
+class RenderStyle;
+class RenderTreePosition;
+class Settings;
+class ShadowRoot;
+
+class PluginReplacement : public RefCounted<PluginReplacement> {
+public:
+ virtual ~PluginReplacement() = default;
+
+ struct InstallResult {
+ bool success;
+#if PLATFORM(COCOA)
+ JSC::JSValue scriptObject { };
+#endif
+ };
+
+ virtual InstallResult installReplacement(ShadowRoot&) = 0;
+
+ virtual bool willCreateRenderer() { return false; }
+ virtual RenderPtr<RenderElement> createElementRenderer(HTMLPlugInElement&, RenderStyle&&, const RenderTreePosition&) = 0;
+};
+
+typedef Ref<PluginReplacement> (*CreatePluginReplacement)(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+typedef bool (*PluginReplacementSupportsType)(const String&);
+typedef bool (*PluginReplacementSupportsFileExtension)(const String&);
+typedef bool (*PluginReplacementSupportsURL)(const URL&);
+typedef bool (*PluginReplacementEnabledForSettings)(const Settings&);
+
+class ReplacementPlugin {
+public:
+ ReplacementPlugin(CreatePluginReplacement constructor, PluginReplacementSupportsType supportsType, PluginReplacementSupportsFileExtension supportsFileExtension, PluginReplacementSupportsURL supportsURL, PluginReplacementEnabledForSettings isEnabledBySettings)
+ : m_constructor(constructor)
+ , m_supportsType(supportsType)
+ , m_supportsFileExtension(supportsFileExtension)
+ , m_supportsURL(supportsURL)
+ , m_isEnabledBySettings(isEnabledBySettings)
+ {
+ }
+
+ explicit ReplacementPlugin(const ReplacementPlugin& other)
+ : m_constructor(other.m_constructor)
+ , m_supportsType(other.m_supportsType)
+ , m_supportsFileExtension(other.m_supportsFileExtension)
+ , m_supportsURL(other.m_supportsURL)
+ , m_isEnabledBySettings(other.m_isEnabledBySettings)
+ {
+ }
+
+ Ref<PluginReplacement> create(HTMLPlugInElement& element, const Vector<String>& paramNames, const Vector<String>& paramValues) const { return m_constructor(element, paramNames, paramValues); }
+ bool supportsType(const String& mimeType) const { return m_supportsType(mimeType); }
+ bool supportsFileExtension(const String& extension) const { return m_supportsFileExtension(extension); }
+ bool supportsURL(const URL& url) const { return m_supportsURL(url); }
+ bool isEnabledBySettings(const Settings& settings) const { return m_isEnabledBySettings(settings); };
+
+private:
+ CreatePluginReplacement m_constructor;
+ PluginReplacementSupportsType m_supportsType;
+ PluginReplacementSupportsFileExtension m_supportsFileExtension;
+ PluginReplacementSupportsURL m_supportsURL;
+ PluginReplacementEnabledForSettings m_isEnabledBySettings;
+};
+
+typedef void (*PluginReplacementRegistrar)(const ReplacementPlugin&);
+
+}
Added: trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp (0 => 290519)
--- trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp (rev 0)
+++ trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YouTubePluginReplacement.h"
+
+#include "HTMLIFrameElement.h"
+#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
+#include "HTMLPlugInElement.h"
+#include "RenderElement.h"
+#include "Settings.h"
+#include "ShadowRoot.h"
+#include "YouTubeEmbedShadowElement.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+void YouTubePluginReplacement::registerPluginReplacement(PluginReplacementRegistrar registrar)
+{
+ registrar(ReplacementPlugin(create, supportsMIMEType, supportsFileExtension, supportsURL, isEnabledBySettings));
+}
+
+Ref<PluginReplacement> YouTubePluginReplacement::create(HTMLPlugInElement& plugin, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+ return adoptRef(*new YouTubePluginReplacement(plugin, paramNames, paramValues));
+}
+
+bool YouTubePluginReplacement::supportsMIMEType(const String& mimeType)
+{
+ return equalLettersIgnoringASCIICase(mimeType, "application/x-shockwave-flash")
+ || equalLettersIgnoringASCIICase(mimeType, "application/futuresplash");
+}
+
+bool YouTubePluginReplacement::supportsFileExtension(const String& extension)
+{
+ return equalLettersIgnoringASCIICase(extension, "spl") || equalLettersIgnoringASCIICase(extension, "swf");
+}
+
+YouTubePluginReplacement::YouTubePluginReplacement(HTMLPlugInElement& plugin, const Vector<String>& paramNames, const Vector<String>& paramValues)
+ : m_parentElement(plugin)
+{
+ ASSERT(paramNames.size() == paramValues.size());
+ for (size_t i = 0; i < paramNames.size(); ++i)
+ m_attributes.add(paramNames[i], paramValues[i]);
+}
+
+RenderPtr<RenderElement> YouTubePluginReplacement::createElementRenderer(HTMLPlugInElement& plugin, RenderStyle&& style, const RenderTreePosition& insertionPosition)
+{
+ ASSERT_UNUSED(plugin, m_parentElement == &plugin);
+
+ if (!m_embedShadowElement)
+ return nullptr;
+
+ return m_embedShadowElement->createElementRenderer(WTFMove(style), insertionPosition);
+}
+
+auto YouTubePluginReplacement::installReplacement(ShadowRoot& root) -> InstallResult
+{
+ m_embedShadowElement = YouTubeEmbedShadowElement::create(m_parentElement->document());
+
+ root.appendChild(*m_embedShadowElement);
+
+ auto iframeElement = HTMLIFrameElement::create(HTMLNames::iframeTag, m_parentElement->document());
+ if (m_attributes.contains("width"))
+ iframeElement->setAttributeWithoutSynchronization(HTMLNames::widthAttr, AtomString("100%", AtomString::ConstructFromLiteral));
+
+ const auto& heightValue = m_attributes.find("height");
+ if (heightValue != m_attributes.end()) {
+ iframeElement->setAttribute(HTMLNames::styleAttr, AtomString("max-height: 100%", AtomString::ConstructFromLiteral));
+ iframeElement->setAttributeWithoutSynchronization(HTMLNames::heightAttr, heightValue->value);
+ }
+
+ iframeElement->setAttributeWithoutSynchronization(HTMLNames::srcAttr, youTubeURL(m_attributes.get("src")));
+ iframeElement->setAttributeWithoutSynchronization(HTMLNames::frameborderAttr, AtomString("0", AtomString::ConstructFromLiteral));
+
+ // Disable frame flattening for this iframe.
+ iframeElement->setAttributeWithoutSynchronization(HTMLNames::scrollingAttr, AtomString("no", AtomString::ConstructFromLiteral));
+ m_embedShadowElement->appendChild(iframeElement);
+
+ return { true };
+}
+
+static URL createYouTubeURL(StringView videoID, StringView timeID)
+{
+ ASSERT(!videoID.isEmpty());
+ ASSERT(videoID != "/");
+ return URL(URL(), makeString("youtube:", videoID, timeID.isEmpty() ? "" : "t=", timeID));
+}
+
+static YouTubePluginReplacement::KeyValueMap queryKeysAndValues(StringView queryString)
+{
+ YouTubePluginReplacement::KeyValueMap queryDictionary;
+
+ size_t queryLength = queryString.length();
+ if (!queryLength)
+ return queryDictionary;
+
+ size_t equalSearchLocation = 0;
+ size_t equalSearchLength = queryLength;
+
+ while (equalSearchLocation < queryLength - 1 && equalSearchLength) {
+
+ // Search for "=".
+ size_t equalLocation = queryString.find('=', equalSearchLocation);
+ if (equalLocation == notFound)
+ break;
+
+ size_t indexAfterEqual = equalLocation + 1;
+ if (indexAfterEqual > queryLength - 1)
+ break;
+
+ // Get the key before the "=".
+ size_t keyLocation = equalSearchLocation;
+ size_t keyLength = equalLocation - equalSearchLocation;
+
+ // Seach for the ampersand.
+ size_t ampersandLocation = queryString.find('&', indexAfterEqual);
+
+ // Get the value after the "=", before the ampersand.
+ size_t valueLocation = indexAfterEqual;
+ size_t valueLength;
+ if (ampersandLocation != notFound)
+ valueLength = ampersandLocation - indexAfterEqual;
+ else
+ valueLength = queryLength - indexAfterEqual;
+
+ // Save the key and the value.
+ if (keyLength && valueLength) {
+ String key = queryString.substring(keyLocation, keyLength).convertToASCIILowercase();
+ String value = queryString.substring(valueLocation, valueLength).toString();
+ value.replace('+', ' ');
+
+ if (!key.isEmpty() && !value.isEmpty())
+ queryDictionary.add(key, value);
+ }
+
+ if (ampersandLocation == notFound)
+ break;
+
+ // Continue searching after the ampersand.
+ size_t indexAfterAmpersand = ampersandLocation + 1;
+ equalSearchLocation = indexAfterAmpersand;
+ equalSearchLength = queryLength - indexAfterAmpersand;
+ }
+
+ return queryDictionary;
+}
+
+static bool isYouTubeURL(const URL& url)
+{
+ auto hostName = url.host();
+ return equalLettersIgnoringASCIICase(hostName, "m.youtube.com")
+ || equalLettersIgnoringASCIICase(hostName, "youtu.be")
+ || equalLettersIgnoringASCIICase(hostName, "www.youtube.com")
+ || equalLettersIgnoringASCIICase(hostName, "youtube.com")
+ || equalLettersIgnoringASCIICase(hostName, "www.youtube-nocookie.com")
+ || equalLettersIgnoringASCIICase(hostName, "youtube-nocookie.com");
+}
+
+static const String& valueForKey(const YouTubePluginReplacement::KeyValueMap& dictionary, const String& key)
+{
+ const auto& value = dictionary.find(key);
+ if (value == dictionary.end())
+ return emptyString();
+
+ return value->value;
+}
+
+static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedURL, String& outPathAfterFirstAmpersand)
+{
+ if (!url.protocolIsInHTTPFamily())
+ return URL();
+
+ // Bail out early if we aren't even on www.youtube.com or youtube.com.
+ if (!isYouTubeURL(url))
+ return URL();
+
+ auto hostName = url.host();
+ bool isYouTubeMobileWebAppURL = equalLettersIgnoringASCIICase(hostName, "m.youtube.com");
+ isYouTubeShortenedURL = equalLettersIgnoringASCIICase(hostName, "youtu.be");
+
+ // Short URL of the form: http://youtu.be/v1d301D
+ if (isYouTubeShortenedURL) {
+ auto videoID = url.lastPathComponent();
+ if (videoID.isEmpty() || videoID == "/")
+ return URL();
+ return createYouTubeURL(videoID, { });
+ }
+
+ auto path = url.path();
+ auto query = url.query();
+ auto fragment = url.fragmentIdentifier();
+
+ // On the YouTube mobile web app, the path and query string are put into the
+ // fragment so that one web page is only ever loaded (see <rdar://problem/9550639>).
+ if (isYouTubeMobileWebAppURL) {
+ size_t location = fragment.find('?');
+ if (location == notFound) {
+ path = fragment;
+ query = emptyString();
+ } else {
+ path = fragment.substring(0, location);
+ query = fragment.substring(location + 1);
+ }
+ fragment = emptyString();
+ }
+
+ if (equalLettersIgnoringASCIICase(path, "/watch")) {
+ if (!query.isEmpty()) {
+ const auto& queryDictionary = queryKeysAndValues(query);
+ String videoID = valueForKey(queryDictionary, "v");
+
+ if (!videoID.isEmpty()) {
+ const auto& fragmentDictionary = queryKeysAndValues(url.fragmentIdentifier());
+ String timeID = valueForKey(fragmentDictionary, "t");
+ return createYouTubeURL(videoID, timeID);
+ }
+ }
+
+ // May be a new-style link (see <rdar://problem/7733692>).
+ if (fragment.startsWith('!')) {
+ query = fragment.substring(1);
+
+ if (!query.isEmpty()) {
+ const auto& queryDictionary = queryKeysAndValues(query);
+ String videoID = valueForKey(queryDictionary, "v");
+
+ if (!videoID.isEmpty()) {
+ String timeID = valueForKey(queryDictionary, "t");
+ return createYouTubeURL(videoID, timeID);
+ }
+ }
+ }
+ } else if (startsWithLettersIgnoringASCIICase(path, "/v/") || startsWithLettersIgnoringASCIICase(path, "/e/")) {
+ StringView videoID;
+ StringView pathAfterFirstAmpersand;
+
+ auto lastPathComponent = url.lastPathComponent();
+ size_t ampersandLocation = lastPathComponent.find('&');
+ if (ampersandLocation != notFound) {
+ // Some URLs we care about use & in place of ? for the first query parameter.
+ videoID = lastPathComponent.substring(0, ampersandLocation);
+ pathAfterFirstAmpersand = lastPathComponent.substring(ampersandLocation + 1, lastPathComponent.length() - ampersandLocation);
+ } else
+ videoID = lastPathComponent;
+
+ if (!videoID.isEmpty()) {
+ outPathAfterFirstAmpersand = pathAfterFirstAmpersand.toString();
+ return createYouTubeURL(videoID, emptyString());
+ }
+ }
+
+ return URL();
+}
+
+String YouTubePluginReplacement::youTubeURL(const String& srcString)
+{
+ URL srcURL = m_parentElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(srcString));
+ return youTubeURLFromAbsoluteURL(srcURL, srcString);
+}
+
+String YouTubePluginReplacement::youTubeURLFromAbsoluteURL(const URL& srcURL, const String& srcString)
+{
+ bool isYouTubeShortenedURL = false;
+ String possiblyMalformedQuery;
+ URL youTubeURL = processAndCreateYouTubeURL(srcURL, isYouTubeShortenedURL, possiblyMalformedQuery);
+ if (srcURL.isEmpty() || youTubeURL.isEmpty())
+ return srcString;
+
+ // Transform the youtubeURL (youtube:VideoID) to iframe embed url which has the format: http://www.youtube.com/embed/VideoID
+ auto srcPath = srcURL.path();
+ const String& videoID = youTubeURL.string().substring(youTubeURL.protocol().length() + 1);
+ size_t locationOfVideoIDInPath = srcPath.find(videoID);
+
+ size_t locationOfPathBeforeVideoID = notFound;
+ if (locationOfVideoIDInPath != notFound) {
+ ASSERT(locationOfVideoIDInPath);
+
+ // From the original URL, we need to get the part before /path/VideoId.
+ locationOfPathBeforeVideoID = StringView(srcString).find(srcPath.substring(0, locationOfVideoIDInPath));
+ } else if (equalLettersIgnoringASCIICase(srcPath, "/watch")) {
+ // From the original URL, we need to get the part before /watch/#!v=VideoID
+ // FIXME: Shouldn't this be ASCII case-insensitive?
+ locationOfPathBeforeVideoID = srcString.find("/watch");
+ } else
+ return srcString;
+
+ ASSERT(locationOfPathBeforeVideoID != notFound);
+
+ auto srcURLPrefix = StringView(srcString).substring(0, locationOfPathBeforeVideoID);
+ auto query = srcURL.query();
+
+ // If the URL has no query, use the possibly malformed query we found.
+ if (query.isEmpty())
+ query = possiblyMalformedQuery;
+
+ // Append the query string if it is valid.
+ return makeString(
+ isYouTubeShortenedURL ? "http://www.youtube.com" : srcURLPrefix,
+ "/embed/",
+ videoID,
+ query.isEmpty() ? "" : "?",
+ query
+ );
+}
+
+bool YouTubePluginReplacement::supportsURL(const URL& url)
+{
+ return isYouTubeURL(url);
+}
+
+bool YouTubePluginReplacement::isEnabledBySettings(const Settings& settings)
+{
+ return settings.youTubeFlashPluginReplacementEnabled();
+}
+
+}
Added: trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.h (0 => 290519)
--- trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.h (rev 0)
+++ trunk/Source/WebCore/Modules/plugins/YouTubePluginReplacement.h 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "PluginReplacement.h"
+#include <wtf/HashMap.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class YouTubeEmbedShadowElement;
+
+class YouTubePluginReplacement final : public PluginReplacement {
+public:
+ static void registerPluginReplacement(PluginReplacementRegistrar);
+
+ typedef HashMap<String, String> KeyValueMap;
+
+ WEBCORE_EXPORT static String youTubeURLFromAbsoluteURL(const URL& srcURL, const String& srcString);
+
+private:
+ YouTubePluginReplacement(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+ static Ref<PluginReplacement> create(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+ static bool supportsMIMEType(const String&);
+ static bool supportsFileExtension(const String&);
+ static bool supportsURL(const URL&);
+ static bool isEnabledBySettings(const Settings&);
+
+ InstallResult installReplacement(ShadowRoot&) final;
+
+ String youTubeURL(const String& rawURL);
+
+ bool willCreateRenderer() final { return m_embedShadowElement; }
+ RenderPtr<RenderElement> createElementRenderer(HTMLPlugInElement&, RenderStyle&&, const RenderTreePosition&) final;
+
+ WeakPtr<HTMLPlugInElement> m_parentElement;
+ RefPtr<YouTubeEmbedShadowElement> m_embedShadowElement;
+ KeyValueMap m_attributes;
+};
+
+}
Modified: trunk/Source/WebCore/SourcesCocoa.txt (290518 => 290519)
--- trunk/Source/WebCore/SourcesCocoa.txt 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/SourcesCocoa.txt 2022-02-25 19:26:27 UTC (rev 290519)
@@ -109,6 +109,7 @@
Modules/model-element/scenekit/SceneKitModelLoaderUSD.mm
Modules/model-element/scenekit/SceneKitModelPlayer.mm
Modules/push-api/cocoa/PushCryptoCocoa.cpp
+Modules/plugins/YouTubePluginReplacement.cpp
Modules/speech/cocoa/SpeechRecognizerCocoa.mm
Modules/speech/cocoa/WebSpeechRecognizerTask.mm
Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm
@@ -180,6 +181,7 @@
editing/mac/TextUndoInsertionMarkupMac.mm
fileapi/FileCocoa.mm
history/mac/HistoryItemMac.mm
+html/shadow/YouTubeEmbedShadowElement.cpp
inspector/mac/PageDebuggerMac.mm
loader/archive/cf/LegacyWebArchive.cpp
loader/archive/cf/LegacyWebArchiveMac.mm
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (290518 => 290519)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-02-25 19:26:27 UTC (rev 290519)
@@ -112,6 +112,7 @@
07277E5517D018CC0015534D /* JSMediaStreamTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */; };
072880D12010F1F60071B255 /* RealtimeVideoCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 072880D02010EED70071B255 /* RealtimeVideoCaptureSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
072A70401D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */; };
+ 072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1DF183C0741000A5988 /* PluginReplacement.h */; settings = {ATTRIBUTES = (Private, ); }; };
073794DE19EE2C5200E5A045 /* RTCOfferAnswerOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 073794DC19EE2C5200E5A045 /* RTCOfferAnswerOptions.h */; };
073794E619EE2FF200E5A045 /* JSRTCConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 073794E419EE2FF200E5A045 /* JSRTCConfiguration.h */; };
073794EC19EE341E00E5A045 /* JSRTCIceServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 073794EA19EE341E00E5A045 /* JSRTCIceServer.h */; };
@@ -2392,6 +2393,7 @@
7A45033018DB717200377B34 /* BufferedLineReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A45032E18DB717200377B34 /* BufferedLineReader.h */; };
7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54857E14E02D51006AE05A /* InspectorHistory.h */; };
7A54881714E432A1006AE05A /* DOMPatchSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54881514E432A1006AE05A /* DOMPatchSupport.h */; };
+ 7A5515F5191830A3009687D2 /* YouTubePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A5515F3191830A3009687D2 /* YouTubePluginReplacement.h */; settings = {ATTRIBUTES = (Private, ); }; };
7A5699702086C619000E0433 /* CookieRequestHeaderFieldProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A56996E2086C618000E0433 /* CookieRequestHeaderFieldProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
7A674BDC0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A674BDA0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h */; };
7A929CA71C598AA9004DF226 /* ResourceLoadStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A929CA21C598378004DF226 /* ResourceLoadStatistics.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3489,6 +3491,7 @@
A52B348F1FA3BDA6008B6246 /* ServiceWorkerDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A52B348C1FA3BD79008B6246 /* ServiceWorkerDebuggable.h */; settings = {ATTRIBUTES = (Private, ); }; };
A52B34961FA3E290008B6246 /* ServiceWorkerInspectorProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A52B34931FA3E286008B6246 /* ServiceWorkerInspectorProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
A52B349E1FA41703008B6246 /* WorkerDebuggerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A52B349C1FA416F8008B6246 /* WorkerDebuggerProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ A5416FE618810EF80009FC5F /* YouTubeEmbedShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A5416FE418810EF80009FC5F /* YouTubeEmbedShadowElement.h */; };
A54A0C621DB7F8C10017A90B /* WorkerInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = A54A0C601DB7F8B70017A90B /* WorkerInspectorController.h */; };
A54A0C661DB805360017A90B /* WorkerDebugger.h in Headers */ = {isa = PBXBuildFile; fileRef = A54A0C641DB805320017A90B /* WorkerDebugger.h */; };
A54A0C681DB807D90017A90B /* WorkerToPageFrontendChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = A54A0C671DB807D00017A90B /* WorkerToPageFrontendChannel.h */; };
@@ -6055,6 +6058,7 @@
072880D02010EED70071B255 /* RealtimeVideoCaptureSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeVideoCaptureSource.h; sourceTree = "<group>"; };
072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OverconstrainedErrorEvent.h; sourceTree = "<group>"; };
072A703F1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OverconstrainedErrorEvent.idl; sourceTree = "<group>"; };
+ 072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginReplacement.h; sourceTree = "<group>"; };
072CA86016CB4DC3008AE131 /* CaptionUserPreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CaptionUserPreferences.cpp; sourceTree = "<group>"; };
072DBBFB25DB38BC00A1350E /* MediaSessionCoordinator.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = MediaSessionCoordinator.idl; sourceTree = "<group>"; };
072DBC0325DC6BD300A1350E /* MediaSessionCoordinator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaSessionCoordinator.h; sourceTree = "<group>"; };
@@ -11512,6 +11516,8 @@
7A54857E14E02D51006AE05A /* InspectorHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorHistory.h; sourceTree = "<group>"; };
7A54881514E432A1006AE05A /* DOMPatchSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMPatchSupport.h; sourceTree = "<group>"; };
7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMPatchSupport.cpp; sourceTree = "<group>"; };
+ 7A5515F3191830A3009687D2 /* YouTubePluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YouTubePluginReplacement.h; sourceTree = "<group>"; };
+ 7A5515F4191830A3009687D2 /* YouTubePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YouTubePluginReplacement.cpp; sourceTree = "<group>"; };
7A56996E2086C618000E0433 /* CookieRequestHeaderFieldProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CookieRequestHeaderFieldProxy.h; sourceTree = "<group>"; };
7A674BD90F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageGroupLoadDeferrer.cpp; sourceTree = "<group>"; };
7A674BDA0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageGroupLoadDeferrer.h; sourceTree = "<group>"; };
@@ -13847,6 +13853,8 @@
A52B349C1FA416F8008B6246 /* WorkerDebuggerProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerDebuggerProxy.h; sourceTree = "<group>"; };
A52D85CA21B0982F0061C1EB /* ServerTimingParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ServerTimingParser.cpp; sourceTree = "<group>"; };
A52D85CB21B098300061C1EB /* ServerTimingParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ServerTimingParser.h; sourceTree = "<group>"; };
+ A5416FE318810EF80009FC5F /* YouTubeEmbedShadowElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YouTubeEmbedShadowElement.cpp; sourceTree = "<group>"; };
+ A5416FE418810EF80009FC5F /* YouTubeEmbedShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YouTubeEmbedShadowElement.h; sourceTree = "<group>"; };
A54A0C5F1DB7F8B70017A90B /* WorkerInspectorController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerInspectorController.cpp; sourceTree = "<group>"; };
A54A0C601DB7F8B70017A90B /* WorkerInspectorController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerInspectorController.h; sourceTree = "<group>"; };
A54A0C631DB805320017A90B /* WorkerDebugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerDebugger.cpp; sourceTree = "<group>"; };
@@ -18779,6 +18787,16 @@
path = mac;
sourceTree = "<group>";
};
+ 072AE1DE183C0513000A5988 /* plugins */ = {
+ isa = PBXGroup;
+ children = (
+ 072AE1DF183C0741000A5988 /* PluginReplacement.h */,
+ 7A5515F4191830A3009687D2 /* YouTubePluginReplacement.cpp */,
+ 7A5515F3191830A3009687D2 /* YouTubePluginReplacement.h */,
+ );
+ path = plugins;
+ sourceTree = "<group>";
+ };
076F0D0812B8192700C26AA4 /* avfoundation */ = {
isa = PBXGroup;
children = (
@@ -21047,6 +21065,8 @@
142B97C813138943008BEF4B /* TextControlInnerElements.h */,
CE212154240DBD30006ED443 /* TextPlaceholderElement.cpp */,
CE212153240DBD30006ED443 /* TextPlaceholderElement.h */,
+ A5416FE318810EF80009FC5F /* YouTubeEmbedShadowElement.cpp */,
+ A5416FE418810EF80009FC5F /* YouTubeEmbedShadowElement.h */,
);
path = shadow;
sourceTree = "<group>";
@@ -26144,6 +26164,7 @@
A1F76B0E1F44C0CF0014C318 /* paymentrequest */,
93B0A64226CDC57400AA21E4 /* permissions */,
1DEF06A2233C32DB00EE228D /* pictureinpicture */,
+ 072AE1DE183C0513000A5988 /* plugins */,
418FCBB82706E4BD00F96ECA /* push-api */,
CDC312E022FCD0B0001204EC /* remoteplayback */,
AA2A5AB716A485A400975A25 /* speech */,
@@ -36705,6 +36726,7 @@
A9C6E4F40D745E48006442E9 /* PluginData.h in Headers */,
97205ABC1239292700B17380 /* PluginDocument.h in Headers */,
1A08FEDD1D592B8B008BA8CB /* PluginInfoProvider.h in Headers */,
+ 072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */,
71E2183A17359FB8006E6E4D /* PlugInsResources.h in Headers */,
0AFDAC3D10F5448C00E1F3D2 /* PluginViewBase.h in Headers */,
BCBB8AB913F1AFB000734DF0 /* PODInterval.h in Headers */,
@@ -38256,6 +38278,8 @@
E1F1E8300C3C2BB9006DB391 /* XSLTExtensions.h in Headers */,
93F199ED08245E59001E9ABC /* XSLTProcessor.h in Headers */,
E1BE512E0CF6C512002EA959 /* XSLTUnicodeSort.h in Headers */,
+ A5416FE618810EF80009FC5F /* YouTubeEmbedShadowElement.h in Headers */,
+ 7A5515F5191830A3009687D2 /* YouTubePluginReplacement.h in Headers */,
FD537353137B651800008DCE /* ZeroPole.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Modified: trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp (290518 => 290519)
--- trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -78,8 +78,12 @@
// Choke point for script/plugin interaction; notify DOMTimer of the event.
DOMTimer::scriptDidInteractWithPlugin(pluginElement);
+
+ // First, see if the element has a plug-in replacement with a script.
+ if (auto* scriptObject = pluginElement.scriptObjectForPluginReplacement())
+ return scriptObject;
- // See if we can ask the plug-in view for its script object.
+ // Next, see if we can ask the plug-in view for its script object.
if (auto* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()))
return scriptObject;
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (290518 => 290519)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2022-02-25 19:26:27 UTC (rev 290519)
@@ -4898,6 +4898,11 @@
push(@implContent, " ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n");
push(@implContent, " Base::visitChildren(thisObject, visitor);\n");
push(@implContent, " thisObject->visitAdditionalChildren(visitor);\n") if $interface->extendedAttributes->{JSCustomMarkFunction};
+ if ($interface->extendedAttributes->{Plugin}) {
+ push(@implContent, "#if PLATFORM(COCOA)\n");
+ push(@implContent, " thisObject->wrapped().pluginReplacementScriptObject().visit(visitor);\n");
+ push(@implContent, "#endif\n");
+ }
if ($interface->extendedAttributes->{GenerateAddOpaqueRoot}) {
AddToImplIncludes("<wtf/GetPtr.h>");
my $functionName = $interface->extendedAttributes->{GenerateAddOpaqueRoot};
Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp (290518 => 290519)
--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -253,6 +253,9 @@
auto* thisObject = jsCast<JSTestPluginInterface*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
+#if PLATFORM(COCOA)
+ thisObject->wrapped().pluginReplacementScriptObject().visit(visitor);
+#endif
}
DEFINE_VISIT_CHILDREN(JSTestPluginInterface);
Modified: trunk/Source/WebCore/html/HTMLPlugInElement.cpp (290518 => 290519)
--- trunk/Source/WebCore/html/HTMLPlugInElement.cpp 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/html/HTMLPlugInElement.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -37,6 +37,7 @@
#include "MIMETypeRegistry.h"
#include "Page.h"
#include "PluginData.h"
+#include "PluginReplacement.h"
#include "PluginViewBase.h"
#include "RenderEmbeddedObject.h"
#include "RenderLayer.h"
@@ -49,6 +50,10 @@
#include "Widget.h"
#include <wtf/IsoMallocInlines.h>
+#if PLATFORM(COCOA)
+#include "YouTubePluginReplacement.h"
+#endif
+
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLPlugInElement);
@@ -225,8 +230,11 @@
return !downcast<RenderEmbeddedObject>(*renderer()).isPluginUnavailable();
}
-RenderPtr<RenderElement> HTMLPlugInElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+RenderPtr<RenderElement> HTMLPlugInElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition& insertionPosition)
{
+ if (m_pluginReplacement && m_pluginReplacement->willCreateRenderer())
+ return m_pluginReplacement->createElementRenderer(*this, WTFMove(style), insertionPosition);
+
return createRenderer<RenderEmbeddedObject>(*this, WTFMove(style));
}
@@ -254,15 +262,124 @@
m_swapRendererTimer.startOneShot(0_s);
}
-void HTMLPlugInElement::didAddUserAgentShadowRoot(ShadowRoot&)
+void HTMLPlugInElement::didAddUserAgentShadowRoot(ShadowRoot& root)
{
+ if (!m_pluginReplacement || !document().page() || displayState() != PreparingPluginReplacement)
+ return;
+
+ root.setResetStyleInheritance(true);
+ auto result = m_pluginReplacement->installReplacement(root);
+
+#if PLATFORM(COCOA)
+ RELEASE_ASSERT(result.success || !result.scriptObject);
+ m_pluginReplacementScriptObject.setWeakly(result.scriptObject);
+#endif
+
+ if (result.success) {
+ setDisplayState(DisplayingPluginReplacement);
+ invalidateStyleAndRenderersForSubtree();
+ }
}
-bool HTMLPlugInElement::requestObject(const String&, const String&, const Vector<String>&, const Vector<String>&)
+#if PLATFORM(COCOA)
+static void registrar(const ReplacementPlugin&);
+#endif
+
+static Vector<ReplacementPlugin*>& registeredPluginReplacements()
{
- return false;
+ static NeverDestroyed<Vector<ReplacementPlugin*>> registeredReplacements;
+ static bool enginesQueried = false;
+
+ if (enginesQueried)
+ return registeredReplacements;
+ enginesQueried = true;
+
+#if PLATFORM(COCOA)
+ YouTubePluginReplacement::registerPluginReplacement(registrar);
+#endif
+
+ return registeredReplacements;
}
+#if PLATFORM(COCOA)
+static void registrar(const ReplacementPlugin& replacement)
+{
+ registeredPluginReplacements().append(new ReplacementPlugin(replacement));
+}
+#endif
+
+static ReplacementPlugin* pluginReplacementForType(const URL& url, const String& mimeType)
+{
+ Vector<ReplacementPlugin*>& replacements = registeredPluginReplacements();
+ if (replacements.isEmpty())
+ return nullptr;
+
+ String extension;
+ auto lastPathComponent = url.lastPathComponent();
+ size_t dotOffset = lastPathComponent.reverseFind('.');
+ if (dotOffset != notFound)
+ extension = lastPathComponent.substring(dotOffset + 1).toString();
+
+ String type = mimeType;
+ if (type.isEmpty() && url.protocolIsData())
+ type = mimeTypeFromDataURL(url.string());
+
+ if (type.isEmpty() && !extension.isEmpty()) {
+ for (auto* replacement : replacements) {
+ if (replacement->supportsFileExtension(extension) && replacement->supportsURL(url))
+ return replacement;
+ }
+ }
+
+ if (type.isEmpty()) {
+ if (extension.isEmpty())
+ return nullptr;
+ type = MIMETypeRegistry::mediaMIMETypeForExtension(extension);
+ }
+
+ if (type.isEmpty())
+ return nullptr;
+
+ for (auto* replacement : replacements) {
+ if (replacement->supportsType(type) && replacement->supportsURL(url))
+ return replacement;
+ }
+
+ return nullptr;
+}
+
+bool HTMLPlugInElement::requestObject(const String& relativeURL, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+ if (m_pluginReplacement)
+ return true;
+
+ URL completedURL;
+ if (!relativeURL.isEmpty())
+ completedURL = document().completeURL(relativeURL);
+
+ ReplacementPlugin* replacement = pluginReplacementForType(completedURL, mimeType);
+ if (!replacement || !replacement->isEnabledBySettings(document().settings()))
+ return false;
+
+ LOG(Plugins, "%p - Found plug-in replacement for %s.", this, completedURL.string().utf8().data());
+
+ m_pluginReplacement = replacement->create(*this, paramNames, paramValues);
+ setDisplayState(PreparingPluginReplacement);
+ return true;
+}
+
+JSC::JSObject* HTMLPlugInElement::scriptObjectForPluginReplacement()
+{
+#if PLATFORM(COCOA)
+ JSC::JSValue value = m_pluginReplacementScriptObject.getValue();
+ if (!value)
+ return nullptr;
+ return value.getObject();
+#else
+ return nullptr;
+#endif
+}
+
bool HTMLPlugInElement::isBelowSizeThreshold() const
{
auto* renderObject = renderer();
Modified: trunk/Source/WebCore/html/HTMLPlugInElement.h (290518 => 290519)
--- trunk/Source/WebCore/html/HTMLPlugInElement.h 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/html/HTMLPlugInElement.h 2022-02-25 19:26:27 UTC (rev 290519)
@@ -35,6 +35,7 @@
namespace WebCore {
+class PluginReplacement;
class RenderWidget;
class Widget;
@@ -58,6 +59,11 @@
DisplayState displayState() const { return m_displayState; }
void setDisplayState(DisplayState);
+ JSC::JSObject* scriptObjectForPluginReplacement();
+#if PLATFORM(COCOA)
+ JSValueInWrappedObject& pluginReplacementScriptObject() { return m_pluginReplacementScriptObject; }
+#endif
+
bool isCapturingMouseEvents() const { return m_isCapturingMouseEvents; }
void setIsCapturingMouseEvents(bool capturing) { m_isCapturingMouseEvents = capturing; }
@@ -108,6 +114,10 @@
RefPtr<JSC::Bindings::Instance> m_instance;
Timer m_swapRendererTimer;
+ RefPtr<PluginReplacement> m_pluginReplacement;
+#if PLATFORM(COCOA)
+ JSValueInWrappedObject m_pluginReplacementScriptObject;
+#endif
bool m_isCapturingMouseEvents { false };
DisplayState m_displayState { Playing };
};
Modified: trunk/Source/WebCore/html/shadow/ShadowPseudoIds.cpp (290518 => 290519)
--- trunk/Source/WebCore/html/shadow/ShadowPseudoIds.cpp 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/html/shadow/ShadowPseudoIds.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -213,6 +213,12 @@
return webkitMeterEvenLessGoodValue;
}
+const AtomString& webkitPluginReplacement()
+{
+ static MainThreadNeverDestroyed<const AtomString> webkitPluginReplacement("-webkit-plugin-replacement", AtomString::ConstructFromLiteral);
+ return webkitPluginReplacement;
+}
+
const AtomString& webkitProgressBar()
{
static MainThreadNeverDestroyed<const AtomString> webkitProgressBar("-webkit-progress-bar", AtomString::ConstructFromLiteral);
Modified: trunk/Source/WebCore/html/shadow/ShadowPseudoIds.h (290518 => 290519)
--- trunk/Source/WebCore/html/shadow/ShadowPseudoIds.h 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/html/shadow/ShadowPseudoIds.h 2022-02-25 19:26:27 UTC (rev 290519)
@@ -77,6 +77,8 @@
const AtomString& webkitMeterSuboptimumValue();
const AtomString& webkitMeterEvenLessGoodValue();
+const AtomString& webkitPluginReplacement();
+
const AtomString& webkitProgressBar();
const AtomString& webkitProgressValue();
const AtomString& webkitProgressInnerElement();
Added: trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.cpp (0 => 290519)
--- trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.cpp (rev 0)
+++ trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YouTubeEmbedShadowElement.h"
+
+#include "RenderBlockFlow.h"
+#include "ShadowPseudoIds.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(YouTubeEmbedShadowElement);
+
+Ref<YouTubeEmbedShadowElement> YouTubeEmbedShadowElement::create(Document& document)
+{
+ auto element = adoptRef(*new YouTubeEmbedShadowElement(document));
+ element->setPseudo(ShadowPseudoIds::webkitPluginReplacement());
+ return element;
+}
+
+YouTubeEmbedShadowElement::YouTubeEmbedShadowElement(Document& document)
+ : HTMLDivElement(HTMLNames::divTag, document)
+{
+}
+
+RenderPtr<RenderElement> YouTubeEmbedShadowElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ return createRenderer<RenderBlockFlow>(*this, WTFMove(style));
+}
+
+}
Added: trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.h (0 => 290519)
--- trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.h (rev 0)
+++ trunk/Source/WebCore/html/shadow/YouTubeEmbedShadowElement.h 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "HTMLDivElement.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class YouTubeEmbedShadowElement final : public HTMLDivElement {
+ WTF_MAKE_ISO_ALLOCATED(YouTubeEmbedShadowElement);
+public:
+ static Ref<YouTubeEmbedShadowElement> create(Document&);
+
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+
+private:
+ YouTubeEmbedShadowElement(Document&);
+};
+
+} // namespace WebCore
Modified: trunk/Source/WebCore/page/Settings.yaml (290518 => 290519)
--- trunk/Source/WebCore/page/Settings.yaml 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Source/WebCore/page/Settings.yaml 2022-02-25 19:26:27 UTC (rev 290519)
@@ -618,3 +618,10 @@
defaultValue:
WebCore:
default: false
+
+YouTubeFlashPluginReplacementEnabled:
+ type: bool
+ defaultValue:
+ WebCore:
+ PLATFORM(COCOA): true
+ default: false
Modified: trunk/Tools/ChangeLog (290518 => 290519)
--- trunk/Tools/ChangeLog 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Tools/ChangeLog 2022-02-25 19:26:27 UTC (rev 290519)
@@ -1,3 +1,13 @@
+2022-02-25 Alex Christensen <[email protected]>
+
+ Re-add YouTubePluginReplacement, removed in r285252
+ https://bugs.webkit.org/show_bug.cgi?id=237182
+
+ Reviewed by Chris Dumez.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp:
+
2022-02-24 Jonathan Bedard <[email protected]>
[Python 3] Invoke validate-committer-lists with Python 3
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (290518 => 290519)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2022-02-25 19:13:53 UTC (rev 290518)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2022-02-25 19:26:27 UTC (rev 290519)
@@ -393,6 +393,7 @@
5C2936961D5C00ED00DEAB1E /* CookieMessage.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5C2936941D5BFD1900DEAB1E /* CookieMessage.html */; };
5C2C01A82734883600F89D37 /* CrossThreadCopier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 278DE64B22B8D611004E0E7A /* CrossThreadCopier.cpp */; };
5C4259462266A68A0039AA7A /* BasicProposedCredentialPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C42594422669E9B0039AA7A /* BasicProposedCredentialPlugIn.mm */; };
+ 5C581D3227C8A01C006B3BC4 /* YouTubePluginReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C581D3127C8A01C006B3BC4 /* YouTubePluginReplacement.cpp */; };
5C6E27A7224EEBEA00128736 /* URLCanonicalization.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E27A6224EEBEA00128736 /* URLCanonicalization.mm */; };
5C7101C725DD98B600686200 /* test_print.pdf in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5C7101C625DD988700686200 /* test_print.pdf */; };
5C75716122124C5200B9E5AC /* BundleRetainPagePlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C75715F221249BD00B9E5AC /* BundleRetainPagePlugIn.mm */; };
@@ -2259,6 +2260,7 @@
5C3B1D2522A74EA400BCF4D0 /* ContextMenus.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContextMenus.mm; sourceTree = "<group>"; };
5C42594422669E9B0039AA7A /* BasicProposedCredentialPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BasicProposedCredentialPlugIn.mm; sourceTree = "<group>"; };
5C4A84941F7EEFD400ACFC54 /* Configuration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Configuration.mm; sourceTree = "<group>"; };
+ 5C581D3127C8A01C006B3BC4 /* YouTubePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YouTubePluginReplacement.cpp; sourceTree = "<group>"; };
5C5E633D1D0B67940085A025 /* UniqueRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniqueRef.cpp; sourceTree = "<group>"; };
5C69BDD41F82A7EB000F4F4B /* _javascript_DuringNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _javascript_DuringNavigation.mm; sourceTree = "<group>"; };
5C6E27A6224EEBEA00128736 /* URLCanonicalization.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = URLCanonicalization.mm; sourceTree = "<group>"; };
@@ -3828,6 +3830,7 @@
7AD3FE8D1D75FB8D00B169A4 /* TransformationMatrix.cpp */,
57D1D75E21DCB7A80093E86A /* U2fCommandConstructorTest.cpp */,
E3A1E77E21B25B39008C6007 /* URLParserTextEncoding.cpp */,
+ 5C581D3127C8A01C006B3BC4 /* YouTubePluginReplacement.cpp */,
);
path = WebCore;
sourceTree = "<group>";
@@ -5927,6 +5930,7 @@
E520A36B25AFB76C00526CB9 /* WKWebViewTitlebarSeparatorTests.mm in Sources */,
7C74C8FA22DFBA9600DA2DAB /* WTFStringUtilities.cpp in Sources */,
C14D304624B4C3BA00480387 /* XPCEndpoint.mm in Sources */,
+ 5C581D3227C8A01C006B3BC4 /* YouTubePluginReplacement.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Added: trunk/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp (0 => 290519)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/YouTubePluginReplacement.cpp 2022-02-25 19:26:27 UTC (rev 290519)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <WebCore/YouTubePluginReplacement.h>
+#include <wtf/MainThread.h>
+#include <wtf/URL.h>
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class YouTubePluginReplacementTest : public testing::Test {
+public:
+ void SetUp() final
+ {
+ WTF::initializeMainThread();
+ }
+};
+
+static bool test(const String& inputURLString, const String& expectedURLString)
+{
+ URL inputURL(URL(), inputURLString);
+ String actualURLString = YouTubePluginReplacement::youTubeURLFromAbsoluteURL(inputURL, inputURLString);
+ return actualURLString.utf8() == expectedURLString.utf8();
+}
+
+TEST_F(YouTubePluginReplacementTest, YouTubeURLFromAbsoluteURL)
+{
+ // YouTube non-video URL, not expected to be transformed.
+ EXPECT_TRUE(test("https://www.youtube.com", "https://www.youtube.com"));
+
+ // Basic YouTube video links, expected to be transformed.
+ EXPECT_TRUE(test("https://www.youtube.com/v/dQw4w9WgXcQ", "https://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ", "http://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("https://youtube.com/v/dQw4w9WgXcQ", "https://youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://youtube.com/v/dQw4w9WgXcQ", "http://youtube.com/embed/dQw4w9WgXcQ"));
+
+ // With start time, preserved.
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ?start=4", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ?start=4&fs=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4&fs=1"));
+
+ // With an invalid query (see & instead of ?), we preserve and fix the query.
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ&start=4", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/v/dQw4w9WgXcQ&start=4&fs=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?start=4&fs=1"));
+
+ // Non-Flash URL is untouched.
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ", "https://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://www.youtube.com/embed/dQw4w9WgXcQ", "http://www.youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("https://youtube.com/embed/dQw4w9WgXcQ", "https://youtube.com/embed/dQw4w9WgXcQ"));
+ EXPECT_TRUE(test("http://youtube.com/embed/dQw4w9WgXcQ", "http://youtube.com/embed/dQw4w9WgXcQ"));
+ // Even with extra parameters.
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ?start=4", "https://www.youtube.com/embed/dQw4w9WgXcQ?start=4"));
+ EXPECT_TRUE(test("http://www.youtube.com/embed/dQw4w9WgXcQ?enablejsapi=1", "http://www.youtube.com/embed/dQw4w9WgXcQ?enablejsapi=1"));
+ // Even with an invalid "query".
+ EXPECT_TRUE(test("https://www.youtube.com/embed/dQw4w9WgXcQ&start=4", "https://www.youtube.com/embed/dQw4w9WgXcQ&start=4"));
+
+ // Don't transform anything with a non "/v/" path component immediately following the domain.
+ EXPECT_TRUE(test("https://www.youtube.com/something/v/dQw4w9WgXcQ", "https://www.youtube.com/something/v/dQw4w9WgXcQ"));
+
+ // Non-YouTube domain whose path looks like a Flash video shouldn't be transformed.
+ EXPECT_TRUE(test("https://www.notyoutube.com/v/dQw4w9WgXcQ", "https://www.notyoutube.com/v/dQw4w9WgXcQ"));
+}
+
+} // namespace TestWebKitAPI