Allow the QuickTime plug-in to be replaced by script in an isolated word
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Nov 2013 01:05:35 +0000 (01:05 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Nov 2013 01:05:35 +0000 (01:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=124900

Reviewed by Dean Jackson.

Source/WebCore:

Test: plugins/quicktime-plugin-replacement.html

* CMakeLists.txt: Add new Modules path.
* DerivedSources.make: Add new files.
* GNUmakefile.am: Add new Modules path.
* GNUmakefile.list.am: Add new header.
* WebCore.vcxproj/WebCore.vcxproj: Add new header.
* WebCore.vcxproj/WebCoreCommon.props: Add new Modules path.
* WebCore.xcodeproj/project.pbxproj: Add new files.

* Modules/plugins: Added.
* Modules/plugins/PluginReplacement.h: Added. Defines the interface for a plug-in replacement.

Create a replacement for the QuickTime plug-in.
* Modules/plugins/QuickTimePluginReplacement.cpp: Added.
* Modules/plugins/QuickTimePluginReplacement.css: Added.
* Modules/plugins/QuickTimePluginReplacement.h: Added.
* Modules/plugins/QuickTimePluginReplacement.idl: Added.
* Modules/plugins/QuickTimePluginReplacement.js: Added.

Allow plug-in replacement to be enabled at runtime.
* bindings/generic/RuntimeEnabledFeatures.h:
(WebCore::RuntimeEnabledFeatures::setPluginReplacementEnabled):
(WebCore::RuntimeEnabledFeatures::pluginReplacementEnabled):

* bindings/js/JSDOMBinding.h:
(WebCore::toJS): Add toJS(... const String& ...).

* bindings/js/JSPluginElementFunctions.cpp:
(WebCore::pluginScriptObject): Give a plug-in replacement a first shot at defining the
    script interface.

* html/HTMLEmbedElement.cpp:
(WebCore::HTMLEmbedElement::updateWidget): Call base class requestObject.

* html/HTMLMediaElement.cpp:
(HTMLMediaElement::fileSize): New, passthrough to media engine.
* html/HTMLMediaElement.h:

* html/HTMLObjectElement.cpp:
(WebCore::HTMLObjectElement::updateWidget): Call base class requestObject.

Moved some logic that was previously used only for creating a plug-in snapshot to the base
class so it can be shared by a plug-in replacement.
* html/HTMLPlugInElement.cpp:
(WebCore::HTMLPlugInElement::HTMLPlugInElement): Initialize timer used to swap renderers.
(WebCore::HTMLPlugInElement::createRenderer): Allow plug-in replacement to create the renderer.
(WebCore::HTMLPlugInElement::swapRendererTimerFired): Create a shadow root.
(WebCore::HTMLPlugInElement::setDisplayState): Set the new state, prime the swap renderer
    timer if necessary.
(WebCore::HTMLPlugInElement::didAddUserAgentShadowRoot): Tell the plug-in replacement to
    install itself in the new shadow DOM.
(WebCore::registeredPluginReplacements): Return vector of all registered plug-in replacements.
(WebCore::registerPluginReplacement): Add a plug-in replacement.
(WebCore::pluginReplacementForType): Find a plug-in replacement for a MIME type.
(WebCore::HTMLPlugInElement::requestObject): If there is a plug-in replacement for the MIME type,
    create it and set the display state.
(WebCore::HTMLPlugInElement::scriptObjectForPluginReplacement): Return the script object for
    the current plug-in replacement, if any.
* html/HTMLPlugInElement.h:

Move some plug-in snapshot code into the base class.
* html/HTMLPlugInImageElement.cpp:
(WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): No need to initialize timer.
(WebCore::HTMLPlugInImageElement::setDisplayState): Call base class.
(WebCore::HTMLPlugInImageElement::createRenderer): Ditto.
(WebCore::HTMLPlugInImageElement::didAddUserAgentShadowRoot): Ditto.
(WebCore::HTMLPlugInImageElement::userDidClickSnapshot): Remove unnecessary class name.
(WebCore::HTMLPlugInImageElement::requestObject): New.
* html/HTMLPlugInImageElement.h:

* html/HTMLVideoElement.h: Make createRenderer public so the QuickTime plug-in replacement can
    call it.

* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::fileSize): New.
* platform/graphics/MediaPlayer.h:
* platform/graphics/MediaPlayerPrivate.h:

* platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
(WebCore::MediaPlayerPrivateAVFoundation::extraMemoryCost): totalBytes returns an unsigned long long.
* platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h:
(WebCore::MediaPlayerPrivateAVFoundation::fileSize):

* platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp:
(WebCore::MediaPlayerPrivateAVFoundationCF::totalBytes): Return an unsigned long long.
* platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.h:

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::totalBytes): Ditto.

* testing/InternalSettings.cpp:
(WebCore::InternalSettings::Backup::Backup): Backup the plug-in replacement runtime setting.
(WebCore::InternalSettings::Backup::restoreTo): Restore it.
(WebCore::InternalSettings::setPluginReplacementEnabled): Set it.
* testing/InternalSettings.h:
* testing/InternalSettings.idl:

LayoutTests:

* platform/efl/TestExpectations: Skip the new test.
* platform/gtk/TestExpectations: Ditto.
* platform/wincairo/TestExpectations: Ditto.
* plugins/quicktime-plugin-replacement.html: Added.
* plugins/quicktime-plugin-replacement-expected.txt: Added.
* plugins/resources/orange.mov: Replace movie compressed with ancient (and deprecated)
    animated gif codec with one compressed with H.264 codec.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@159827 268f45cc-cd09-0410-ab3c-d52691b4dbfc

45 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/wincairo/TestExpectations
LayoutTests/plugins/quicktime-plugin-replacement-expected.txt [new file with mode: 0644]
LayoutTests/plugins/quicktime-plugin-replacement.html [new file with mode: 0644]
LayoutTests/plugins/resources/orange.mov
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/GNUmakefile.am
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Modules/plugins/PluginReplacement.h [new file with mode: 0644]
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp [new file with mode: 0644]
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.css [new file with mode: 0644]
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h [new file with mode: 0644]
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl [new file with mode: 0644]
Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js [new file with mode: 0644]
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCoreCommon.props
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSPluginElementFunctions.cpp
Source/WebCore/html/HTMLEmbedElement.cpp
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/HTMLObjectElement.cpp
Source/WebCore/html/HTMLPlugInElement.cpp
Source/WebCore/html/HTMLPlugInElement.h
Source/WebCore/html/HTMLPlugInImageElement.cpp
Source/WebCore/html/HTMLPlugInImageElement.h
Source/WebCore/html/HTMLVideoElement.h
Source/WebCore/platform/graphics/MediaPlayer.cpp
Source/WebCore/platform/graphics/MediaPlayer.h
Source/WebCore/platform/graphics/MediaPlayerPrivate.h
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h
Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp
Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.h
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h
Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl

index 81e80cc..61cb7ef 100644 (file)
@@ -1,3 +1,18 @@
+2013-11-27  Eric Carlson  <eric.carlson@apple.com>
+
+        Allow the QuickTime plug-in to be replaced by script in an isolated word
+        https://bugs.webkit.org/show_bug.cgi?id=124900
+
+        Reviewed by Dean Jackson.
+
+        * platform/efl/TestExpectations: Skip the new test.
+        * platform/gtk/TestExpectations: Ditto.
+        * platform/wincairo/TestExpectations: Ditto.
+        * plugins/quicktime-plugin-replacement.html: Added.
+        * plugins/quicktime-plugin-replacement-expected.txt: Added.
+        * plugins/resources/orange.mov: Replace movie compressed with ancient (and deprecated) 
+            animated gif codec with one compressed with H.264 codec.
+
 2013-11-27  Thiago de Barros Lacerda  <thiago.lacerda@openbossa.org>
 
         Adding MediaConstraintsMock class
