<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[166719] trunk/Source/WebCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/166719">166719</a></dd>
<dt>Author</dt> <dd>eric.carlson@apple.com</dd>
<dt>Date</dt> <dd>2014-04-03 08:46:05 -0700 (Thu, 03 Apr 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>[iOS] add missing QuickTime plug-in replacement API
https://bugs.webkit.org/show_bug.cgi?id=131042
Reviewed by Dean Jackson.
Rename QuickTimePluginReplacement.cpp to QuickTimePluginReplacement.mm to make it possible
to use the ObjC JSC API.
* Modules/plugins/QuickTimePluginReplacement.cpp:
* Modules/plugins/QuickTimePluginReplacement.h:
(WebCore::QuickTimePluginReplacement::parentElement):
* Modules/plugins/QuickTimePluginReplacement.idl:
* Modules/plugins/QuickTimePluginReplacement.js:
(Replacement.prototype.timedMetadataUpdates): Implement.
(Replacement.prototype.accessLog): Ditto.
(Replacement.prototype.errorLog): Ditto.
Use the JSC ObjC API to create a JavaScript object from an array of AVMetadataItems. The
JSC ObjC API supports basic NSTypes, but an AVMetadataItem can also contain NSData which
the existing plug-in returns as base-64 encoded data, so create wrappers for NSDictionary
and NSArray.
* Modules/plugins/QuickTimePluginReplacement.mm: Copied from Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp.
(WebCore::QuickTimePluginReplacement::ensureReplacementScriptInjected): Disambiguate with "JSC::"
(WebCore::QuickTimePluginReplacement::installReplacement): Ditto.
(WebCore::jsValueWithDataInContext): Create JSValue* from NSData.
(WebCore::jsValueWithArrayInContext): Create JSValue* from NSArray.
(WebCore::jsValueWithDictionaryInContext): Create JSValue* from NSDictionary.
(WebCore::jsValueWithValueInContext): Create JSValue* from basic NSTypes plus AVMetadataItem
and NSData.
(WebCore::jsValueWithAVMetadataItemInContext): Create JSValue* from AVMetadataItem.
(WebCore::JSQuickTimePluginReplacement::timedMetaData): Script interface.
(WebCore::JSQuickTimePluginReplacement::accessLog): Ditto.
(WebCore::JSQuickTimePluginReplacement::errorLog): Ditto.
* WebCore.xcodeproj/project.pbxproj: QuickTimePluginReplacement.cpp -> QuickTimePluginReplacement.mm.
* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::timedMetadata): iOS only accessor.
(WebCore::MediaPlayer::accessLog): Ditto.
(WebCore::MediaPlayer::errorLog): Ditto.
* platform/graphics/MediaPlayer.h:
* platform/graphics/MediaPlayerPrivate.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::timedMetadata):
(WebCore::MediaPlayerPrivateAVFoundationObjC::accessLog):
(WebCore::MediaPlayerPrivateAVFoundationObjC::errorLog):
(WebCore::MediaPlayerPrivateAVFoundationObjC::metadataDidArrive):
(WebCore::itemKVOProperties):
(-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulespluginsQuickTimePluginReplacementh">trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h</a></li>
<li><a href="#trunkSourceWebCoreModulespluginsQuickTimePluginReplacementidl">trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl</a></li>
<li><a href="#trunkSourceWebCoreModulespluginsQuickTimePluginReplacementjs">trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsMediaPlayercpp">trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsMediaPlayerh">trunk/Source/WebCore/platform/graphics/MediaPlayer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsMediaPlayerPrivateh">trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateAVFoundationObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateAVFoundationObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreModulespluginsQuickTimePluginReplacementmm">trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.mm</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreModulespluginsQuickTimePluginReplacementcpp">trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/ChangeLog        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -1,3 +1,57 @@
</span><ins>+2014-04-03 Eric Carlson <eric.carlson@apple.com>
+
+ [iOS] add missing QuickTime plug-in replacement API
+ https://bugs.webkit.org/show_bug.cgi?id=131042
+
+ Reviewed by Dean Jackson.
+
+ Rename QuickTimePluginReplacement.cpp to QuickTimePluginReplacement.mm to make it possible
+ to use the ObjC JSC API.
+ * Modules/plugins/QuickTimePluginReplacement.cpp:
+ * Modules/plugins/QuickTimePluginReplacement.h:
+ (WebCore::QuickTimePluginReplacement::parentElement):
+ * Modules/plugins/QuickTimePluginReplacement.idl:
+
+ * Modules/plugins/QuickTimePluginReplacement.js:
+ (Replacement.prototype.timedMetadataUpdates): Implement.
+ (Replacement.prototype.accessLog): Ditto.
+ (Replacement.prototype.errorLog): Ditto.
+
+ Use the JSC ObjC API to create a JavaScript object from an array of AVMetadataItems. The
+ JSC ObjC API supports basic NSTypes, but an AVMetadataItem can also contain NSData which
+ the existing plug-in returns as base-64 encoded data, so create wrappers for NSDictionary
+ and NSArray.
+ * Modules/plugins/QuickTimePluginReplacement.mm: Copied from Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp.
+ (WebCore::QuickTimePluginReplacement::ensureReplacementScriptInjected): Disambiguate with "JSC::"
+ (WebCore::QuickTimePluginReplacement::installReplacement): Ditto.
+ (WebCore::jsValueWithDataInContext): Create JSValue* from NSData.
+ (WebCore::jsValueWithArrayInContext): Create JSValue* from NSArray.
+ (WebCore::jsValueWithDictionaryInContext): Create JSValue* from NSDictionary.
+ (WebCore::jsValueWithValueInContext): Create JSValue* from basic NSTypes plus AVMetadataItem
+ and NSData.
+ (WebCore::jsValueWithAVMetadataItemInContext): Create JSValue* from AVMetadataItem.
+ (WebCore::JSQuickTimePluginReplacement::timedMetaData): Script interface.
+ (WebCore::JSQuickTimePluginReplacement::accessLog): Ditto.
+ (WebCore::JSQuickTimePluginReplacement::errorLog): Ditto.
+
+ * WebCore.xcodeproj/project.pbxproj: QuickTimePluginReplacement.cpp -> QuickTimePluginReplacement.mm.
+
+ * platform/graphics/MediaPlayer.cpp:
+ (WebCore::MediaPlayer::timedMetadata): iOS only accessor.
+ (WebCore::MediaPlayer::accessLog): Ditto.
+ (WebCore::MediaPlayer::errorLog): Ditto.
+ * platform/graphics/MediaPlayer.h:
+ * platform/graphics/MediaPlayerPrivate.h:
+
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::timedMetadata):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::accessLog):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::errorLog):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::metadataDidArrive):
+ (WebCore::itemKVOProperties):
+ (-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]):
+
</ins><span class="cx"> 2014-04-03 Andrei Bucur <abucur@adobe.com>
</span><span class="cx">
</span><span class="cx"> [CSS Regions] Include region range information when printing the render tree
</span></span></pre></div>
<a id="trunkSourceWebCoreModulespluginsQuickTimePluginReplacementcpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -1,237 +0,0 @@
</span><del>-/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#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 "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()
-{
- DEPRECATED_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"
- };
- DEPRECATED_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"
- };
- DEPRECATED_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;
-}
-
-RenderPtr<RenderElement> QuickTimePluginReplacement::createElementRenderer(HTMLPlugInElement& plugin, PassRef<RenderStyle> style)
-{
- ASSERT_UNUSED(plugin, m_parentElement == &plugin);
-
- if (m_mediaElement)
- return m_mediaElement->createElementRenderer(std::move(style));
-
- return nullptr;
-}
-
-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
</del></span></pre></div>
<a id="trunkSourceWebCoreModulespluginsQuickTimePluginReplacementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.h        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -55,6 +55,8 @@
</span><span class="cx"> virtual bool willCreateRenderer() override { return m_mediaElement; }
</span><span class="cx"> virtual RenderPtr<RenderElement> createElementRenderer(HTMLPlugInElement&, PassRef<RenderStyle>) override;
</span><span class="cx">
</span><ins>+ HTMLVideoElement* parentElement() { return m_mediaElement.get(); }
+
</ins><span class="cx"> unsigned long long movieSize() const;
</span><span class="cx"> void postEvent(const String&);
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreModulespluginsQuickTimePluginReplacementidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.idl        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -29,5 +29,8 @@
</span><span class="cx"> JSGenerateToJSObject,
</span><span class="cx"> ] interface QuickTimePluginReplacement {
</span><span class="cx"> readonly attribute unsigned long long movieSize;
</span><ins>+ [CustomGetter] readonly attribute any timedMetaData;
+ [CustomGetter] readonly attribute any accessLog;
+ [CustomGetter] readonly attribute any errorLog;
</ins><span class="cx"> void postEvent(DOMString eventName);
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulespluginsQuickTimePluginReplacementjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.js        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -322,19 +322,28 @@
</span><span class="cx">
</span><span class="cx"> timedMetadataUpdates: function()
</span><span class="cx"> {
</span><del>- // FIXME: not implemented yet.
</del><ins>+ try {
+ return this.host.timedMetaData;
+ } catch(e) { }
+
</ins><span class="cx"> return null;
</span><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> accessLog: function()
</span><span class="cx"> {
</span><del>- // FIXME: not implemented yet.
</del><ins>+ try {
+ return this.host.accessLog;
+ } catch(e) { }
+
</ins><span class="cx"> return null;
</span><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> errorLog: function()
</span><span class="cx"> {
</span><del>- // FIXME: not implemented yet.
</del><ins>+ try {
+ return this.host.errorLog;
+ } catch(e) { }
+
</ins><span class="cx"> return null;
</span><span class="cx"> },
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulespluginsQuickTimePluginReplacementmmfromrev166649trunkSourceWebCoreModulespluginsQuickTimePluginReplacementcpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.mm (from rev 166649, trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.cpp) (0 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.mm         (rev 0)
+++ trunk/Source/WebCore/Modules/plugins/QuickTimePluginReplacement.mm        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -0,0 +1,442 @@
</span><ins>+/*
+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if ENABLE(MEDIA_CONTROLS_SCRIPT)
+
+#import "QuickTimePluginReplacement.h"
+
+#import "Event.h"
+#import "HTMLPlugInElement.h"
+#import "HTMLVideoElement.h"
+#import "JSDOMBinding.h"
+#import "JSDOMGlobalObject.h"
+#import "JSHTMLVideoElement.h"
+#import "JSQuickTimePluginReplacement.h"
+#import "Logging.h"
+#import "MainFrame.h"
+#import "Page.h"
+#import "RenderElement.h"
+#import "ScriptController.h"
+#import "ScriptSourceCode.h"
+#import "SoftLinking.h"
+#import "UserAgentScripts.h"
+#import <objc/runtime.h>
+#import <AVFoundation/AVFoundation.h>
+#import <CoreMedia/CoreMedia.h>
+#import <Foundation/NSString.h>
+#import <JavaScriptCore/JavaScriptCore.h>
+#import <JavaScriptCore/APICast.h>
+#import <wtf/text/Base64.h>
+
+SOFT_LINK_FRAMEWORK_OPTIONAL(CoreMedia)
+SOFT_LINK(CoreMedia, CMTimeCopyAsDictionary, CFDictionaryRef, (CMTime time, CFAllocatorRef allocator), (time, allocator))
+
+typedef AVMetadataItem AVMetadataItemType;
+SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
+SOFT_LINK_CLASS(AVFoundation, AVMetadataItem)
+#define AVMetadataItem getAVMetadataItemClass()
+
+namespace WebCore {
+
+#if PLATFORM(IOS)
+static JSValue *jsValueWithValueInContext(id, JSContext *);
+static JSValue *jsValueWithAVMetadataItemInContext(AVMetadataItemType *, JSContext *);
+#endif
+
+static String quickTimePluginReplacementScript()
+{
+ DEPRECATED_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"
+ };
+ DEPRECATED_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"
+ };
+ DEPRECATED_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;
+}
+
+RenderPtr<RenderElement> QuickTimePluginReplacement::createElementRenderer(HTMLPlugInElement& plugin, PassRef<RenderStyle> style)
+{
+ ASSERT_UNUSED(plugin, m_parentElement == &plugin);
+
+ if (m_mediaElement)
+ return m_mediaElement->createElementRenderer(std::move(style));
+
+ return nullptr;
+}
+
+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 = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(world));
+ JSC::ExecState* exec = globalObject->globalExec();
+
+ JSC::JSValue replacementFunction = globalObject->get(exec, JSC::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 = JSC::jsCast<JSDOMGlobalObject*>(scriptController.globalObject(world));
+ JSC::ExecState* exec = globalObject->globalExec();
+ JSC::JSLockHolder lock(exec);
+
+ // Lookup the "createPluginReplacement" function.
+ JSC::JSValue replacementFunction = globalObject->get(exec, JSC::Identifier(exec, "createPluginReplacement"));
+ if (replacementFunction.isUndefinedOrNull())
+ return false;
+ JSC::JSObject* replacementObject = replacementFunction.toObject(exec);
+ JSC::CallData callData;
+ JSC::CallType callType = replacementObject->methodTable()->getCallData(replacementObject, callData);
+ if (callType == JSC::CallTypeNone)
+ return false;
+
+ JSC::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));
+ JSC::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.
+ JSC::JSValue value = replacement.get(exec, JSC::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, JSC::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());
+}
+
+#if PLATFORM(IOS)
+static JSValue *jsValueWithDataInContext(NSData *data, const String& mimeType, JSContext *context)
+{
+ Vector<char> base64Data;
+ base64Encode([data bytes], [data length], base64Data);
+
+ String data64;
+ if (!mimeType.isEmpty())
+ data64 = "data:" + mimeType + ";base64," + base64Data;
+ else
+ data64 = "data:text/plain;base64," + base64Data;
+
+ return [JSValue valueWithObject:(id)data64.createCFString().get() inContext:context];
+}
+
+static JSValue *jsValueWithArrayInContext(NSArray *array, JSContext *context)
+{
+ JSValueRef exception = 0;
+ JSValue *result = [JSValue valueWithNewArrayInContext:context];
+ JSObjectRef resultObject = JSValueToObject([context JSGlobalContextRef], [result JSValueRef], &exception);
+ if (exception)
+ return [JSValue valueWithUndefinedInContext:context];
+
+ NSUInteger count = [array count];
+ for (NSUInteger i = 0; i < count; ++i) {
+ JSValue *value = jsValueWithValueInContext([array objectAtIndex:i], context);
+ if (!value)
+ continue;
+
+ JSObjectSetPropertyAtIndex([context JSGlobalContextRef], resultObject, (unsigned)i, [value JSValueRef], &exception);
+ if (exception)
+ continue;
+ }
+
+ return result;
+}
+
+
+static JSValue *jsValueWithDictionaryInContext(NSDictionary *dictionary, JSContext *context)
+{
+ JSValueRef exception = 0;
+ JSValue *result = [JSValue valueWithNewObjectInContext:context];
+ JSObjectRef resultObject = JSValueToObject([context JSGlobalContextRef], [result JSValueRef], &exception);
+ if (exception)
+ return [JSValue valueWithUndefinedInContext:context];
+
+ for (id key in [dictionary keyEnumerator]) {
+ if (![key isKindOfClass:[NSString class]])
+ continue;
+
+ JSValue *value = jsValueWithValueInContext([dictionary objectForKey:key], context);
+ if (!value)
+ continue;
+
+ JSStringRef name = JSStringCreateWithCFString((CFStringRef)key);
+ JSObjectSetProperty([context JSGlobalContextRef], resultObject, name, [value JSValueRef], 0, &exception);
+ if (exception)
+ continue;
+ }
+
+ return result;
+}
+
+static JSValue *jsValueWithValueInContext(id value, JSContext *context)
+{
+ if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]])
+ return [JSValue valueWithObject:value inContext:context];
+ else if ([value isKindOfClass:[NSLocale class]])
+ return [JSValue valueWithObject:[value localeIdentifier] inContext:context];
+ else if ([value isKindOfClass:[NSDictionary class]])
+ return jsValueWithDictionaryInContext(value, context);
+ else if ([value isKindOfClass:[NSArray class]])
+ return jsValueWithArrayInContext(value, context);
+ else if ([value isKindOfClass:[NSData class]])
+ return jsValueWithDataInContext(value, emptyString(), context);
+ else if ([value isKindOfClass:[AVMetadataItem class]])
+ return jsValueWithAVMetadataItemInContext(value, context);
+
+ return nil;
+}
+
+static JSValue *jsValueWithAVMetadataItemInContext(AVMetadataItemType *item, JSContext *context)
+{
+ NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:[item extraAttributes]];
+
+ if (item.keySpace)
+ [dictionary setObject:item.keySpace forKey:@"keyspace"];
+
+ if (item.key)
+ [dictionary setObject:item.key forKey:@"key"];
+
+ if (item.locale)
+ [dictionary setObject:item.locale forKey:@"locale"];
+
+ if (CMTIME_IS_VALID(item.time)) {
+ CFDictionaryRef timeDict = CMTimeCopyAsDictionary(item.time, kCFAllocatorDefault);
+
+ if (timeDict) {
+ [dictionary setObject:(id)timeDict forKey:@"timestamp"];
+ CFRelease(timeDict);
+ }
+ }
+
+ if (item.value) {
+ id value = item.value;
+ NSString *mimeType = [[item extraAttributes] objectForKey:@"MIMEtype"];
+ if ([value isKindOfClass:[NSData class]] && mimeType) {
+ Vector<char> base64Data;
+ base64Encode([value bytes], [value length], base64Data);
+ String data64 = "data:" + String(mimeType) + ";base64," + base64Data;
+ [dictionary setObject:(id)data64.createCFString().get() forKey:@"value"];
+ } else
+ [dictionary setObject:value forKey:@"value"];
+ }
+
+ return jsValueWithDictionaryInContext(dictionary, context);
+}
+#endif
+
+JSC::JSValue JSQuickTimePluginReplacement::timedMetaData(JSC::ExecState* exec) const
+{
+#if PLATFORM(IOS)
+ HTMLVideoElement* parent = impl().parentElement();
+ if (!parent || !parent->player())
+ return JSC::jsNull();
+
+ Frame* frame = parent->document().frame();
+ if (!frame)
+ return JSC::jsNull();
+
+ NSArray *metaData = parent->player()->timedMetadata();
+ if (!metaData)
+ return JSC::jsNull();
+
+ JSContext *jsContext = frame->script().javaScriptContext();
+ JSValue *metaDataValue = jsValueWithValueInContext(metaData, jsContext);
+
+ return toJS(exec, [metaDataValue JSValueRef]);
+#else
+ UNUSED_PARAM(exec);
+ return JSC::jsNull();
+#endif
+}
+
+JSC::JSValue JSQuickTimePluginReplacement::accessLog(JSC::ExecState* exec) const
+{
+#if PLATFORM(IOS)
+ HTMLVideoElement* parent = impl().parentElement();
+ if (!parent || !parent->player())
+ return JSC::jsNull();
+
+ Frame* frame = parent->document().frame();
+ if (!frame)
+ return JSC::jsNull();
+
+ JSValue *dictionary = [JSValue valueWithNewObjectInContext:frame->script().javaScriptContext()];
+ String accessLogString = parent->player()->accessLog();
+ [dictionary setValue:static_cast<NSString *>(accessLogString) forProperty:(NSString *)CFSTR("extendedLog")];
+
+ return toJS(exec, [dictionary JSValueRef]);
+#else
+ UNUSED_PARAM(exec);
+ return JSC::jsNull();
+#endif
+}
+
+JSC::JSValue JSQuickTimePluginReplacement::errorLog(JSC::ExecState* exec) const
+{
+#if PLATFORM(IOS)
+ HTMLVideoElement* parent = impl().parentElement();
+ if (!parent || !parent->player())
+ return JSC::jsNull();
+
+ Frame* frame = parent->document().frame();
+ if (!frame)
+ return JSC::jsNull();
+
+ JSValue *dictionary = [JSValue valueWithNewObjectInContext:frame->script().javaScriptContext()];
+ String errorLogString = parent->player()->errorLog();
+ [dictionary setValue:static_cast<NSString *>(errorLogString) forProperty:(NSString *)CFSTR("extendedLog")];
+
+ return toJS(exec, [dictionary JSValueRef]);
+#else
+ UNUSED_PARAM(exec);
+ return JSC::jsNull();
+#endif
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -149,7 +149,7 @@
</span><span class="cx">                 07277E5417D018CC0015534D /* JSMediaStreamTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07277E4817D018CC0015534D /* JSMediaStreamTrackEvent.cpp */; };
</span><span class="cx">                 07277E5517D018CC0015534D /* JSMediaStreamTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1DF183C0741000A5988 /* PluginReplacement.h */; };
</span><del>-                072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */; };
</del><ins>+                072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.mm */; };
</ins><span class="cx">                 072AE1E8183C0741000A5988 /* QuickTimePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */; };
</span><span class="cx">                 072C8B11131C518600A4FCE9 /* MediaPlayerPrivateAVFoundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076F0D0912B8192700C26AA4 /* MediaPlayerPrivateAVFoundation.cpp */; };
</span><span class="cx">                 072CA86116CB4DC3008AE131 /* CaptionUserPreferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 072CA86016CB4DC3008AE131 /* CaptionUserPreferences.cpp */; };
</span><span class="lines">@@ -7021,7 +7021,7 @@
</span><span class="cx">                 0729B14E17CFCCA0004F1D60 /* MediaStreamCenterMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaStreamCenterMac.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 0729B14F17CFCCA0004F1D60 /* MediaStreamCenterMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaStreamCenterMac.h; sourceTree = "<group>"; };
</span><span class="cx">                 072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PluginReplacement.h; path = plugins/PluginReplacement.h; sourceTree = "<group>"; };
</span><del>-                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QuickTimePluginReplacement.cpp; path = plugins/QuickTimePluginReplacement.cpp; sourceTree = "<group>"; };
</del><ins>+                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = QuickTimePluginReplacement.mm; path = plugins/QuickTimePluginReplacement.mm; sourceTree = "<group>"; };
</ins><span class="cx">                 072AE1E1183C0741000A5988 /* QuickTimePluginReplacement.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = QuickTimePluginReplacement.css; path = plugins/QuickTimePluginReplacement.css; sourceTree = "<group>"; };
</span><span class="cx">                 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QuickTimePluginReplacement.h; path = plugins/QuickTimePluginReplacement.h; sourceTree = "<group>"; };
</span><span class="cx">                 072AE1E3183C0741000A5988 /* QuickTimePluginReplacement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = QuickTimePluginReplacement.idl; path = plugins/QuickTimePluginReplacement.idl; sourceTree = "<group>"; };
</span><span class="lines">@@ -14282,7 +14282,7 @@
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><span class="cx">                                 072AE1DF183C0741000A5988 /* PluginReplacement.h */,
</span><del>-                                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */,
</del><ins>+                                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.mm */,
</ins><span class="cx">                                 072AE1E1183C0741000A5988 /* QuickTimePluginReplacement.css */,
</span><span class="cx">                                 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */,
</span><span class="cx">                                 072AE1E3183C0741000A5988 /* QuickTimePluginReplacement.idl */,
</span><span class="lines">@@ -28599,7 +28599,7 @@
</span><span class="cx">                                 E4D687770ED7AE3D006EA978 /* PurgeableBufferMac.cpp in Sources */,
</span><span class="cx">                                 550A0BC9085F6039007353D6 /* QualifiedName.cpp in Sources */,
</span><span class="cx">                                 442AF7AA102CDDEA008FD4D3 /* QuickLook.mm in Sources */,
</span><del>-                                072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.cpp in Sources */,
</del><ins>+                                072AE1E6183C0741000A5988 /* QuickTimePluginReplacement.mm in Sources */,
</ins><span class="cx">                                 379E371613736A6600B9E919 /* QuotedPrintable.cpp in Sources */,
</span><span class="cx">                                 5A574F28131DB96D00471B88 /* QuotesData.cpp in Sources */,
</span><span class="cx">                                 F55B3DCB1251F12D003EF269 /* RadioInputType.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsMediaPlayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -640,6 +640,21 @@
</span><span class="cx"> {
</span><span class="cx"> m_private->setVideoFullscreenGravity(gravity);
</span><span class="cx"> }
</span><ins>+
+NSArray* MediaPlayer::timedMetadata() const
+{
+ return m_private->timedMetadata();
+}
+
+String MediaPlayer::accessLog() const
+{
+ return m_private->accessLog();
+}
+
+String MediaPlayer::errorLog() const
+{
+ return m_private->errorLog();
+}
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> MediaPlayer::NetworkState MediaPlayer::networkState()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsMediaPlayerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx">
</span><span class="cx"> OBJC_CLASS AVAsset;
</span><span class="cx"> OBJC_CLASS AVPlayer;
</span><ins>+OBJC_CLASS NSArray;
</ins><span class="cx"> OBJC_CLASS QTMovie;
</span><span class="cx">
</span><span class="cx"> class AVCFPlayer;
</span><span class="lines">@@ -308,7 +309,12 @@
</span><span class="cx"> void setVideoFullscreenFrame(FloatRect);
</span><span class="cx"> enum VideoGravity { VideoGravityResize, VideoGravityResizeAspect, VideoGravityResizeAspectFill };
</span><span class="cx"> void setVideoFullscreenGravity(VideoGravity);
</span><ins>+
+ NSArray *timedMetadata() const;
+ String accessLog() const;
+ String errorLog() const;
</ins><span class="cx"> #endif
</span><ins>+
</ins><span class="cx"> IntSize naturalSize();
</span><span class="cx"> bool hasVideo() const;
</span><span class="cx"> bool hasAudio() const;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsMediaPlayerPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -58,7 +58,12 @@
</span><span class="cx"> virtual void setVideoFullscreenLayer(PlatformLayer*) { }
</span><span class="cx"> virtual void setVideoFullscreenFrame(FloatRect) { }
</span><span class="cx"> virtual void setVideoFullscreenGravity(MediaPlayer::VideoGravity) { }
</span><ins>+
+ virtual NSArray *timedMetadata() const { return 0; }
+ virtual String accessLog() const { return emptyString(); }
+ virtual String errorLog() const { return emptyString(); }
</ins><span class="cx"> #endif
</span><ins>+
</ins><span class="cx"> virtual void play() = 0;
</span><span class="cx"> virtual void pause() = 0;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateAVFoundationObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -108,6 +108,7 @@
</span><span class="cx"> void presentationSizeDidChange(FloatSize);
</span><span class="cx"> void durationDidChange(double);
</span><span class="cx"> void rateDidChange(double);
</span><ins>+ void metadataDidArrive(RetainPtr<NSArray>);
</ins><span class="cx">
</span><span class="cx"> #if HAVE(AVFOUNDATION_VIDEO_OUTPUT)
</span><span class="cx"> void outputMediaDataWillChange(AVPlayerItemVideoOutput*);
</span><span class="lines">@@ -152,7 +153,12 @@
</span><span class="cx"> virtual void setVideoFullscreenLayer(PlatformLayer*);
</span><span class="cx"> virtual void setVideoFullscreenFrame(FloatRect);
</span><span class="cx"> virtual void setVideoFullscreenGravity(MediaPlayer::VideoGravity);
</span><ins>+
+ virtual NSArray *timedMetadata() const override;
+ virtual String accessLog() const;
+ virtual String errorLog() const;
</ins><span class="cx"> #endif
</span><ins>+
</ins><span class="cx"> virtual bool supportsAcceleratedRendering() const { return true; }
</span><span class="cx"> virtual float mediaTimeForTimeValue(float) const;
</span><span class="cx"> virtual double maximumDurationToCacheMediaTime() const { return 5; }
</span><span class="lines">@@ -301,6 +307,7 @@
</span><span class="cx"> mutable RetainPtr<NSArray> m_cachedSeekableRanges;
</span><span class="cx"> mutable RetainPtr<NSArray> m_cachedLoadedRanges;
</span><span class="cx"> RetainPtr<NSArray> m_cachedTracks;
</span><ins>+ RetainPtr<NSArray> m_currentMetaData;
</ins><span class="cx"> FloatSize m_cachedPresentationSize;
</span><span class="cx"> double m_cachedDuration;
</span><span class="cx"> double m_cachedRate;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateAVFoundationObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (166718 => 166719)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm        2014-04-03 15:33:11 UTC (rev 166718)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm        2014-04-03 15:46:05 UTC (rev 166719)
</span><span class="lines">@@ -98,6 +98,8 @@
</span><span class="cx"> @end
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+typedef AVMetadataItem AVMetadataItemType;
+
</ins><span class="cx"> SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
</span><span class="cx"> SOFT_LINK_FRAMEWORK_OPTIONAL(CoreMedia)
</span><span class="cx"> SOFT_LINK_FRAMEWORK_OPTIONAL(CoreImage)
</span><span class="lines">@@ -132,6 +134,8 @@
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVPlayerLayer)
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVURLAsset)
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVAssetImageGenerator)
</span><ins>+SOFT_LINK_CLASS(AVFoundation, AVMetadataItem)
+
</ins><span class="cx"> SOFT_LINK_CLASS(CoreImage, CIContext)
</span><span class="cx"> SOFT_LINK_CLASS(CoreImage, CIImage)
</span><span class="cx">
</span><span class="lines">@@ -156,6 +160,7 @@
</span><span class="cx"> #define AVPlayerLayer getAVPlayerLayerClass()
</span><span class="cx"> #define AVURLAsset getAVURLAssetClass()
</span><span class="cx"> #define AVAssetImageGenerator getAVAssetImageGeneratorClass()
</span><ins>+#define AVMetadataItem getAVMetadataItemClass()
</ins><span class="cx">
</span><span class="cx"> #define AVMediaCharacteristicVisual getAVMediaCharacteristicVisual()
</span><span class="cx"> #define AVMediaCharacteristicAudible getAVMediaCharacteristicAudible()
</span><span class="lines">@@ -847,6 +852,35 @@
</span><span class="cx">
</span><span class="cx"> [m_videoLayer setVideoGravity:videoGravity];
</span><span class="cx"> }
</span><ins>+
+NSArray *MediaPlayerPrivateAVFoundationObjC::timedMetadata() const
+{
+ if (m_currentMetaData)
+ return m_currentMetaData.get();
+ return nil;
+}
+
+String MediaPlayerPrivateAVFoundationObjC::accessLog() const
+{
+ if (!m_avPlayerItem)
+ return emptyString();
+
+ AVPlayerItemAccessLog *log = [m_avPlayerItem.get() accessLog];
+ RetainPtr<NSString> logString = adoptNS([[NSString alloc] initWithData:[log extendedLogData] encoding:[log extendedLogDataStringEncoding]]);
+
+ return logString.get();
+}
+
+String MediaPlayerPrivateAVFoundationObjC::errorLog() const
+{
+ if (!m_avPlayerItem)
+ return emptyString();
+
+ AVPlayerItemErrorLog *log = [m_avPlayerItem.get() errorLog];
+ RetainPtr<NSString> logString = adoptNS([[NSString alloc] initWithData:[log extendedLogData] encoding:[log extendedLogDataStringEncoding]]);
+
+ return logString.get();
+}
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> void MediaPlayerPrivateAVFoundationObjC::platformSetVisible(bool isVisible)
</span><span class="lines">@@ -2192,6 +2226,14 @@
</span><span class="cx"> updateStates();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void MediaPlayerPrivateAVFoundationObjC::metadataDidArrive(RetainPtr<NSArray> metadata)
+{
+ if (!metadata || [metadata isKindOfClass:[NSNull class]])
+ return;
+
+ m_currentMetaData = metadata;
+}
+
</ins><span class="cx"> void MediaPlayerPrivateAVFoundationObjC::tracksDidChange(RetainPtr<NSArray> tracks)
</span><span class="cx"> {
</span><span class="cx"> m_cachedTracks = tracks;
</span><span class="lines">@@ -2270,6 +2312,7 @@
</span><span class="cx"> @"playbackBufferEmpty",
</span><span class="cx"> @"duration",
</span><span class="cx"> @"hasEnabledAudio",
</span><ins>+ @"timedMetadata",
</ins><span class="cx"> nil];
</span><span class="cx"> }
</span><span class="cx"> return keys;
</span><span class="lines">@@ -2357,6 +2400,8 @@
</span><span class="cx"> function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::presentationSizeDidChange, m_callback, FloatSize([newValue sizeValue]));
</span><span class="cx"> else if ([keyPath isEqualToString:@"duration"])
</span><span class="cx"> function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::durationDidChange, m_callback, CMTimeGetSeconds([newValue CMTimeValue]));
</span><ins>+ else if ([keyPath isEqualToString:@"timedMetadata"] && newValue)
+ function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::metadataDidArrive, m_callback, RetainPtr<NSArray>(newValue));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (context == MediaPlayerAVFoundationObservationContextPlayer && !willChange) {
</span></span></pre>
</div>
</div>
</body>
</html>