index 1bd527f..165528b 100644 (file)
@@ -1751,3 +1751,6 @@ webkit.org/b/124663 media/track/track-legacyapi-with-automatic-mode.html [ Skip
 webkit.org/b/124890 platform/efl/accessibility/media-emits-object-replacement.html [ Failure ]
 
 webkit.org/b/124894 accessibility/fieldset-element.html [ Missing ]
+
+# QuickTime plug-in not relevant to this port
+plugins/quicktime-plugin-replacement.html [ Skip ]
index afcd08d..65f0241 100644 (file)
@@ -511,6 +511,9 @@ webkit.org/b/107194 http/tests/security/no-indexeddb-from-sandbox.html [ Skip ]
 # crypto.subtle is not yet enabled
 crypto/subtle [ Skip ]
 
+# QuickTime plug-in not relevant to this port
+plugins/quicktime-plugin-replacement.html [ Skip ]
+
 #////////////////////////////////////////////////////////////////////////////////////////
 # End of Expected failures
 #////////////////////////////////////////////////////////////////////////////////////////
index f02e4e1..2bf9cdf 100644 (file)
@@ -2853,3 +2853,6 @@ editing/secure-input [ Failure ]
 
 # crypto.subtle is not yet enabled
 crypto/subtle [ Skip ]
+
+# QuickTime plug-in not relevant to this port
+plugins/quicktime-plugin-replacement.html [ Skip ]
diff --git a/LayoutTests/plugins/quicktime-plugin-replacement-expected.txt b/LayoutTests/plugins/quicktime-plugin-replacement-expected.txt
new file mode 100644 (file)
index 0000000..0d14d56
--- /dev/null
@@ -0,0 +1,63 @@
+
+EVENT(qt_begin)
+EVENT(qt_validated)
+EVENT(qt_canplay)
+EVENT(qt_canplaythrough)
+
+** Test to make sure <video> element is in the shadow DOM.
+shadowElement = internals.shadowRoot(embed).firstChild
+PASS shadowElement.tagName is "VIDEO"
+PASS internals.shadowPseudoId(shadowElement) is "-webkit-plugin-replacement"
+
+** Test for the presence of overridden methods.
+PASS embed.SetURL is a function.
+PASS embed.GetURL is a function.
+PASS embed.Play is a function.
+PASS embed.Stop is a function.
+PASS embed.GetRate is a function.
+PASS embed.SetRate is a function.
+PASS embed.IsFullScreen is a function.
+PASS embed.ExitFullScreen is a function.
+PASS embed.GetPluginStatus is a function.
+PASS embed.GetTime is a function.
+PASS embed.SetTime is a function.
+PASS embed.SeekToDate is a function.
+PASS embed.GetDate is a function.
+PASS embed.GetDuration is a function.
+PASS embed.GetTimeScale is a function.
+PASS embed.GetMaxTimeLoaded is a function.
+PASS embed.GetMaxBytesLoaded is a function.
+PASS embed.GetMovieSize is a function.
+PASS embed.GetTimedMetadataUpdates is a function.
+PASS embed.GetAccessLog is a function.
+PASS embed.GetErrorLog is a function.
+
+** Test overridden methods.
+PASS embed.GetURL().indexOf('resources/orange.mov') != -1 is true
+PASS embed.GetDuration() is 300000
+PASS embed.GetMovieSize() is 24962
+PASS embed.GetMaxTimeLoaded() is 300000
+PASS embed.GetMaxBytesLoaded() is 24962
+PASS embed.GetMovieSize() is 24962
+PASS embed.GetPluginStatus() is "Playable"
+PASS new Date(embed.GetDate()) - new Date() is within 100 of 0
+embed.SetTime(embed.GetTimeScale() * 2)
+
+PASS embed.GetTime() is 60000
+embed.Play()
+
+EVENT(qt_play)
+PASS embed.GetRate() is 1
+embed.Stop()
+
+EVENT(qt_pause)
+PASS embed.GetRate() is 0
+
+embed.SetURL('')
+EVENT(qt_begin)
+EVENT(qt_error)
+PASS embed.GetURL() is ""
+PASS embed.GetPluginStatus() is "Error"
+
+END TEST.
+
diff --git a/LayoutTests/plugins/quicktime-plugin-replacement.html b/LayoutTests/plugins/quicktime-plugin-replacement.html
new file mode 100644 (file)
index 0000000..9031178
--- /dev/null
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="../resources/js-test-pre.js"></script>
+        <script>
+            var embed;
+            var src = "resources/orange.mov";
+
+            function logEvent(event)
+            {
+                debug("<i>EVENT(" + event.type + ")</i>");
+            }
+            
+            function seeked()
+            {
+                debug("");
+                shouldEvaluateTo("embed.GetTime()", embed.GetTimeScale() * 2);
+                evalAndLog("embed.Play()");
+            }
+
+            function playing(event)
+            {
+                debug("");
+                logEvent(event);
+                shouldEvaluateTo("embed.GetRate()", 1);
+                evalAndLog("embed.Stop()");
+            }
+            
+            function paused(event)
+            {
+                debug("");
+                logEvent(event)
+                shouldEvaluateTo("embed.GetRate()", 0);
+
+                debug("");
+                evalAndLog("embed.SetURL('')");
+            }
+            
+            function error(event)
+            {
+                logEvent(event)
+                shouldBeEqualToString("embed.GetURL()", "");
+                shouldBeEqualToString("embed.GetPluginStatus()", "Error");
+                debug("<br>END TEST.");
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }
+            
+            function test(event)
+            {
+                logEvent(event)
+
+                if (window.internals) {
+                    debug("<br>** Test to make sure &lt;video&gt; element is in the shadow DOM.");
+                    evalAndLog("shadowElement = internals.shadowRoot(embed).firstChild");
+                    shouldBeEqualToString("shadowElement.tagName", "VIDEO");
+                    shouldBeEqualToString("internals.shadowPseudoId(shadowElement)", "-webkit-plugin-replacement");
+                } else {
+                    debug("");
+                    testFailed("This test must be run in DRT.");
+                    debug("");
+                }
+
+                debug("<br>** Test for the presence of overridden methods.");
+                var methods = [ "SetURL", "GetURL", "Play", "Stop", "GetRate", "SetRate", "IsFullScreen", 
+                                "ExitFullScreen", "GetPluginStatus", "GetTime", "SetTime", "SeekToDate", "GetDate", 
+                                "GetDuration", "GetTimeScale", "GetMaxTimeLoaded", "GetMaxBytesLoaded", 
+                                "GetMovieSize", "GetTimedMetadataUpdates", "GetAccessLog", "GetErrorLog"
+                              ];
+                for (i = 0; i < methods.length; ++i) {
+                    var type = typeof embed[methods[i]];
+                    if (type == "function")
+                        testPassed("embed." + methods[i] + " is a function.");
+                    else
+                        testFailed("embed." + methods[i] + " should be a function but is \"" + type + "\".");
+                }
+
+                debug("<br>** Test overridden methods.");
+                shouldBeTrue("embed.GetURL().indexOf('" + src + "') != -1");
+                shouldEvaluateTo("embed.GetDuration()", 300000);
+                shouldEvaluateTo("embed.GetMovieSize()", 24962);
+                shouldEvaluateTo("embed.GetMaxTimeLoaded()", 300000);
+                shouldEvaluateTo("embed.GetMaxBytesLoaded()", 24962);
+                shouldEvaluateTo("embed.GetMovieSize()", 24962);
+                shouldBeEqualToString("embed.GetPluginStatus()", "Playable");
+                
+                // "GetDate()" should return the current date, clear seconds and milliseconds 
+                var now = new Date();
+                shouldBeCloseTo("new Date(embed.GetDate()) - new Date()", 0, 100);
+
+                evalAndLog("embed.SetTime(embed.GetTimeScale() * 2)");
+                setTimeout(seeked, 500);
+            }
+            
+            function setup()
+            {
+                if (window.testRunner) {
+                    window.testRunner.waitUntilDone();
+                    window.testRunner.dumpAsText()
+                    window.internals.settings.setPluginReplacementEnabled(true);
+                }
+                div = document.getElementById("parent");
+                div.innerHTML = '<embed src="' + src + '" width="640" height="480" postdomevents=true>';
+                
+                var events = [ "qt_begin", "qt_validated", "qt_enterfullscreen", "qt_exitfullscreen", 
+                                "qt_loadedmetada", "qt_canplay", "qt_ended", "qt_timedmetadataupdated" 
+                              ];
+                embed = div.firstChild;
+                for (i = 0; i < events.length; ++i)
+                    embed.addEventListener(events[i], logEvent, true);
+                embed.addEventListener("qt_canplaythrough", test, true);
+                embed.addEventListener("qt_play", playing, true);
+                embed.addEventListener("qt_pause", paused, true);
+                embed.addEventListener("qt_error", error, true);
+            }
+        </script>
+    </head>
+
+    <body onload="setup()">
+        <div id=parent></div>
+        <p>
+        <div id=console></div>
+    </body>
+</html>
index a17e81b..f771fa2 100644 (file)
Binary files a/LayoutTests/plugins/resources/orange.mov and b/LayoutTests/plugins/resources/orange.mov differ
index f3a01a8..9244d99 100644 (file)
@@ -11,6 +11,7 @@ set(WebCore_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/Modules/navigatorcontentutils"
     "${WEBCORE_DIR}/Modules/networkinfo"
     "${WEBCORE_DIR}/Modules/notifications"
+    "${WEBCORE_DIR}/Modules/plugins"
     "${WEBCORE_DIR}/Modules/proximity"
     "${WEBCORE_DIR}/Modules/quota"
     "${WEBCORE_DIR}/Modules/vibration"
index 28efe83..6837266 100644 (file)
@@ -1,3 +1,109 @@
+2013-11-27  Eric Carlson  <eric.carlson@apple.com>
+
+        Allow the QuickTime plug-in to be replaced by script in an isolated word
+        https://bugs.webkit.org/show_bug.cgi?id=124900
+
+        Reviewed by Dean Jackson.
+
+        Test: plugins/quicktime-plugin-replacement.html
+
+        * CMakeLists.txt: Add new Modules path.
+        * DerivedSources.make: Add new files.
+        * GNUmakefile.am: Add new Modules path.
+        * GNUmakefile.list.am: Add new header.
+        * WebCore.vcxproj/WebCore.vcxproj: Add new header.
+        * WebCore.vcxproj/WebCoreCommon.props: Add new Modules path.
+        * WebCore.xcodeproj/project.pbxproj: Add new files.
+
+        * Modules/plugins: Added.
+        * Modules/plugins/PluginReplacement.h: Added. Defines the interface for a plug-in replacement.
+
+        Create a replacement for the QuickTime plug-in.
+        * Modules/plugins/QuickTimePluginReplacement.cpp: Added.
+        * Modules/plugins/QuickTimePluginReplacement.css: Added.
+        * Modules/plugins/QuickTimePluginReplacement.h: Added.
+        * Modules/plugins/QuickTimePluginReplacement.idl: Added.
+        * Modules/plugins/QuickTimePluginReplacement.js: Added.
+
+        Allow plug-in replacement to be enabled at runtime.
+        * bindings/generic/RuntimeEnabledFeatures.h:
+        (WebCore::RuntimeEnabledFeatures::setPluginReplacementEnabled):
+        (WebCore::RuntimeEnabledFeatures::pluginReplacementEnabled):
+
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::toJS): Add toJS(... const String& ...).
+
+        * bindings/js/JSPluginElementFunctions.cpp:
+        (WebCore::pluginScriptObject): Give a plug-in replacement a first shot at defining the
+            script interface.
+
+        * html/HTMLEmbedElement.cpp:
+        (WebCore::HTMLEmbedElement::updateWidget): Call base class requestObject.
+
+        * html/HTMLMediaElement.cpp:
+        (HTMLMediaElement::fileSize): New, passthrough to media engine.
+        * html/HTMLMediaElement.h:
+
+        * html/HTMLObjectElement.cpp:
+        (WebCore::HTMLObjectElement::updateWidget): Call base class requestObject.
+
+        Moved some logic that was previously used only for creating a plug-in snapshot to the base
+        class so it can be shared by a plug-in replacement.
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::HTMLPlugInElement::HTMLPlugInElement): Initialize timer used to swap renderers.
+        (WebCore::HTMLPlugInElement::createRenderer): Allow plug-in replacement to create the renderer.
+        (WebCore::HTMLPlugInElement::swapRendererTimerFired): Create a shadow root.
+        (WebCore::HTMLPlugInElement::setDisplayState): Set the new state, prime the swap renderer 
+            timer if necessary.
+        (WebCore::HTMLPlugInElement::didAddUserAgentShadowRoot): Tell the plug-in replacement to
+            install itself in the new shadow DOM.
+        (WebCore::registeredPluginReplacements): Return vector of all registered plug-in replacements.
+        (WebCore::registerPluginReplacement): Add a plug-in replacement.
+        (WebCore::pluginReplacementForType): Find a plug-in replacement for a MIME type.
+        (WebCore::HTMLPlugInElement::requestObject): If there is a plug-in replacement for the MIME type,
+            create it and set the display state.
+        (WebCore::HTMLPlugInElement::scriptObjectForPluginReplacement): Return the script object for 
+            the current plug-in replacement, if any.
+        * html/HTMLPlugInElement.h:
+
+        Move some plug-in snapshot code into the base class.
+        * html/HTMLPlugInImageElement.cpp:
+        (WebCore::HTMLPlugInImageElement::HTMLPlugInImageElement): No need to initialize timer.
+        (WebCore::HTMLPlugInImageElement::setDisplayState): Call base class.
+        (WebCore::HTMLPlugInImageElement::createRenderer): Ditto.
+        (WebCore::HTMLPlugInImageElement::didAddUserAgentShadowRoot): Ditto.
+        (WebCore::HTMLPlugInImageElement::userDidClickSnapshot): Remove unnecessary class name.
+        (WebCore::HTMLPlugInImageElement::requestObject): New.
+        * html/HTMLPlugInImageElement.h:
+
+        * html/HTMLVideoElement.h: Make createRenderer public so the QuickTime plug-in replacement can
+            call it.
+
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::fileSize): New.
+        * platform/graphics/MediaPlayer.h:
+        * platform/graphics/MediaPlayerPrivate.h:
+
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
+        (WebCore::MediaPlayerPrivateAVFoundation::extraMemoryCost): totalBytes returns an unsigned long long.
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h:
+        (WebCore::MediaPlayerPrivateAVFoundation::fileSize):
+
+        * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp:
+        (WebCore::MediaPlayerPrivateAVFoundationCF::totalBytes): Return an unsigned long long.
+        * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.h:
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::totalBytes): Ditto.
+
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::Backup::Backup): Backup the plug-in replacement runtime setting.
+        (WebCore::InternalSettings::Backup::restoreTo): Restore it.
+        (WebCore::InternalSettings::setPluginReplacementEnabled): Set it.
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+
 2013-11-27  Thiago de Barros Lacerda  <thiago.lacerda@openbossa.org>
 
         Adding MediaConstraintsMock class
index c280a65..35c0f28 100644 (file)
@@ -36,6 +36,7 @@ VPATH = \
     $(WebCore)/Modules/mediasource \
     $(WebCore)/Modules/mediastream \
     $(WebCore)/Modules/notifications \
+    $(WebCore)/Modules/plugins \
     $(WebCore)/Modules/quota \
     $(WebCore)/Modules/speech \
     $(WebCore)/Modules/webaudio \
@@ -141,6 +142,7 @@ BINDING_IDLS = \
     $(WebCore)/Modules/notifications/NotificationCenter.idl \
     $(WebCore)/Modules/notifications/NotificationPermissionCallback.idl \
     $(WebCore)/Modules/notifications/WorkerGlobalScopeNotifications.idl \
+    $(WebCore)/Modules/plugins/QuickTimePluginReplacement.idl \
     $(WebCore)/Modules/quota/DOMWindowQuota.idl \
     $(WebCore)/Modules/quota/NavigatorStorageQuota.idl \
     $(WebCore)/Modules/quota/StorageInfo.idl \
@@ -870,6 +872,10 @@ ifeq ($(findstring ENABLE_MEDIA_CONTROLS_SCRIPT,$(FEATURE_DEFINES)), ENABLE_MEDI
        USER_AGENT_STYLE_SHEETS := $(USER_AGENT_STYLE_SHEETS) $(WebCore)/Modules/mediacontrols/mediaControlsApple.css
 endif
 
+ifeq ($(OS),MACOS)
+       USER_AGENT_STYLE_SHEETS := $(USER_AGENT_STYLE_SHEETS) $(WebCore)/Modules/plugins/QuickTimePluginReplacement.css
+endif
+
 UserAgentStyleSheets.h : css/make-css-file-arrays.pl bindings/scripts/preprocessor.pm $(USER_AGENT_STYLE_SHEETS) $(PLATFORM_FEATURE_DEFINES)
        perl -I$(WebCore)/bindings/scripts $< --defines "$(FEATURE_DEFINES)" $@ UserAgentStyleSheetsData.cpp $(USER_AGENT_STYLE_SHEETS)
 
@@ -883,6 +889,9 @@ ifeq ($(findstring ENABLE_MEDIA_CONTROLS_SCRIPT,$(FEATURE_DEFINES)), ENABLE_MEDI
        USER_AGENT_SCRIPTS := $(USER_AGENT_SCRIPTS) $(WebCore)/Modules/mediacontrols/mediaControlsApple.js
 endif
 
+ifeq ($(OS),MACOS)
+       USER_AGENT_SCRIPTS := $(USER_AGENT_SCRIPTS) $(WebCore)/Modules/plugins/QuickTimePluginReplacement.js
+endif
 
 UserAgentScripts.h : css/make-css-file-arrays.pl bindings/scripts/preprocessor.pm $(USER_AGENT_SCRIPTS) $(PLATFORM_FEATURE_DEFINES)
        perl -I$(WebCore)/bindings/scripts $< --defines "$(FEATURE_DEFINES)" $@ UserAgentScriptsData.cpp $(USER_AGENT_SCRIPTS)
index a5971d9..21a08fc 100644 (file)
@@ -19,6 +19,7 @@ webcore_cppflags += \
        -I$(srcdir)/Source/WebCore/Modules/mediastream \
        -I$(srcdir)/Source/WebCore/Modules/navigatorcontentutils \
        -I$(srcdir)/Source/WebCore/Modules/notifications \
+       -I$(srcdir)/Source/WebCore/Modules/plugins \
        -I$(srcdir)/Source/WebCore/Modules/proximity \
        -I$(srcdir)/Source/WebCore/Modules/quota \
        -I$(srcdir)/Source/WebCore/Modules/webaudio \
index 826adb5..676ab56 100644 (file)
@@ -1977,6 +1977,7 @@ webcore_modules_sources += \
        Source/WebCore/Modules/notifications/NotificationPermissionCallback.h \
        Source/WebCore/Modules/notifications/WorkerGlobalScopeNotifications.cpp \
        Source/WebCore/Modules/notifications/WorkerGlobalScopeNotifications.h \
+       Source/WebCore/Modules/plugins/PluginReplacement.h \
        Source/WebCore/Modules/proximity/DeviceProximityClient.h \
        Source/WebCore/Modules/proximity/DeviceProximityController.cpp \
        Source/WebCore/Modules/proximity/DeviceProximityController.h \
diff --git a/Source/WebCore/Modules/plugins/PluginReplacement.h b/Source/WebCore/Modules/plugins/PluginReplacement.h
new file mode 100644 (file)
index 0000000..897b1a6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#ifndef PluginReplacement_h
+#define PluginReplacement_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+class JSObject;
+}
+
+namespace WebCore {
+
+class HTMLPlugInElement;
+class RenderElement;
+class RenderStyle;
+class ShadowRoot;
+
+class PluginReplacement : public RefCounted<PluginReplacement> {
+public:
+    virtual ~PluginReplacement() { }
+
+    virtual bool installReplacement(ShadowRoot*) = 0;
+    virtual JSC::JSObject* scriptObject() { return 0; }
+
+    virtual bool willCreateRenderer() { return false; }
+    virtual RenderElement* createRenderer(HTMLPlugInElement&, PassRef<RenderStyle>) = 0;
+
+protected:
+    PluginReplacement() { }
+};
+
+typedef PassRefPtr<PluginReplacement> (*CreatePluginReplacement)(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+typedef bool (*PluginReplacementSupportsType)(const String&);
+typedef bool (*PluginReplacementSupportsFileExtension)(const String&);
+
+class ReplacementPlugin {
+public:
+    ReplacementPlugin(CreatePluginReplacement constructor, PluginReplacementSupportsType supportsType, PluginReplacementSupportsFileExtension supportsFileExtension)
+        : m_constructor(constructor)
+        , m_supportsType(supportsType)
+        , m_supportsFileExtension(supportsFileExtension)
+    {
+    }
+
+    explicit ReplacementPlugin(const ReplacementPlugin& other)
+        : m_constructor(other.m_constructor)
+        , m_supportsType(other.m_supportsType)
+        , m_supportsFileExtension(other.m_supportsFileExtension)
+    {
+    }
+
+    PassRefPtr<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); }
+
+private:
+    CreatePluginReplacement m_constructor;
+    PluginReplacementSupportsType m_supportsType;
+    PluginReplacementSupportsFileExtension m_supportsFileExtension;
+};
+
+typedef void (*PluginReplacementRegistrar)(const ReplacementPlugin&);
+
+}
+
+#endif
diff --git a/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp b/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp
new file mode 100644 (file)
index 0000000..82b86e9
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, 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"
+
+#if ENABLE(MEDIA_CONTROLS_SCRIPT)
+
+#include "QuickTimePluginReplacement.h"
+
+#include "Event.h"
+#include "HTMLPlugInElement.h"
+#include "HTMLVideoElement.h"
+#include "JSDOMBinding.h"
+#include "JSDOMGlobalObject.h"
+#include "JSHTMLVideoElement.h"
+#include "JSQuickTimePluginReplacement.h"
+#include "Logging.h"
+#include "MainFrame.h"
+#include "Page.h"
+#include "RenderElement.h"
+#include "ScriptController.h"
+#include "ScriptObject.h"
+#include "ScriptSourceCode.h"
+#include "UserAgentScripts.h"
+#include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/JSBase.h>
+#include <JavaScriptCore/JSCJSValueInlines.h>
+
+using namespace JSC;
+
+namespace WebCore {
+
+static String quickTimePluginReplacementScript()
+{
+    DEFINE_STATIC_LOCAL(String, script, (QuickTimePluginReplacementJavaScript, sizeof(QuickTimePluginReplacementJavaScript)));
+    return script;
+}
+
+void QuickTimePluginReplacement::registerPluginReplacement(PluginReplacementRegistrar registrar)
+{
+    registrar(ReplacementPlugin(create, supportsMimeType, supportsFileExtension));
+}
+
+PassRefPtr<PluginReplacement> QuickTimePluginReplacement::create(HTMLPlugInElement& plugin, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+    return adoptRef(new QuickTimePluginReplacement(plugin, paramNames, paramValues));
+}
+
+bool QuickTimePluginReplacement::supportsMimeType(const String& mimeType)
+{
+    static const char* types[] = {
+        "application/vnd.apple.mpegurl", "application/x-mpegurl", "audio/3gpp", "audio/3gpp2", "audio/aac", "audio/aiff",
+        "audio/amr", "audio/basic", "audio/mp3", "audio/mp4", "audio/mpeg", "audio/mpeg3", "audio/mpegurl", "audio/scpls",
+        "audio/wav", "audio/x-aac", "audio/x-aiff", "audio/x-caf", "audio/x-m4a", "audio/x-m4b", "audio/x-m4p",
+        "audio/x-m4r", "audio/x-mp3", "audio/x-mpeg", "audio/x-mpeg3", "audio/x-mpegurl", "audio/x-scpls", "audio/x-wav",
+        "video/3gpp", "video/3gpp2", "video/mp4", "video/quicktime", "video/x-m4v"
+    };
+    DEFINE_STATIC_LOCAL(HashSet<String>, typeHash, ());
+    if (!typeHash.size()) {
+        for (size_t i = 0; i < WTF_ARRAY_LENGTH(types); ++i)
+            typeHash.add(types[i]);
+    }
+
+    return typeHash.contains(mimeType);
+}
+
+bool QuickTimePluginReplacement::supportsFileExtension(const String& extension)
+{
+    static const char* extensions[] = {
+        "3g2", "3gp", "3gp2", "3gpp", "aac", "adts", "aif", "aifc", "aiff", "AMR", "au", "bwf", "caf", "cdda", "m3u",
+        "m3u8", "m4a", "m4b", "m4p", "m4r", "m4v", "mov", "mp3", "mp3", "mp4", "mpeg", "mpg", "mqv", "pls", "qt",
+        "snd", "swa", "ts", "ulw", "wav"
+    };
+    DEFINE_STATIC_LOCAL(HashSet<String>, extensionHash, ());
+    if (!extensionHash.size()) {
+        for (size_t i = 0; i < WTF_ARRAY_LENGTH(extensions); ++i)
+            extensionHash.add(extensions[i]);
+    }
+
+    return extensionHash.contains(extension);
+}
+
+QuickTimePluginReplacement::QuickTimePluginReplacement(HTMLPlugInElement& plugin, const Vector<String>& paramNames, const Vector<String>& paramValues)
+    :PluginReplacement()
+    , m_parentElement(&plugin)
+    , m_names(paramNames)
+    , m_values(paramValues)
+    , m_scriptObject(nullptr)
+{
+}
+
+QuickTimePluginReplacement::~QuickTimePluginReplacement()
+{
+    m_parentElement = nullptr;
+    m_scriptObject = nullptr;
+    m_mediaElement = nullptr;
+}
+
+RenderElement* QuickTimePluginReplacement::createRenderer(HTMLPlugInElement& plugin, PassRef<RenderStyle> style)
+{
+    ASSERT_UNUSED(plugin, m_parentElement == &plugin);
+
+    if (m_mediaElement)
+        return m_mediaElement->createRenderer(std::move(style));
+
+    return 0;
+}
+
+DOMWrapperWorld& QuickTimePluginReplacement::isolatedWorld()
+{
+    static DOMWrapperWorld& isolatedWorld = *DOMWrapperWorld::create(JSDOMWindow::commonVM()).leakRef();
+    return isolatedWorld;
+}
+
+bool QuickTimePluginReplacement::ensureReplacementScriptInjected()
+{
+    Page* page = m_parentElement->document().page();
+    if (!page)
+        return false;
+    
+    DOMWrapperWorld& world = isolatedWorld();
+    ScriptController& scriptController = page->mainFrame().script();
+    JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(scriptController.globalObject(world));
+    ExecState* exec = globalObject->globalExec();
+    
+    JSValue replacementFunction = globalObject->get(exec, Identifier(exec, "createPluginReplacement"));
+    if (replacementFunction.isFunction())
+        return true;
+    
+    scriptController.evaluateInWorld(ScriptSourceCode(quickTimePluginReplacementScript()), world);
+    if (exec->hadException()) {
+        LOG(Plugins, "%p - Exception when evaluating QuickTime plugin replacement script", this);
+        exec->clearException();
+        return false;
+    }
+    
+    return true;
+}
+
+bool QuickTimePluginReplacement::installReplacement(ShadowRoot* root)
+{
+    Page* page = m_parentElement->document().page();
+
+    if (!ensureReplacementScriptInjected())
+        return false;
+
+    DOMWrapperWorld& world = isolatedWorld();
+    ScriptController& scriptController = page->mainFrame().script();
+    JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(scriptController.globalObject(world));
+    ExecState* exec = globalObject->globalExec();
+    JSLockHolder lock(exec);
+    
+    // Lookup the "createPluginReplacement" function.
+    JSValue replacementFunction = globalObject->get(exec, Identifier(exec, "createPluginReplacement"));
+    if (replacementFunction.isUndefinedOrNull())
+        return false;
+    JSObject* replacementObject = replacementFunction.toObject(exec);
+    CallData callData;
+    CallType callType = replacementObject->methodTable()->getCallData(replacementObject, callData);
+    if (callType == CallTypeNone)
+        return false;
+
+    MarkedArgumentBuffer argList;
+    argList.append(toJS(exec, globalObject, root));
+    argList.append(toJS(exec, globalObject, m_parentElement));
+    argList.append(toJS(exec, globalObject, this));
+    argList.append(toJS<String>(exec, globalObject, m_names));
+    argList.append(toJS<String>(exec, globalObject, m_values));
+    JSValue replacement = call(exec, replacementObject, callType, callData, globalObject, argList);
+    if (exec->hadException()) {
+        exec->clearException();
+        return false;
+    }
+
+    // Get the <video> created to replace the plug-in.
+    JSValue value = replacement.get(exec, Identifier(exec, "video"));
+    if (!exec->hadException() && !value.isUndefinedOrNull())
+        m_mediaElement = toHTMLVideoElement(value);
+
+    if (!m_mediaElement) {
+        LOG(Plugins, "%p - Failed to find <video> element created by QuickTime plugin replacement script.", this);
+        exec->clearException();
+        return false;
+    }
+
+    // Get the scripting interface.
+    value = replacement.get(exec, Identifier(exec, "scriptObject"));
+    if (!exec->hadException() && !value.isUndefinedOrNull())
+        m_scriptObject = value.toObject(exec);
+
+    if (!m_scriptObject) {
+        LOG(Plugins, "%p - Failed to find script object created by QuickTime plugin replacement.", this);
+        exec->clearException();
+        return false;
+    }
+
+    return true;
+}
+
+unsigned long long QuickTimePluginReplacement::movieSize() const
+{
+    if (m_mediaElement)
+        return m_mediaElement->fileSize();
+
+    return 0;
+}
+
+void QuickTimePluginReplacement::postEvent(const String& eventName)
+{
+    Ref<HTMLPlugInElement> protect(*m_parentElement);
+    RefPtr<Event> event = Event::create(eventName, false, true);
+    m_parentElement->dispatchEvent(event.get());
+}
+
+}
+#endif
diff --git a/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.css b/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.css
new file mode 100644 (file)
index 0000000..2a343a9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * 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. 
+ */
+
+embed::-webkit-plugin-replacement,
+object::-webkit-plugin-replacement
+{
+    position: relative;
+    display: inline-block;
+    width: 100%;
+    height: 100%;
+}
+
diff --git a/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h b/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h
new file mode 100644 (file)
index 0000000..daae7b1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+#ifndef QuickTimePluginReplacement_h
+#define QuickTimePluginReplacement_h
+
+#include "PluginReplacement.h"
+#include "ScriptState.h"
+#include "ScriptValue.h"
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class HTMLPlugInElement;
+class HTMLVideoElement;
+class RenderElement;
+class RenderStyle;
+class ShadowRoot;
+
+class QuickTimePluginReplacement : public PluginReplacement {
+public:
+    static void registerPluginReplacement(PluginReplacementRegistrar);
+    static bool supportsMimeType(const String&);
+    static bool supportsFileExtension(const String&);
+    
+    static PassRefPtr<PluginReplacement> create(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+    ~QuickTimePluginReplacement();
+
+    virtual bool installReplacement(ShadowRoot*) OVERRIDE;
+    virtual JSC::JSObject* scriptObject() OVERRIDE { return m_scriptObject; }
+
+    virtual bool willCreateRenderer() OVERRIDE { return m_mediaElement; }
+    virtual RenderElement* createRenderer(HTMLPlugInElement&, PassRef<RenderStyle>) OVERRIDE;
+
+    unsigned long long movieSize() const;
+    void postEvent(const String&);
+
+private:
+    QuickTimePluginReplacement(HTMLPlugInElement&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+
+    bool ensureReplacementScriptInjected();
+    DOMWrapperWorld& isolatedWorld();
+
+    HTMLPlugInElement* m_parentElement;
+    RefPtr<HTMLVideoElement> m_mediaElement;
+    const Vector<String> m_names;
+    const Vector<String> m_values;
+    JSC::JSObject* m_scriptObject;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl b/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl
new file mode 100644 (file)
index 0000000..7d22cf9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 COMPUTER, 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 COMPUTER, 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. 
+ */
+
+[
+    NoInterfaceObject,
+    OperationsNotDeletable,
+    JSGenerateToJSObject,
+] interface QuickTimePluginReplacement {
+    readonly attribute unsigned long long movieSize;
+    void postEvent(DOMString eventName);
+};
diff --git a/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js b/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js
new file mode 100644 (file)
index 0000000..59c4397
--- /dev/null
@@ -0,0 +1,328 @@
+
+function createPluginReplacement(root, parent, host, attributeNames, attributeValues)
+{
+    return new Replacement(root, parent, host, attributeNames, attributeValues);
+};
+
+function Replacement(root, parent, host, attributeNames, attributeValues)
+{
+    this.root = root;
+    this.parent = parent;
+    this.host = host;
+    this.listeners = {};
+    this.scriptObject = {};
+
+    this.autoExitFullScreen = true;
+    this.postEvents = false;
+    this.height = 0;
+    this.width = 0;
+    this.src = '';
+    this.autohref = false;
+    this.href = '';
+    this.qtsrc = '';
+    this.target = '';
+
+    this.createVideoElement(attributeNames, attributeValues);
+    this.createScriptInterface();
+};
+
+Replacement.prototype = {
+
+    HandledVideoEvents: {
+        loadstart: 'handleLoadStart',
+        error: 'handleError',
+        loadedmetadata: 'handleLoadedMetaData',
+        canplay: 'qt_canplay',
+        canplaythrough: 'qt_canplaythrough',
+        play: 'qt_play',
+        pause: 'qt_pause',
+        ended: 'handleEnded',
+        webkitfullscreenchange: 'handleFullscreenChange',
+    },
+
+    AttributeMap: {
+        autoexitfullscreen: 'autoExitFullScreen',
+        postdomevents: 'postEvents',
+        height: 'height',
+        width: 'width',
+        src: 'src',
+        airplay: 'x-webkit-airplay=',
+        href: 'href',
+        target: 'target',
+    },
+    
+    MethodMap: {
+        SetURL : 'setURL',
+        GetURL : 'url',
+        Play : 'play',
+        Stop : 'pause',
+        GetRate : 'rate',
+        SetRate : 'setRate',
+        IsFullScreen : 'isFullScreen',
+        ExitFullScreen : 'exitFullScreen',
+        GetPluginStatus : 'pluginStatus',
+        GetTime : 'currentTime',
+        SetTime : 'setCurrentTime',
+        SeekToDate : 'seekToDate',
+        GetDate : 'date',
+        GetDuration : 'duration',
+        GetTimeScale : 'timeScale',
+        GetMaxTimeLoaded : 'maxTimeLoaded',
+        GetMaxBytesLoaded : 'maxBytesLoaded',
+        GetMovieSize : 'movieSize',
+        GetTimedMetadataUpdates : 'timedMetadataUpdates',
+        GetAccessLog : 'accessLog',
+        GetErrorLog : 'errorLog',
+    },
+
+    TimeScale: 30000,
+
+    createVideoElement: function(attributeNames, attributeValues)
+    {
+        var video = this.video = document.createElement('video');
+
+        for (name in this.HandledVideoEvents)
+            video.addEventListener(name, this, false);
+        
+        for (i = 0; i < attributeNames.length; i++) {
+            var property = this.AttributeMap[attributeNames[i]];
+            if (this[property] != undefined)
+                this[property] = attributeValues[i];
+        }
+
+        video.setAttribute('pseudo', '-webkit-plugin-replacement');
+        video.setAttribute('controls', 'controls');
+        this.setStatus('Waiting');
+
+        var src = this.src;
+        if (this.href && this.target) {
+            src = this.resolveRelativeToUrl(this.href, this.src);
+            video.poster = this.src;
+            video.setAttribute('preload', 'none');
+        }
+        
+        if (src.length)
+            this.setURL(src);
+
+        this.root.appendChild(video);
+    },
+
+    resolveRelativeToUrl: function(url, baseUrl)
+    {
+        if (url.indexOf('://') != -1)
+            return url;
+        if (baseUrl.indexOf('://') == -1)
+            baseUrl = this.resolveRelativeToUrl(baseUrl, document.baseURI);
+
+        var base = document.createElement('base');
+        base.href = baseUrl;
+        document.head.appendChild(base);
+
+        var resolver = document.createElement('a');
+        resolver.href = url;
+        url = resolver.href;
+
+        document.head.removeChild(base);
+        base = null;
+
+        return url;
+    },
+    createScriptInterface: function()
+    {
+        for (name in this.MethodMap) {
+            var methodName = this.MethodMap[name];
+            this.scriptObject[name] = this[methodName].bind(this);
+        }
+    },
+
+    handleEvent: function(event)
+    {
+        if (event.target !== this.video)
+            return;
+
+        try {
+            var eventData = this.HandledVideoEvents[event.type];
+            if (!eventData)
+                return;
+
+            if (this[eventData] && this[eventData] instanceof Function)
+                this[eventData].call(this, event);
+            else
+                this.postEvent(eventData);
+        } catch(e) {
+            if (window.console)
+                console.error(e);
+        }
+    },
+
+    postEvent: function(eventName)
+    {
+        try {
+            if (this.postEvents)
+                this.host.postEvent(eventName);
+        } catch(e) { }
+    },
+
+    setStatus: function(status)
+    {
+        this.status = status;
+    },
+
+    handleLoadedMetaData: function(event)
+    {
+        this.setStatus('Playable');
+        this.postEvent('qt_validated');
+        this.postEvent('qt_loadedfirstframe');
+        this.postEvent('qt_loadedmetadata');
+    },
+
+    handleFullscreenChange: function(event)
+    {
+        this.postEvent(this.isFullScreen() ? 'qt_enterfullscreen' : 'qt_exitfullscreen');
+    },
+
+    handleError: function(event)
+    {
+        this.setStatus('Error');
+        this.postEvent('qt_error');
+    },
+
+    handleLoadStart:function(event)
+    {
+        if (this.video.poster)
+            this.setStatus('Waiting');
+        else
+            this.setStatus('Loading');
+        this.postEvent('qt_begin');
+    },
+
+    handleEnded: function(event)
+    {
+        this.postEvent('qt_ended');
+        if (this.isFullScreen() && this.autoExitFullScreen)
+            document.webkitExitFullscreen();
+    },
+
+    isFullScreen: function()
+    {
+        return document.webkitCurrentFullScreenElement === this.video;
+    },
+
+    setURL: function(url)
+    {
+        this.setStatus('Validating');
+        this.video.src = url;
+    },
+    
+    url: function()
+    {
+        return this.video.currentSrc;
+    },
+    
+    play: function()
+    {
+        this.video.play();
+    },
+    
+    pause: function()
+    {
+        this.video.playbackRate = 0;
+        this.video.pause();
+    },
+    
+    rate: function()
+    {
+        return this.video.paused ? 0 : 1;
+    },
+    
+    setRate: function(rate)
+    {
+        if (rate)
+            this.video.play();
+        else
+            this.video.pause();
+    },
+    
+    exitFullScreen: function()
+    {
+        document.webkitExitFullscreen();
+    },
+    
+    pluginStatus: function()
+    {
+        return this.status;
+    },
+
+    currentTime: function()
+    {
+        return this.video.currentTime * this.TimeScale;
+    },
+
+    setCurrentTime: function(time)
+    {
+        this.video.currentTime = time / this.TimeScale;
+    },
+
+    seekToDate: function()
+    {
+        // FIXME: not implemented yet.
+    },
+    
+    date: function()
+    {
+        return new Date();
+    },
+    
+    duration: function()
+    {
+        return this.video.duration * this.TimeScale;
+    },
+    
+    timeScale: function()
+    {
+        // Note: QuickTime movies and MPEG-4 files have a timescale, but it is not exposed by all media engines.
+        // 30000 works well with common frame rates, eg. 29.97 NTSC can be represented accurately as a time
+        // scale of 30000 and frame duration of 1001.
+        return 30000;
+    },
+    
+    maxTimeLoaded: function()
+    {
+        return this.video.duration * this.TimeScale;
+    },
+    
+    maxBytesLoaded: function()
+    {
+        var percentLoaded = this.video.buffered.end(0) / this.video.duration;
+        return percentLoaded * this.movieSize();
+    },
+    
+    movieSize: function()
+    {
+        try {
+            return this.host.movieSize;
+        } catch(e) { }
+
+        return 0;
+    },
+    
+    timedMetadataUpdates: function()
+    {
+        // FIXME: not implemented yet.
+        return null;
+    },
+    
+    accessLog: function()
+    {
+        // FIXME: not implemented yet.
+        return null;
+    },
+    
+    errorLog: function()
+    {
+        // FIXME: not implemented yet.
+        return null;
+    },
+};
+
index 9300b4b..f9c9ac4 100644 (file)
     <ClInclude Include="..\Modules\notifications\NotificationCenter.h" />
     <ClInclude Include="..\Modules\notifications\NotificationClient.h" />
     <ClInclude Include="..\Modules\notifications\WorkerGlobalScopeNotifications.h" />
+    <ClInclude Include="..\Modules\plugins\PluginReplacement.h" />
     <ClInclude Include="..\Modules\webdatabase\AbstractDatabaseServer.h" />
     <ClInclude Include="..\Modules\webdatabase\AbstractSQLStatement.h" />
     <ClInclude Include="..\Modules\webdatabase\AbstractSQLStatementBackend.h" />
index e34f914..67cd85d 100644 (file)
@@ -7,7 +7,7 @@
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
-      <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\Modules\mediacontrols;$(ProjectDir)..\Modules\mediastream;$(ProjectDir)..\Modules\filesystem;$(ProjectDir)..\Modules\geolocation;$(ProjectDir)..\Modules\indexeddb;$(ProjectDir)..\Modules\mediasource;$(ProjectDir)..\Modules\navigatorcontentutils;$(ProjectDir)..\Modules\speech;$(ProjectDir)..\Modules\proximity;$(ProjectDir)..\Modules\quota;$(ProjectDir)..\Modules\notifications;$(ProjectDir)..\Modules\webdatabase;$(ProjectDir)..\Modules\websockets;$(ProjectDir)..\accessibility;$(ProjectDir)..\accessibility\win;$(ProjectDir)..\bridge;$(ProjectDir)..\bridge\c;$(ProjectDir)..\bridge\jsc;$(ProjectDir)..\css;$(ProjectDir)..\editing;$(ProjectDir)..\fileapi;$(ProjectDir)..\rendering;$(ProjectDir)..\rendering\line;$(ProjectDir)..\rendering\mathml;$(ProjectDir)..\rendering\shapes;$(ProjectDir)..\rendering\style;$(ProjectDir)..\rendering\svg;$(ProjectDir)..\bindings;$(ProjectDir)..\bindings\generic;$(ProjectDir)..\bindings\js;$(ProjectDir)..\bindings\js\specialization;$(ProjectDir)..\dom;$(ProjectDir)..\dom\default;$(ProjectDir)..\history;$(ProjectDir)..\html;$(ProjectDir)..\html\canvas;$(ProjectDir)..\html\forms;$(ProjectDir)..\html\parser;$(ProjectDir)..\html\shadow;$(ProjectDir)..\html\track;$(ProjectDir)..\inspector;$(ProjectDir)..\loader;$(ProjectDir)..\loader\appcache;$(ProjectDir)..\loader\archive;$(ProjectDir)..\loader\archive\cf;$(ProjectDir)..\loader\cache;$(ProjectDir)..\loader\icon;$(ProjectDir)..\mathml;$(ProjectDir)..\page;$(ProjectDir)..\page\animation;$(ProjectDir)..\page\scrolling;$(ProjectDir)..\page\win;$(ProjectDir)..\platform;$(ProjectDir)..\platform\animation;$(ProjectDir)..\platform\mock;$(ProjectDir)..\platform\sql;$(ProjectDir)..\platform\win;$(ProjectDir)..\platform\network;$(ProjectDir)..\platform\network\win;$(ProjectDir)..\platform\cf;$(ProjectDir)..\platform\graphics;$(ProjectDir)..\platform\graphics\ca;$(ProjectDir)..\platform\graphics\cpu\arm\filters;$(ProjectDir)..\platform\graphics\filters;$(ProjectDir)..\platform\graphics\filters\arm;$(ProjectDir)..\platform\graphics\opentype;$(ProjectDir)..\platform\graphics\transforms;$(ProjectDir)..\platform\text;$(ProjectDir)..\platform\text\transcoder;$(ProjectDir)..\platform\graphics\win;$(ProjectDir)..\xml;$(ProjectDir)..\xml\parser;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources;$(ProjectDir)..\plugins;$(ProjectDir)..\plugins\win;$(ProjectDir)..\svg\animation;$(ProjectDir)..\svg\graphics;$(ProjectDir)..\svg\properties;$(ProjectDir)..\svg\graphics\filters;$(ProjectDir)..\svg;$(ProjectDir)..\testing;$(ProjectDir)..\crypto;$(ProjectDir)..\wml;$(ProjectDir)..\storage;$(ProjectDir)..\style;$(ProjectDir)..\websockets;$(ProjectDir)..\workers;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ProjectDir)..\ForwardingHeaders;$(ProjectDir)..\platform\graphics\gpu;$(ProjectDir)..\platform\graphics\egl;$(ProjectDir)..\platform\graphics\surfaces;$(ProjectDir)..\platform\graphics\surfaces\egl;$(ProjectDir)..\platform\graphics\opengl;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;$(WebKit_Libraries)\include\private\JavaScriptCore;$(WebKit_Libraries)\include\sqlite;$(WebKit_Libraries)\include\JavaScriptCore;$(WebKit_Libraries)\include\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\Modules\mediacontrols;$(ProjectDir)..\Modules\mediastream;$(ProjectDir)..\Modules\filesystem;$(ProjectDir)..\Modules\geolocation;$(ProjectDir)..\Modules\indexeddb;$(ProjectDir)..\Modules\mediasource;$(ProjectDir)..\Modules\navigatorcontentutils;$(ProjectDir)..\Modules\plugins;$(ProjectDir)..\Modules\speech;$(ProjectDir)..\Modules\proximity;$(ProjectDir)..\Modules\quota;$(ProjectDir)..\Modules\notifications;$(ProjectDir)..\Modules\webdatabase;$(ProjectDir)..\Modules\websockets;$(ProjectDir)..\accessibility;$(ProjectDir)..\accessibility\win;$(ProjectDir)..\bridge;$(ProjectDir)..\bridge\c;$(ProjectDir)..\bridge\jsc;$(ProjectDir)..\css;$(ProjectDir)..\editing;$(ProjectDir)..\fileapi;$(ProjectDir)..\rendering;$(ProjectDir)..\rendering\line;$(ProjectDir)..\rendering\mathml;$(ProjectDir)..\rendering\shapes;$(ProjectDir)..\rendering\style;$(ProjectDir)..\rendering\svg;$(ProjectDir)..\bindings;$(ProjectDir)..\bindings\generic;$(ProjectDir)..\bindings\js;$(ProjectDir)..\bindings\js\specialization;$(ProjectDir)..\dom;$(ProjectDir)..\dom\default;$(ProjectDir)..\history;$(ProjectDir)..\html;$(ProjectDir)..\html\canvas;$(ProjectDir)..\html\forms;$(ProjectDir)..\html\parser;$(ProjectDir)..\html\shadow;$(ProjectDir)..\html\track;$(ProjectDir)..\inspector;$(ProjectDir)..\loader;$(ProjectDir)..\loader\appcache;$(ProjectDir)..\loader\archive;$(ProjectDir)..\loader\archive\cf;$(ProjectDir)..\loader\cache;$(ProjectDir)..\loader\icon;$(ProjectDir)..\mathml;$(ProjectDir)..\page;$(ProjectDir)..\page\animation;$(ProjectDir)..\page\scrolling;$(ProjectDir)..\page\win;$(ProjectDir)..\platform;$(ProjectDir)..\platform\animation;$(ProjectDir)..\platform\mock;$(ProjectDir)..\platform\sql;$(ProjectDir)..\platform\win;$(ProjectDir)..\platform\network;$(ProjectDir)..\platform\network\win;$(ProjectDir)..\platform\cf;$(ProjectDir)..\platform\graphics;$(ProjectDir)..\platform\graphics\ca;$(ProjectDir)..\platform\graphics\cpu\arm\filters;$(ProjectDir)..\platform\graphics\filters;$(ProjectDir)..\platform\graphics\filters\arm;$(ProjectDir)..\platform\graphics\opentype;$(ProjectDir)..\platform\graphics\transforms;$(ProjectDir)..\platform\text;$(ProjectDir)..\platform\text\transcoder;$(ProjectDir)..\platform\graphics\win;$(ProjectDir)..\xml;$(ProjectDir)..\xml\parser;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\WebCore\DerivedSources;$(ProjectDir)..\plugins;$(ProjectDir)..\plugins\win;$(ProjectDir)..\svg\animation;$(ProjectDir)..\svg\graphics;$(ProjectDir)..\svg\properties;$(ProjectDir)..\svg\graphics\filters;$(ProjectDir)..\svg;$(ProjectDir)..\testing;$(ProjectDir)..\crypto;$(ProjectDir)..\wml;$(ProjectDir)..\storage;$(ProjectDir)..\style;$(ProjectDir)..\websockets;$(ProjectDir)..\workers;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ProjectDir)..\ForwardingHeaders;$(ProjectDir)..\platform\graphics\gpu;$(ProjectDir)..\platform\graphics\egl;$(ProjectDir)..\platform\graphics\surfaces;$(ProjectDir)..\platform\graphics\surfaces\egl;$(ProjectDir)..\platform\graphics\opengl;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;$(WebKit_Libraries)\include\private\JavaScriptCore;$(WebKit_Libraries)\include\sqlite;$(WebKit_Libraries)\include\JavaScriptCore;$(WebKit_Libraries)\include\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>DISABLE_3D_RENDERING;WEBCORE_CONTEXT_MENUS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>WebCorePrefix.h</PrecompiledHeaderFile>
index 82b1c30..147804d 100644 (file)
                07277E5317D018CC0015534D /* JSMediaStreamTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4717D018CC0015534D /* JSMediaStreamTrack.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07277E5417D018CC0015534D /* JSMediaStreamTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07277E4817D018CC0015534D /* JSMediaStreamTrackEvent.cpp */; };
                07277E5517D018CC0015534D /* JSMediaStreamTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1DF183C0741000A5988 /* PluginReplacement.h */; };
+               072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */; };
+               072AE1E8183C0741000A5988 /* QuickTimePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */; };
                072C8B11131C518600A4FCE9 /* MediaPlayerPrivateAVFoundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076F0D0912B8192700C26AA4 /* MediaPlayerPrivateAVFoundation.cpp */; };
                072CA86116CB4DC3008AE131 /* CaptionUserPreferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 072CA86016CB4DC3008AE131 /* CaptionUserPreferences.cpp */; };
                0735EE6A0F40C5E4004A2604 /* MediaPlayerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0735EE690F40C5E4004A2604 /* MediaPlayerProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
                07846342145B151A00A58DF1 /* JSTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07846340145B151A00A58DF1 /* JSTrackEvent.cpp */; };
                07846343145B151A00A58DF1 /* JSTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07846341145B151A00A58DF1 /* JSTrackEvent.h */; };
                07846385145B1B8E00A58DF1 /* JSTrackCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = 07846384145B1B8E00A58DF1 /* JSTrackCustom.h */; };
+               077664FC183E6B5C00133B92 /* JSQuickTimePluginReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 077664FA183E6B5C00133B92 /* JSQuickTimePluginReplacement.cpp */; };
+               077664FD183E6B5C00133B92 /* JSQuickTimePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 077664FB183E6B5C00133B92 /* JSQuickTimePluginReplacement.h */; };
                078E08FE17D14CEE00420AA1 /* MediaConstraintsImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4A17CEC32700848E51 /* MediaConstraintsImpl.cpp */; };
                078E08FF17D14CEE00420AA1 /* MediaStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4C17CEC32700848E51 /* MediaStream.cpp */; };
                078E090017D14CEE00420AA1 /* MediaStreamEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4F17CEC32700848E51 /* MediaStreamEvent.cpp */; };
                072847E316EBC5B00043CFA4 /* PlatformTextTrackMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformTextTrackMenu.h; sourceTree = "<group>"; };
                0729B14E17CFCCA0004F1D60 /* MediaStreamCenterMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaStreamCenterMac.cpp; sourceTree = "<group>"; };
                0729B14F17CFCCA0004F1D60 /* MediaStreamCenterMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaStreamCenterMac.h; sourceTree = "<group>"; };
+               072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PluginReplacement.h; path = plugins/PluginReplacement.h; sourceTree = "<group>"; };
+               072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QuickTimePluginReplacement.cpp; path = plugins/QuickTimePluginReplacement.cpp; sourceTree = "<group>"; };
+               072AE1E1183C0741000A5988 /* QuickTimePluginReplacement.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = QuickTimePluginReplacement.css; path = plugins/QuickTimePluginReplacement.css; sourceTree = "<group>"; };
+               072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QuickTimePluginReplacement.h; path = plugins/QuickTimePluginReplacement.h; sourceTree = "<group>"; };
+               072AE1E3183C0741000A5988 /* QuickTimePluginReplacement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = QuickTimePluginReplacement.idl; path = plugins/QuickTimePluginReplacement.idl; sourceTree = "<group>"; };
+               072AE1E4183C0741000A5988 /* QuickTimePluginReplacement.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = QuickTimePluginReplacement.js; path = plugins/QuickTimePluginReplacement.js; sourceTree = "<group>"; };
                072CA86016CB4DC3008AE131 /* CaptionUserPreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CaptionUserPreferences.cpp; sourceTree = "<group>"; };
                0735EE690F40C5E4004A2604 /* MediaPlayerProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPlayerProxy.h; sourceTree = "<group>"; };
                07367DDD172CA67F00D861B9 /* InbandTextTrackPrivateLegacyAVFObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InbandTextTrackPrivateLegacyAVFObjC.h; path = objc/InbandTextTrackPrivateLegacyAVFObjC.h; sourceTree = "<group>"; };
                0779BF0C18453168000B6AE7 /* HTMLMediaElementMediaStream.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLMediaElementMediaStream.idl; sourceTree = "<group>"; };
                0783228218013ED700999E0C /* MediaStreamAudioSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaStreamAudioSource.cpp; sourceTree = "<group>"; };
                0783228318013ED800999E0C /* MediaStreamAudioSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaStreamAudioSource.h; sourceTree = "<group>"; };
+               077664FA183E6B5C00133B92 /* JSQuickTimePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSQuickTimePluginReplacement.cpp; path = JSQuickTimePluginReplacement.cpp; sourceTree = "<group>"; };
+               077664FB183E6B5C00133B92 /* JSQuickTimePluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSQuickTimePluginReplacement.h; path = JSQuickTimePluginReplacement.h; sourceTree = "<group>"; };
                07846340145B151A00A58DF1 /* JSTrackEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTrackEvent.cpp; sourceTree = "<group>"; };
                07846341145B151A00A58DF1 /* JSTrackEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTrackEvent.h; sourceTree = "<group>"; };
                07846384145B1B8E00A58DF1 /* JSTrackCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTrackCustom.h; sourceTree = "<group>"; };
                        path = mac;
                        sourceTree = "<group>";
                };
+               072AE1DE183C0513000A5988 /* plugins */ = {
+                       isa = PBXGroup;
+                       children = (
+                               072AE1DF183C0741000A5988 /* PluginReplacement.h */,
+                               072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */,
+                               072AE1E1183C0741000A5988 /* QuickTimePluginReplacement.css */,
+                               072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */,
+                               072AE1E3183C0741000A5988 /* QuickTimePluginReplacement.idl */,
+                               072AE1E4183C0741000A5988 /* QuickTimePluginReplacement.js */,
+                       );
+                       name = plugins;
+                       sourceTree = "<group>";
+               };
                076F0D0812B8192700C26AA4 /* avfoundation */ = {
                        isa = PBXGroup;
                        children = (
                14DFB33F0A7DF7630018F769 /* Derived Sources */ = {
                        isa = PBXGroup;
                        children = (
+                               077664FA183E6B5C00133B92 /* JSQuickTimePluginReplacement.cpp */,
+                               077664FB183E6B5C00133B92 /* JSQuickTimePluginReplacement.h */,
                                A83B79100CCB001B000B0825 /* Core */,
                                E1FF8F61180745C600132674 /* Crypto */,
                                A83B790E0CCAFF97000B0825 /* CSS */,
                971145FE14EF006E00674FD9 /* Modules */ = {
                        isa = PBXGroup;
                        children = (
+                               072AE1DE183C0513000A5988 /* plugins */,
                                CDA98DBD16014E0800FEA3B1 /* encryptedmedia */,
                                971145FF14EF007900674FD9 /* geolocation */,
                                9712A55315004E3C0048AF10 /* indexeddb */,
                                29489FC712C00F0300D83F0F /* AccessibilityScrollView.h in Headers */,
                                0709FC4E1025DEE30059CDBA /* AccessibilitySlider.h in Headers */,
                                51D719D7181106E00016DC51 /* IDBHistograms.h in Headers */,
+                               072AE1E8183C0741000A5988 /* QuickTimePluginReplacement.h in Headers */,
                                29D7BCFA1444AF7D0070619C /* AccessibilitySpinButton.h in Headers */,
                                AAC08CF315F941FD00F1E188 /* AccessibilitySVGRoot.h in Headers */,
                                29A8122B0FBB9C1D00510293 /* AccessibilityTable.h in Headers */,
                                FD315FFF12B0267600C1A359 /* ChannelMergerNode.h in Headers */,
                                FD31600212B0267600C1A359 /* ChannelSplitterNode.h in Headers */,
                                6550B6A0099DF0270090D781 /* CharacterData.h in Headers */,
+                               077664FD183E6B5C00133B92 /* JSQuickTimePluginReplacement.h in Headers */,
                                97B8FFD116AE7F960038388D /* CharacterReferenceParserInlines.h in Headers */,
                                E164FAA318315BF400DB4E61 /* CryptoKeyRSA.h in Headers */,
                                B2C3DA2A0D006C1D00EF6F26 /* CharsetData.h in Headers */,
                                E180811716FCF9CB00B80D07 /* SynchronousLoaderClient.h in Headers */,
                                5DA97ECD168E787B000E3676 /* SystemVersionMac.h in Headers */,
                                A8CFF0510A154F09000A4234 /* TableLayout.h in Headers */,
+                               072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */,
                                BCE3BEC30D222B1D007E06E4 /* TagNodeList.h in Headers */,
                                F55B3DD61251F12D003EF269 /* TelephoneInputType.h in Headers */,
                                C65046A9167BFB5500CC2A4D /* TemplateContentDocumentFragment.h in Headers */,
                                8485227B1190162C006EDC7F /* JSSVGHKernElement.cpp in Sources */,
                                B2FA3D9E0AB75A6F000E5AC4 /* JSSVGImageElement.cpp in Sources */,
                                B2FA3DA00AB75A6F000E5AC4 /* JSSVGLength.cpp in Sources */,
+                               077664FC183E6B5C00133B92 /* JSQuickTimePluginReplacement.cpp in Sources */,
                                08E4FE460E2BD41400F4CAE0 /* JSSVGLengthCustom.cpp in Sources */,
                                B2FA3DA20AB75A6F000E5AC4 /* JSSVGLengthList.cpp in Sources */,
                                B2FA3DA40AB75A6F000E5AC4 /* JSSVGLinearGradientElement.cpp in Sources */,
                                0705850217FA10D0005F2BCB /* JSAllVideoCapabilities.cpp in Sources */,
                                9759E93E14EF1CF80026A2DD /* LoadableTextTrack.cpp in Sources */,
                                656D37330ADBA5DE00A4554D /* LoaderNSURLExtras.mm in Sources */,
+                               072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.cpp in Sources */,
                                7EE6846812D26E3800E79415 /* LoaderRunLoopCF.cpp in Sources */,
                                51ABF64D16392E2800132A7A /* LoaderStrategy.cpp in Sources */,
                                06E81EEC0AB5DA9700C87837 /* LocalCurrentGraphicsContext.mm in Sources */,
index 7d17717..2720901 100644 (file)
@@ -228,6 +228,9 @@ public:
     // The lang attribute support is incomplete and should only be turned on for tests.
     void setLangAttributeAwareFormControlUIEnabled(bool isEnabled) { m_isLangAttributeAwareFormControlUIEnabled = isEnabled; }
 
+    void setPluginReplacementEnabled(bool isEnabled) { m_isPluginReplacementEnabled = isEnabled; }
+    bool pluginReplacementEnabled() const { return m_isPluginReplacementEnabled; }
+
     static RuntimeEnabledFeatures& sharedFeatures();
 
 private:
@@ -250,6 +253,8 @@ private:
     bool m_isCSSRegionsEnabled;
     bool m_isCSSCompositingEnabled;
     bool m_isLangAttributeAwareFormControlUIEnabled;
+    bool m_isPluginReplacementEnabled;
+
 #if ENABLE(SCRIPTED_SPEECH)
     bool m_isScriptedSpeechEnabled;
 #endif
index 6db8004..1cfe7e1 100644 (file)
@@ -392,6 +392,11 @@ inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject,
     return array;
 }
 
+inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
+{
+    return jsStringOrNull(exec, value);
+}
+
 template <class T>
 struct JSValueTraits {
     static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value)
index 85a9dab..adb3e3a 100644 (file)
@@ -82,7 +82,11 @@ JSObject* pluginScriptObject(ExecState* exec, JSHTMLElement* jsHTMLElement)
 
     HTMLPlugInElement& pluginElement = toHTMLPlugInElement(element);
 
-    // First, see if we can ask the plug-in view for its script object.
+    // First, see if the element has a plug-in replacement with a script.
+    if (JSObject* scriptObject = pluginElement.scriptObjectForPluginReplacement())
+        return scriptObject;
+    
+    // Next, see if we can ask the plug-in view for its script object.
     if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()))
         return scriptObject;
 
index 9816888..f7d65ce 100644 (file)
@@ -170,9 +170,8 @@ void HTMLEmbedElement::updateWidget(PluginCreationOption pluginCreationOption)
     if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
         return;
 
-    SubframeLoader& loader = document().frame()->loader().subframeLoader();
     // FIXME: beforeLoad could have detached the renderer!  Just like in the <object> case above.
-    loader.requestObject(*this, m_url, getNameAttribute(), m_serviceType, paramNames, paramValues);
+    requestObject(m_url, m_serviceType, paramNames, paramValues);
 }
 
 bool HTMLEmbedElement::rendererIsNeeded(const RenderStyle& style)
index 3407378..188a006 100644 (file)
@@ -5300,6 +5300,14 @@ void HTMLMediaElement::didAddUserAgentShadowRoot(ShadowRoot* root)
 }
 #endif
 
+unsigned long long HTMLMediaElement::fileSize() const
+{
+    if (m_player)
+        return m_player->fileSize();
+    
+    return 0;
+}
+
 }
 
 #endif
index f64d437..1c7dd05 100644 (file)
@@ -393,6 +393,8 @@ public:
     bool shouldUseVideoPluginProxy() const;
 #endif
 
+    unsigned long long fileSize() const;
+
 protected:
     HTMLMediaElement(const QualifiedName&, Document&, bool);
     virtual ~HTMLMediaElement();
index 07f59a1..2906ff5 100644 (file)
@@ -307,8 +307,9 @@ void HTMLObjectElement::updateWidget(PluginCreationOption pluginCreationOption)
     if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
         return;
 
-    SubframeLoader& loader = document().frame()->loader().subframeLoader();
-    bool success = beforeLoadAllowedLoad && hasValidClassId() && loader.requestObject(*this, url, getNameAttribute(), serviceType, paramNames, paramValues);
+    bool success = beforeLoadAllowedLoad && hasValidClassId();
+    if (success)
+        success = requestObject(url, serviceType, paramNames, paramValues);
     if (!success && hasFallbackContent())
         renderFallbackContent();
 }
index fcb55a8..260b649 100644 (file)
 #include "FrameLoader.h"
 #include "FrameTree.h"
 #include "HTMLNames.h"
+#include "Logging.h"
+#include "MIMETypeRegistry.h"
 #include "Page.h"
+#include "PluginData.h"
+#include "PluginReplacement.h"
 #include "PluginViewBase.h"
 #include "RenderEmbeddedObject.h"
 #include "RenderSnapshottedPlugIn.h"
 #include "RenderWidget.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScriptController.h"
 #include "Settings.h"
+#include "ShadowRoot.h"
+#include "SubframeLoader.h"
 #include "Widget.h"
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
 #include "npruntime_impl.h"
 #endif
 
+#if PLATFORM(MAC)
+#include "QuickTimePluginReplacement.h"
+#endif
+
 namespace WebCore {
 
 using namespace HTMLNames;
@@ -55,6 +66,7 @@ using namespace HTMLNames;
 HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& document)
     : HTMLFrameOwnerElement(tagName, document)
     , m_inBeforeLoadEventHandler(false)
+    , m_swapRendererTimer(this, &HTMLPlugInElement::swapRendererTimerFired)
 #if ENABLE(NETSCAPE_PLUGIN_API)
     , m_NPObject(0)
 #endif
@@ -262,4 +274,138 @@ NPObject* HTMLPlugInElement::getNPObject()
 
 #endif /* ENABLE(NETSCAPE_PLUGIN_API) */
 
+RenderElement* HTMLPlugInElement::createRenderer(PassRef<RenderStyle> style)
+{
+    if (m_pluginReplacement && m_pluginReplacement->willCreateRenderer())
+        return m_pluginReplacement->createRenderer(*this, std::move(style));
+
+    return new RenderEmbeddedObject(*this, std::move(style));
+}
+
+void HTMLPlugInElement::swapRendererTimerFired(Timer<HTMLPlugInElement>*)
+{
+    ASSERT(displayState() == PreparingPluginReplacement || displayState() == DisplayingSnapshot);
+    if (userAgentShadowRoot())
+        return;
+    
+    // Create a shadow root, which will trigger the code to add a snapshot container
+    // and reattach, thus making a new Renderer.
+    ensureUserAgentShadowRoot();
+}
+
+void HTMLPlugInElement::setDisplayState(DisplayState state)
+{
+    m_displayState = state;
+    
+    if ((state == DisplayingSnapshot || displayState() == PreparingPluginReplacement) && !m_swapRendererTimer.isActive())
+        m_swapRendererTimer.startOneShot(0);
+}
+
+void HTMLPlugInElement::didAddUserAgentShadowRoot(ShadowRoot* root)
+{
+    if (!m_pluginReplacement || !document().page() || displayState() != PreparingPluginReplacement)
+        return;
+    
+    root->setResetStyleInheritance(true);
+    if (m_pluginReplacement->installReplacement(root)) {
+        setDisplayState(DisplayingPluginReplacement);
+        Style::reattachRenderTree(*this);
+    }
+}
+
+#if PLATFORM(MAC)
+static void registrar(const ReplacementPlugin&);
+#endif
+
+static Vector<ReplacementPlugin*>& registeredPluginReplacements()
+{
+    DEFINE_STATIC_LOCAL(Vector<ReplacementPlugin*>, registeredReplacements, ());
+    static bool enginesQueried = false;
+    
+    if (enginesQueried)
+        return registeredReplacements;
+    enginesQueried = true;
+
+#if PLATFORM(MAC)
+    QuickTimePluginReplacement::registerPluginReplacement(registrar);
+#endif
+    
+    return registeredReplacements;
+}
+
+#if PLATFORM(MAC)
+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;
+    String lastPathComponent = url.lastPathComponent();
+    size_t dotOffset = lastPathComponent.reverseFind('.');
+    if (dotOffset != notFound)
+        extension = lastPathComponent.substring(dotOffset + 1);
+
+    String type = mimeType;
+    if (type.isEmpty() && url.protocolIsData())
+        type = mimeTypeFromDataURL(url.string());
+    
+    if (type.isEmpty() && !extension.isEmpty()) {
+        for (size_t i = 0; i < replacements.size(); i++)
+            if (replacements[i]->supportsFileExtension(extension))
+                return replacements[i];
+    }
+    
+    if (type.isEmpty()) {
+        if (extension.isEmpty())
+            return nullptr;
+        type = MIMETypeRegistry::getMediaMIMETypeForExtension(extension);
+    }
+
+    if (type.isEmpty())
+        return nullptr;
+
+    for (unsigned i = 0; i < replacements.size(); i++)
+        if (replacements[i]->supportsType(type))
+            return replacements[i];
+
+    return nullptr;
+}
+
+bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+    if (!RuntimeEnabledFeatures::sharedFeatures().pluginReplacementEnabled())
+        return false;
+
+    if (m_pluginReplacement)
+        return true;
+
+    URL completedURL;
+    if (!url.isEmpty())
+        completedURL = document().completeURL(url);
+
+    ReplacementPlugin* replacement = pluginReplacementForType(completedURL, mimeType);
+    if (!replacement)
+        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 (m_pluginReplacement)
+        return m_pluginReplacement->scriptObject();
+    return nullptr;
+}
+
 }
index a626776..a83b693 100644 (file)
@@ -38,6 +38,7 @@ class Instance;
 
 namespace WebCore {
 
+class PluginReplacement;
 class RenderEmbeddedObject;
 class RenderWidget;
 class Widget;
@@ -57,14 +58,18 @@ public:
         DisplayingSnapshot,
         Restarting,
         RestartingWithPendingMouseClick,
-        Playing
+        Playing,
+        PreparingPluginReplacement,
+        DisplayingPluginReplacement,
     };
     DisplayState displayState() const { return m_displayState; }
-    virtual void setDisplayState(DisplayState state) { m_displayState = state; }
+    virtual void setDisplayState(DisplayState);
     virtual void updateSnapshot(PassRefPtr<Image>) { }
     virtual void dispatchPendingMouseClick() { }
     virtual bool isRestartedPlugin() const { return false; }
 
+    JSC::JSObject* scriptObjectForPluginReplacement();
+
 #if ENABLE(NETSCAPE_PLUGIN_API)
     NPObject* getNPObject();
 #endif
@@ -91,12 +96,19 @@ protected:
 
     virtual void defaultEventHandler(Event*) OVERRIDE;
 
+    virtual bool requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues);
+    virtual RenderElement* createRenderer(PassRef<RenderStyle>) OVERRIDE;
+    virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
+
     // Subclasses should use guardedDispatchBeforeLoadEvent instead of calling dispatchBeforeLoadEvent directly.
     bool guardedDispatchBeforeLoadEvent(const String& sourceURL);
 
     bool m_inBeforeLoadEventHandler;
 
 private:
+    void swapRendererTimerFired(Timer<HTMLPlugInElement>*);
+    bool shouldOverridePlugin(const String& url, const String& mimeType);
+
     bool dispatchBeforeLoadEvent(const String& sourceURL); // Not implemented, generates a compile error if subclasses call this by mistake.
 
     virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
@@ -109,6 +121,8 @@ private:
     virtual bool isPluginElement() const OVERRIDE FINAL;
 
     RefPtr<JSC::Bindings::Instance> m_instance;
+    Timer<HTMLPlugInElement> m_swapRendererTimer;
+    RefPtr<PluginReplacement> m_pluginReplacement;
 #if ENABLE(NETSCAPE_PLUGIN_API)
     NPObject* m_NPObject;
 #endif
index 2438dfe..0bc3dde 100644 (file)
@@ -108,7 +108,6 @@ HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Doc
     , m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
     , m_needsDocumentActivationCallbacks(false)
     , m_simulatedMouseClickTimer(this, &HTMLPlugInImageElement::simulatedMouseClickTimerFired, simulatedMouseClickTimerDelay)
-    , m_swapRendererTimer(this, &HTMLPlugInImageElement::swapRendererTimerFired)
     , m_removeSnapshotTimer(this, &HTMLPlugInImageElement::removeSnapshotTimerFired)
     , m_createdDuringUserGesture(ScriptController::processingUserGesture())
     , m_isRestartedPlugin(false)
@@ -139,9 +138,6 @@ void HTMLPlugInImageElement::setDisplayState(DisplayState state)
 #endif
 
     HTMLPlugInElement::setDisplayState(state);
-
-    if (state == DisplayingSnapshot)
-        m_swapRendererTimer.startOneShot(0);
 }
 
 RenderEmbeddedObject* HTMLPlugInImageElement::renderEmbeddedObject() const
@@ -196,6 +192,9 @@ bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const
 
 RenderElement* HTMLPlugInImageElement::createRenderer(PassRef<RenderStyle> style)
 {
+    if (displayState() >= PreparingPluginReplacement)
+        return HTMLPlugInElement::createRenderer(std::move(style));
+
     // Once a PlugIn Element creates its renderer, it needs to be told when the Document goes
     // inactive or reactivates so it can clear the renderer before going into the page cache.
     if (!m_needsDocumentActivationCallbacks) {
@@ -221,7 +220,7 @@ RenderElement* HTMLPlugInImageElement::createRenderer(PassRef<RenderStyle> style
         return image;
     }
 
-    return new RenderEmbeddedObject(*this, std::move(style));
+    return HTMLPlugInElement::createRenderer(std::move(style));
 }
 
 bool HTMLPlugInImageElement::willRecalcStyle(Style::Change)
@@ -363,8 +362,12 @@ static DOMWrapperWorld& plugInImageElementIsolatedWorld()
 
 void HTMLPlugInImageElement::didAddUserAgentShadowRoot(ShadowRoot* root)
 {
+    HTMLPlugInElement::didAddUserAgentShadowRoot(root);
+    if (displayState() >= PreparingPluginReplacement)
+        return;
+
     Page* page = document().page();
-    if (!page)
+    if (page)
         return;
 
     // Reset any author styles that may apply as we only want explicit
@@ -409,17 +412,6 @@ bool HTMLPlugInImageElement::partOfSnapshotOverlay(Node* node)
     return node && snapshotLabel && (node == snapshotLabel.get() || node->isDescendantOf(snapshotLabel.get()));
 }
 
-void HTMLPlugInImageElement::swapRendererTimerFired(Timer<HTMLPlugInImageElement>*)
-{
-    ASSERT(displayState() == DisplayingSnapshot);
-    if (userAgentShadowRoot())
-        return;
-
-    // Create a shadow root, which will trigger the code to add a snapshot container
-    // and reattach, thus making a new Renderer.
-    ensureUserAgentShadowRoot();
-}
-
 void HTMLPlugInImageElement::removeSnapshotTimerFired(Timer<HTMLPlugInImageElement>*)
 {
     m_snapshotImage = nullptr;
@@ -496,7 +488,7 @@ void HTMLPlugInImageElement::userDidClickSnapshot(PassRefPtr<MouseEvent> event,
     LOG(Plugins, "%p User clicked on snapshotted plug-in. Restart.", this);
     restartSnapshottedPlugIn();
     if (forwardEvent)
-        setDisplayState(HTMLPlugInElement::RestartingWithPendingMouseClick);
+        setDisplayState(RestartingWithPendingMouseClick);
     restartSimilarPlugIns();
 }
 
@@ -732,4 +724,13 @@ void HTMLPlugInImageElement::defaultEventHandler(Event* event)
     HTMLPlugInElement::defaultEventHandler(event);
 }
 
+bool HTMLPlugInImageElement::requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+    if (HTMLPlugInElement::requestObject(url, mimeType, paramNames, paramValues))
+        return true;
+    
+    SubframeLoader& loader = document().frame()->loader().subframeLoader();
+    return loader.requestObject(*this, url, getNameAttribute(), mimeType, paramNames, paramValues);
+}
+
 } // namespace WebCore
index 4d90a5c..e4f582b 100644 (file)
@@ -29,6 +29,7 @@
 namespace WebCore {
 
 class HTMLImageLoader;
+class HTMLVideoElement;
 class FrameLoader;
 class Image;
 class MouseEvent;
@@ -123,6 +124,7 @@ protected:
     virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
 
     virtual bool isRestartedPlugin() const OVERRIDE { return m_isRestartedPlugin; }
+    virtual bool requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues) OVERRIDE;
 
 private:
     virtual RenderElement* createRenderer(PassRef<RenderStyle>) OVERRIDE;
@@ -138,8 +140,6 @@ private:
     virtual void dispatchPendingMouseClick() OVERRIDE;
     void simulatedMouseClickTimerFired(DeferrableOneShotTimer<HTMLPlugInImageElement>*);
 
-    void swapRendererTimerFired(Timer<HTMLPlugInImageElement>*);
-
     void restartSimilarPlugIns();
 
     virtual bool isPlugInImageElement() const OVERRIDE { return true; }
@@ -154,7 +154,6 @@ private:
     RefPtr<RenderStyle> m_customStyleForPageCache;
     RefPtr<MouseEvent> m_pendingClickEventFromSnapshot;
     DeferrableOneShotTimer<HTMLPlugInImageElement> m_simulatedMouseClickTimer;
-    Timer<HTMLPlugInImageElement> m_swapRendererTimer;
     Timer<HTMLPlugInImageElement> m_removeSnapshotTimer;
     RefPtr<Image> m_snapshotImage;
     bool m_createdDuringUserGesture;
index 284544e..a7681c4 100644 (file)
@@ -72,12 +72,12 @@ public:
     bool shouldDisplayPosterImage() const { return displayMode() == Poster || displayMode() == PosterWaitingForVideo; }
 
     URL posterImageURL() const;
+    virtual RenderElement* createRenderer(PassRef<RenderStyle>) OVERRIDE;
 
 private:
     HTMLVideoElement(const QualifiedName&, Document&, bool);
 
     virtual bool rendererIsNeeded(const RenderStyle&) OVERRIDE;
-    virtual RenderElement* createRenderer(PassRef<RenderStyle>) OVERRIDE;
     virtual void didAttachRenderers() OVERRIDE;
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
index 6a88e43..2264333 100644 (file)
@@ -1225,6 +1225,14 @@ size_t MediaPlayer::extraMemoryCost() const
     return m_private->extraMemoryCost();
 }
 
+unsigned long long MediaPlayer::fileSize() const
+{
+    if (!m_private)
+        return 0;
+    
+    return m_private->fileSize();
+}
+
 void MediaPlayerFactorySupport::callRegisterMediaEngine(MediaEngineRegister registerMediaEngine)
 {
     registerMediaEngine(addMediaEngine);
index 2a696f2..8df01b1 100644 (file)
@@ -508,6 +508,8 @@ public:
 
     size_t extraMemoryCost() const;
 
+    unsigned long long fileSize() const;
+
 private:
     MediaPlayer(MediaPlayerClient*);
     MediaPlayerFactory* nextBestMediaEngine(MediaPlayerFactory*) const;
index 3d31a45..3fbde63 100644 (file)
@@ -213,6 +213,8 @@ public:
     virtual String languageOfPrimaryAudioTrack() const { return emptyString(); }
 
     virtual size_t extraMemoryCost() const { return 0; }
+    
+    virtual unsigned long long fileSize() const { return 0; }
 };
 
 }
index cbf3106..267be4d 100644 (file)
@@ -921,7 +921,8 @@ size_t MediaPlayerPrivateAVFoundation::extraMemoryCost() const
     if (!duration)
         return 0;
 
-    return totalBytes() * buffered()->totalDuration() / duration;
+    unsigned long long extra = totalBytes() * buffered()->totalDuration() / duration;
+    return static_cast<unsigned>(extra);
 }
 
 void MediaPlayerPrivateAVFoundation::clearTextTracks()
index 7ac5b01..5da1b68 100644 (file)
@@ -190,6 +190,7 @@ protected:
 
     virtual bool supportsFullscreen() const;
     virtual bool supportsScanning() const { return true; }
+    unsigned long long fileSize() const { return totalBytes(); }
 
     // Required interfaces for concrete derived classes.
     virtual void createAVAssetForURL(const String&) = 0;
@@ -225,7 +226,7 @@ protected:
     virtual void updateRate() = 0;
     virtual float rate() const = 0;
     virtual void seekToTime(double time, double negativeTolerance, double positiveTolerance) = 0;
-    virtual unsigned totalBytes() const = 0;
+    virtual unsigned long long totalBytes() const = 0;
     virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const = 0;
     virtual double platformMaxTimeSeekable() const = 0;
     virtual double platformMinTimeSeekable() const = 0;
index 17e132b..6213b4c 100644 (file)
@@ -721,7 +721,7 @@ float MediaPlayerPrivateAVFoundationCF::platformMaxTimeLoaded() const
     return maxTimeLoaded;   
 }
 
-unsigned MediaPlayerPrivateAVFoundationCF::totalBytes() const
+unsigned long long MediaPlayerPrivateAVFoundationCF::totalBytes() const
 {
     if (!metaDataAvailable() || !avAsset(m_avfWrapper))
         return 0;
@@ -734,8 +734,7 @@ unsigned MediaPlayerPrivateAVFoundationCF::totalBytes() const
         totalMediaSize += AVCFAssetTrackGetTotalSampleDataLength(assetTrack);
     }
 
-    // FIXME: It doesn't seem safe to cast an int64_t to unsigned.
-    return static_cast<unsigned>(totalMediaSize);
+    return static_cast<unsigned long long>(totalMediaSize);
 }
 
 MediaPlayerPrivateAVFoundation::AssetStatus MediaPlayerPrivateAVFoundationCF::assetStatus() const
index 279e582..eb979a3 100644 (file)
@@ -77,7 +77,7 @@ private:
     virtual void updateRate();
     virtual float rate() const;
     virtual void seekToTime(double time, double negativeTolerance, double positiveTolerance);
-    virtual unsigned totalBytes() const;
+    virtual unsigned long long totalBytes() const;
     virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const;
     virtual double platformMinTimeSeekable() const;
     virtual double platformMaxTimeSeekable() const;
index 1562944..5957f12 100644 (file)
@@ -148,7 +148,7 @@ private:
     virtual void updateRate();
     virtual float rate() const;
     virtual void seekToTime(double time, double negativeTolerance, double positiveTolerance);
-    virtual unsigned totalBytes() const;
+    virtual unsigned long long totalBytes() const;
     virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const;
     virtual double platformMinTimeSeekable() const;
     virtual double platformMaxTimeSeekable() const;
index 363ad84..483cbc7 100644 (file)
@@ -803,7 +803,7 @@ float MediaPlayerPrivateAVFoundationObjC::platformMaxTimeLoaded() const
     return maxTimeLoaded;   
 }
 
-unsigned MediaPlayerPrivateAVFoundationObjC::totalBytes() const
+unsigned long long MediaPlayerPrivateAVFoundationObjC::totalBytes() const
 {
     if (!metaDataAvailable())
         return 0;
@@ -812,7 +812,7 @@ unsigned MediaPlayerPrivateAVFoundationObjC::totalBytes() const
     for (AVPlayerItemTrack *thisTrack in m_cachedTracks.get())
         totalMediaSize += [[thisTrack assetTrack] totalSampleDataLength];
 
-    return static_cast<unsigned>(totalMediaSize);
+    return totalMediaSize;
 }
 
 void MediaPlayerPrivateAVFoundationObjC::setAsset(id asset)
index 6c32dff..4363f4f 100644 (file)
@@ -94,6 +94,7 @@ InternalSettings::Backup::Backup(Settings& settings)
     , m_originalTimeWithoutMouseMovementBeforeHidingControls(settings.timeWithoutMouseMovementBeforeHidingControls())
     , m_useLegacyBackgroundSizeShorthandBehavior(settings.useLegacyBackgroundSizeShorthandBehavior())
     , m_autoscrollForDragAndDropEnabled(settings.autoscrollForDragAndDropEnabled())
+    , m_pluginReplacementEnabled(RuntimeEnabledFeatures::sharedFeatures().pluginReplacementEnabled())
 {
 }
 
@@ -156,6 +157,7 @@ void InternalSettings::Backup::restoreTo(Settings& settings)
     settings.setTimeWithoutMouseMovementBeforeHidingControls(m_originalTimeWithoutMouseMovementBeforeHidingControls);
     settings.setUseLegacyBackgroundSizeShorthandBehavior(m_useLegacyBackgroundSizeShorthandBehavior);
     settings.setAutoscrollForDragAndDropEnabled(m_autoscrollForDragAndDropEnabled);
+    RuntimeEnabledFeatures::sharedFeatures().setPluginReplacementEnabled(m_pluginReplacementEnabled);
 }
 
 // We can't use RefCountedSupplement because that would try to make InternalSettings RefCounted
@@ -528,4 +530,9 @@ void InternalSettings::setFontFallbackPrefersPictographs(bool preferPictographs,
     settings()->setFontFallbackPrefersPictographs(preferPictographs);
 }
 
+void InternalSettings::setPluginReplacementEnabled(bool enabled)
+{
+    RuntimeEnabledFeatures::sharedFeatures().setPluginReplacementEnabled(enabled);
+}
+
 }
index 0fa845e..1dcdec3 100644 (file)
@@ -91,6 +91,7 @@ public:
         bool m_originalTimeWithoutMouseMovementBeforeHidingControls;
         bool m_useLegacyBackgroundSizeShorthandBehavior;
         bool m_autoscrollForDragAndDropEnabled;
+        bool m_pluginReplacementEnabled;
     };
 
     static PassRefPtr<InternalSettings> create(Page* page)
@@ -136,6 +137,7 @@ public:
     void setUseLegacyBackgroundSizeShorthandBehavior(bool enabled, ExceptionCode&);
     void setAutoscrollForDragAndDropEnabled(bool enabled, ExceptionCode&);
     void setFontFallbackPrefersPictographs(bool preferPictographs, ExceptionCode&);
+    void setPluginReplacementEnabled(bool);
 
 private:
     explicit InternalSettings(Page*);
index 709c11e..2678b68 100644 (file)
@@ -60,4 +60,5 @@
     [RaisesException] void setUseLegacyBackgroundSizeShorthandBehavior(boolean enabled);
     [RaisesException] void setAutoscrollForDragAndDropEnabled(boolean enabled);
     [RaisesException] void setFontFallbackPrefersPictographs(boolean preferPictographs);
+    void setPluginReplacementEnabled(boolean enabled);
 };