<!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 &quot;JSC::&quot;
(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 -&gt; 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  &lt;eric.carlson@apple.com&gt;
+
+        [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 &quot;JSC::&quot;
+        (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 -&gt; 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  &lt;abucur@adobe.com&gt;
</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 &quot;config.h&quot;
-
-#if ENABLE(MEDIA_CONTROLS_SCRIPT)
-
-#include &quot;QuickTimePluginReplacement.h&quot;
-
-#include &quot;Event.h&quot;
-#include &quot;HTMLPlugInElement.h&quot;
-#include &quot;HTMLVideoElement.h&quot;
-#include &quot;JSDOMBinding.h&quot;
-#include &quot;JSDOMGlobalObject.h&quot;
-#include &quot;JSHTMLVideoElement.h&quot;
-#include &quot;JSQuickTimePluginReplacement.h&quot;
-#include &quot;Logging.h&quot;
-#include &quot;MainFrame.h&quot;
-#include &quot;Page.h&quot;
-#include &quot;RenderElement.h&quot;
-#include &quot;ScriptController.h&quot;
-#include &quot;ScriptSourceCode.h&quot;
-#include &quot;UserAgentScripts.h&quot;
-#include &lt;JavaScriptCore/APICast.h&gt;
-#include &lt;JavaScriptCore/JSBase.h&gt;
-#include &lt;JavaScriptCore/JSCJSValueInlines.h&gt;
-
-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&lt;PluginReplacement&gt; QuickTimePluginReplacement::create(HTMLPlugInElement&amp; plugin, const Vector&lt;String&gt;&amp; paramNames, const Vector&lt;String&gt;&amp; paramValues)
-{
-    return adoptRef(new QuickTimePluginReplacement(plugin, paramNames, paramValues));
-}
-
-bool QuickTimePluginReplacement::supportsMimeType(const String&amp; mimeType)
-{
-    static const char* types[] = {
-        &quot;application/vnd.apple.mpegurl&quot;, &quot;application/x-mpegurl&quot;, &quot;audio/3gpp&quot;, &quot;audio/3gpp2&quot;, &quot;audio/aac&quot;, &quot;audio/aiff&quot;,
-        &quot;audio/amr&quot;, &quot;audio/basic&quot;, &quot;audio/mp3&quot;, &quot;audio/mp4&quot;, &quot;audio/mpeg&quot;, &quot;audio/mpeg3&quot;, &quot;audio/mpegurl&quot;, &quot;audio/scpls&quot;,
-        &quot;audio/wav&quot;, &quot;audio/x-aac&quot;, &quot;audio/x-aiff&quot;, &quot;audio/x-caf&quot;, &quot;audio/x-m4a&quot;, &quot;audio/x-m4b&quot;, &quot;audio/x-m4p&quot;,
-        &quot;audio/x-m4r&quot;, &quot;audio/x-mp3&quot;, &quot;audio/x-mpeg&quot;, &quot;audio/x-mpeg3&quot;, &quot;audio/x-mpegurl&quot;, &quot;audio/x-scpls&quot;, &quot;audio/x-wav&quot;,
-        &quot;video/3gpp&quot;, &quot;video/3gpp2&quot;, &quot;video/mp4&quot;, &quot;video/quicktime&quot;, &quot;video/x-m4v&quot;
-    };
-    DEPRECATED_DEFINE_STATIC_LOCAL(HashSet&lt;String&gt;, typeHash, ());
-    if (!typeHash.size()) {
-        for (size_t i = 0; i &lt; WTF_ARRAY_LENGTH(types); ++i)
-            typeHash.add(types[i]);
-    }
-
-    return typeHash.contains(mimeType);
-}
-
-bool QuickTimePluginReplacement::supportsFileExtension(const String&amp; extension)
-{
-    static const char* extensions[] = {
-        &quot;3g2&quot;, &quot;3gp&quot;, &quot;3gp2&quot;, &quot;3gpp&quot;, &quot;aac&quot;, &quot;adts&quot;, &quot;aif&quot;, &quot;aifc&quot;, &quot;aiff&quot;, &quot;AMR&quot;, &quot;au&quot;, &quot;bwf&quot;, &quot;caf&quot;, &quot;cdda&quot;, &quot;m3u&quot;,
-        &quot;m3u8&quot;, &quot;m4a&quot;, &quot;m4b&quot;, &quot;m4p&quot;, &quot;m4r&quot;, &quot;m4v&quot;, &quot;mov&quot;, &quot;mp3&quot;, &quot;mp3&quot;, &quot;mp4&quot;, &quot;mpeg&quot;, &quot;mpg&quot;, &quot;mqv&quot;, &quot;pls&quot;, &quot;qt&quot;,
-        &quot;snd&quot;, &quot;swa&quot;, &quot;ts&quot;, &quot;ulw&quot;, &quot;wav&quot;
-    };
-    DEPRECATED_DEFINE_STATIC_LOCAL(HashSet&lt;String&gt;, extensionHash, ());
-    if (!extensionHash.size()) {
-        for (size_t i = 0; i &lt; WTF_ARRAY_LENGTH(extensions); ++i)
-            extensionHash.add(extensions[i]);
-    }
-
-    return extensionHash.contains(extension);
-}
-
-QuickTimePluginReplacement::QuickTimePluginReplacement(HTMLPlugInElement&amp; plugin, const Vector&lt;String&gt;&amp; paramNames, const Vector&lt;String&gt;&amp; paramValues)
-    :PluginReplacement()
-    , m_parentElement(&amp;plugin)
-    , m_names(paramNames)
-    , m_values(paramValues)
-    , m_scriptObject(nullptr)
-{
-}
-
-QuickTimePluginReplacement::~QuickTimePluginReplacement()
-{
-    m_parentElement = nullptr;
-    m_scriptObject = nullptr;
-    m_mediaElement = nullptr;
-}
-
-RenderPtr&lt;RenderElement&gt; QuickTimePluginReplacement::createElementRenderer(HTMLPlugInElement&amp; plugin, PassRef&lt;RenderStyle&gt; style)
-{
-    ASSERT_UNUSED(plugin, m_parentElement == &amp;plugin);
-
-    if (m_mediaElement)
-        return m_mediaElement-&gt;createElementRenderer(std::move(style));
-
-    return nullptr;
-}
-
-DOMWrapperWorld&amp; QuickTimePluginReplacement::isolatedWorld()
-{
-    static DOMWrapperWorld&amp; isolatedWorld = *DOMWrapperWorld::create(JSDOMWindow::commonVM()).leakRef();
-    return isolatedWorld;
-}
-
-bool QuickTimePluginReplacement::ensureReplacementScriptInjected()
-{
-    Page* page = m_parentElement-&gt;document().page();
-    if (!page)
-        return false;
-    
-    DOMWrapperWorld&amp; world = isolatedWorld();
-    ScriptController&amp; scriptController = page-&gt;mainFrame().script();
-    JSDOMGlobalObject* globalObject = jsCast&lt;JSDOMGlobalObject*&gt;(scriptController.globalObject(world));
-    ExecState* exec = globalObject-&gt;globalExec();
-    
-    JSValue replacementFunction = globalObject-&gt;get(exec, Identifier(exec, &quot;createPluginReplacement&quot;));
-    if (replacementFunction.isFunction())
-        return true;
-    
-    scriptController.evaluateInWorld(ScriptSourceCode(quickTimePluginReplacementScript()), world);
-    if (exec-&gt;hadException()) {
-        LOG(Plugins, &quot;%p - Exception when evaluating QuickTime plugin replacement script&quot;, this);
-        exec-&gt;clearException();
-        return false;
-    }
-    
-    return true;
-}
-
-bool QuickTimePluginReplacement::installReplacement(ShadowRoot* root)
-{
-    Page* page = m_parentElement-&gt;document().page();
-
-    if (!ensureReplacementScriptInjected())
-        return false;
-
-    DOMWrapperWorld&amp; world = isolatedWorld();
-    ScriptController&amp; scriptController = page-&gt;mainFrame().script();
-    JSDOMGlobalObject* globalObject = jsCast&lt;JSDOMGlobalObject*&gt;(scriptController.globalObject(world));
-    ExecState* exec = globalObject-&gt;globalExec();
-    JSLockHolder lock(exec);
-    
-    // Lookup the &quot;createPluginReplacement&quot; function.
-    JSValue replacementFunction = globalObject-&gt;get(exec, Identifier(exec, &quot;createPluginReplacement&quot;));
-    if (replacementFunction.isUndefinedOrNull())
-        return false;
-    JSObject* replacementObject = replacementFunction.toObject(exec);
-    CallData callData;
-    CallType callType = replacementObject-&gt;methodTable()-&gt;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&lt;String&gt;(exec, globalObject, m_names));
-    argList.append(toJS&lt;String&gt;(exec, globalObject, m_values));
-    JSValue replacement = call(exec, replacementObject, callType, callData, globalObject, argList);
-    if (exec-&gt;hadException()) {
-        exec-&gt;clearException();
-        return false;
-    }
-
-    // Get the &lt;video&gt; created to replace the plug-in.
-    JSValue value = replacement.get(exec, Identifier(exec, &quot;video&quot;));
-    if (!exec-&gt;hadException() &amp;&amp; !value.isUndefinedOrNull())
-        m_mediaElement = toHTMLVideoElement(value);
-
-    if (!m_mediaElement) {
-        LOG(Plugins, &quot;%p - Failed to find &lt;video&gt; element created by QuickTime plugin replacement script.&quot;, this);
-        exec-&gt;clearException();
-        return false;
-    }
-
-    // Get the scripting interface.
-    value = replacement.get(exec, Identifier(exec, &quot;scriptObject&quot;));
-    if (!exec-&gt;hadException() &amp;&amp; !value.isUndefinedOrNull())
-        m_scriptObject = value.toObject(exec);
-
-    if (!m_scriptObject) {
-        LOG(Plugins, &quot;%p - Failed to find script object created by QuickTime plugin replacement.&quot;, this);
-        exec-&gt;clearException();
-        return false;
-    }
-
-    return true;
-}
-
-unsigned long long QuickTimePluginReplacement::movieSize() const
-{
-    if (m_mediaElement)
-        return m_mediaElement-&gt;fileSize();
-
-    return 0;
-}
-
-void QuickTimePluginReplacement::postEvent(const String&amp; eventName)
-{
-    Ref&lt;HTMLPlugInElement&gt; protect(*m_parentElement);
-    RefPtr&lt;Event&gt; event = Event::create(eventName, false, true);
-    m_parentElement-&gt;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&lt;RenderElement&gt; createElementRenderer(HTMLPlugInElement&amp;, PassRef&lt;RenderStyle&gt;) 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&amp;);
</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 &quot;config.h&quot;
+
+#if ENABLE(MEDIA_CONTROLS_SCRIPT)
+
+#import &quot;QuickTimePluginReplacement.h&quot;
+
+#import &quot;Event.h&quot;
+#import &quot;HTMLPlugInElement.h&quot;
+#import &quot;HTMLVideoElement.h&quot;
+#import &quot;JSDOMBinding.h&quot;
+#import &quot;JSDOMGlobalObject.h&quot;
+#import &quot;JSHTMLVideoElement.h&quot;
+#import &quot;JSQuickTimePluginReplacement.h&quot;
+#import &quot;Logging.h&quot;
+#import &quot;MainFrame.h&quot;
+#import &quot;Page.h&quot;
+#import &quot;RenderElement.h&quot;
+#import &quot;ScriptController.h&quot;
+#import &quot;ScriptSourceCode.h&quot;
+#import &quot;SoftLinking.h&quot;
+#import &quot;UserAgentScripts.h&quot;
+#import &lt;objc/runtime.h&gt;
+#import &lt;AVFoundation/AVFoundation.h&gt;
+#import &lt;CoreMedia/CoreMedia.h&gt;
+#import &lt;Foundation/NSString.h&gt;
+#import &lt;JavaScriptCore/JavaScriptCore.h&gt;
+#import &lt;JavaScriptCore/APICast.h&gt;
+#import &lt;wtf/text/Base64.h&gt;
+
+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&lt;PluginReplacement&gt; QuickTimePluginReplacement::create(HTMLPlugInElement&amp; plugin, const Vector&lt;String&gt;&amp; paramNames, const Vector&lt;String&gt;&amp; paramValues)
+{
+    return adoptRef(new QuickTimePluginReplacement(plugin, paramNames, paramValues));
+}
+
+bool QuickTimePluginReplacement::supportsMimeType(const String&amp; mimeType)
+{
+    static const char* types[] = {
+        &quot;application/vnd.apple.mpegurl&quot;, &quot;application/x-mpegurl&quot;, &quot;audio/3gpp&quot;, &quot;audio/3gpp2&quot;, &quot;audio/aac&quot;, &quot;audio/aiff&quot;,
+        &quot;audio/amr&quot;, &quot;audio/basic&quot;, &quot;audio/mp3&quot;, &quot;audio/mp4&quot;, &quot;audio/mpeg&quot;, &quot;audio/mpeg3&quot;, &quot;audio/mpegurl&quot;, &quot;audio/scpls&quot;,
+        &quot;audio/wav&quot;, &quot;audio/x-aac&quot;, &quot;audio/x-aiff&quot;, &quot;audio/x-caf&quot;, &quot;audio/x-m4a&quot;, &quot;audio/x-m4b&quot;, &quot;audio/x-m4p&quot;,
+        &quot;audio/x-m4r&quot;, &quot;audio/x-mp3&quot;, &quot;audio/x-mpeg&quot;, &quot;audio/x-mpeg3&quot;, &quot;audio/x-mpegurl&quot;, &quot;audio/x-scpls&quot;, &quot;audio/x-wav&quot;,
+        &quot;video/3gpp&quot;, &quot;video/3gpp2&quot;, &quot;video/mp4&quot;, &quot;video/quicktime&quot;, &quot;video/x-m4v&quot;
+    };
+    DEPRECATED_DEFINE_STATIC_LOCAL(HashSet&lt;String&gt;, typeHash, ());
+    if (!typeHash.size()) {
+        for (size_t i = 0; i &lt; WTF_ARRAY_LENGTH(types); ++i)
+            typeHash.add(types[i]);
+    }
+
+    return typeHash.contains(mimeType);
+}
+
+bool QuickTimePluginReplacement::supportsFileExtension(const String&amp; extension)
+{
+    static const char* extensions[] = {
+        &quot;3g2&quot;, &quot;3gp&quot;, &quot;3gp2&quot;, &quot;3gpp&quot;, &quot;aac&quot;, &quot;adts&quot;, &quot;aif&quot;, &quot;aifc&quot;, &quot;aiff&quot;, &quot;AMR&quot;, &quot;au&quot;, &quot;bwf&quot;, &quot;caf&quot;, &quot;cdda&quot;, &quot;m3u&quot;,
+        &quot;m3u8&quot;, &quot;m4a&quot;, &quot;m4b&quot;, &quot;m4p&quot;, &quot;m4r&quot;, &quot;m4v&quot;, &quot;mov&quot;, &quot;mp3&quot;, &quot;mp3&quot;, &quot;mp4&quot;, &quot;mpeg&quot;, &quot;mpg&quot;, &quot;mqv&quot;, &quot;pls&quot;, &quot;qt&quot;,
+        &quot;snd&quot;, &quot;swa&quot;, &quot;ts&quot;, &quot;ulw&quot;, &quot;wav&quot;
+    };
+    DEPRECATED_DEFINE_STATIC_LOCAL(HashSet&lt;String&gt;, extensionHash, ());
+    if (!extensionHash.size()) {
+        for (size_t i = 0; i &lt; WTF_ARRAY_LENGTH(extensions); ++i)
+            extensionHash.add(extensions[i]);
+    }
+
+    return extensionHash.contains(extension);
+}
+
+QuickTimePluginReplacement::QuickTimePluginReplacement(HTMLPlugInElement&amp; plugin, const Vector&lt;String&gt;&amp; paramNames, const Vector&lt;String&gt;&amp; paramValues)
+    :PluginReplacement()
+    , m_parentElement(&amp;plugin)
+    , m_names(paramNames)
+    , m_values(paramValues)
+    , m_scriptObject(nullptr)
+{
+}
+
+QuickTimePluginReplacement::~QuickTimePluginReplacement()
+{
+    m_parentElement = nullptr;
+    m_scriptObject = nullptr;
+    m_mediaElement = nullptr;
+}
+
+RenderPtr&lt;RenderElement&gt; QuickTimePluginReplacement::createElementRenderer(HTMLPlugInElement&amp; plugin, PassRef&lt;RenderStyle&gt; style)
+{
+    ASSERT_UNUSED(plugin, m_parentElement == &amp;plugin);
+
+    if (m_mediaElement)
+        return m_mediaElement-&gt;createElementRenderer(std::move(style));
+
+    return nullptr;
+}
+
+DOMWrapperWorld&amp; QuickTimePluginReplacement::isolatedWorld()
+{
+    static DOMWrapperWorld&amp; isolatedWorld = *DOMWrapperWorld::create(JSDOMWindow::commonVM()).leakRef();
+    return isolatedWorld;
+}
+
+bool QuickTimePluginReplacement::ensureReplacementScriptInjected()
+{
+    Page* page = m_parentElement-&gt;document().page();
+    if (!page)
+        return false;
+    
+    DOMWrapperWorld&amp; world = isolatedWorld();
+    ScriptController&amp; scriptController = page-&gt;mainFrame().script();
+    JSDOMGlobalObject* globalObject = JSC::jsCast&lt;JSDOMGlobalObject*&gt;(scriptController.globalObject(world));
+    JSC::ExecState* exec = globalObject-&gt;globalExec();
+    
+    JSC::JSValue replacementFunction = globalObject-&gt;get(exec, JSC::Identifier(exec, &quot;createPluginReplacement&quot;));
+    if (replacementFunction.isFunction())
+        return true;
+    
+    scriptController.evaluateInWorld(ScriptSourceCode(quickTimePluginReplacementScript()), world);
+    if (exec-&gt;hadException()) {
+        LOG(Plugins, &quot;%p - Exception when evaluating QuickTime plugin replacement script&quot;, this);
+        exec-&gt;clearException();
+        return false;
+    }
+    
+    return true;
+}
+
+bool QuickTimePluginReplacement::installReplacement(ShadowRoot* root)
+{
+    Page* page = m_parentElement-&gt;document().page();
+
+    if (!ensureReplacementScriptInjected())
+        return false;
+
+    DOMWrapperWorld&amp; world = isolatedWorld();
+    ScriptController&amp; scriptController = page-&gt;mainFrame().script();
+    JSDOMGlobalObject* globalObject = JSC::jsCast&lt;JSDOMGlobalObject*&gt;(scriptController.globalObject(world));
+    JSC::ExecState* exec = globalObject-&gt;globalExec();
+    JSC::JSLockHolder lock(exec);
+    
+    // Lookup the &quot;createPluginReplacement&quot; function.
+    JSC::JSValue replacementFunction = globalObject-&gt;get(exec, JSC::Identifier(exec, &quot;createPluginReplacement&quot;));
+    if (replacementFunction.isUndefinedOrNull())
+        return false;
+    JSC::JSObject* replacementObject = replacementFunction.toObject(exec);
+    JSC::CallData callData;
+    JSC::CallType callType = replacementObject-&gt;methodTable()-&gt;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&lt;String&gt;(exec, globalObject, m_names));
+    argList.append(toJS&lt;String&gt;(exec, globalObject, m_values));
+    JSC::JSValue replacement = call(exec, replacementObject, callType, callData, globalObject, argList);
+    if (exec-&gt;hadException()) {
+        exec-&gt;clearException();
+        return false;
+    }
+
+    // Get the &lt;video&gt; created to replace the plug-in.
+    JSC::JSValue value = replacement.get(exec, JSC::Identifier(exec, &quot;video&quot;));
+    if (!exec-&gt;hadException() &amp;&amp; !value.isUndefinedOrNull())
+        m_mediaElement = toHTMLVideoElement(value);
+
+    if (!m_mediaElement) {
+        LOG(Plugins, &quot;%p - Failed to find &lt;video&gt; element created by QuickTime plugin replacement script.&quot;, this);
+        exec-&gt;clearException();
+        return false;
+    }
+
+    // Get the scripting interface.
+    value = replacement.get(exec, JSC::Identifier(exec, &quot;scriptObject&quot;));
+    if (!exec-&gt;hadException() &amp;&amp; !value.isUndefinedOrNull())
+        m_scriptObject = value.toObject(exec);
+
+    if (!m_scriptObject) {
+        LOG(Plugins, &quot;%p - Failed to find script object created by QuickTime plugin replacement.&quot;, this);
+        exec-&gt;clearException();
+        return false;
+    }
+
+    return true;
+}
+
+unsigned long long QuickTimePluginReplacement::movieSize() const
+{
+    if (m_mediaElement)
+        return m_mediaElement-&gt;fileSize();
+
+    return 0;
+}
+
+void QuickTimePluginReplacement::postEvent(const String&amp; eventName)
+{
+    Ref&lt;HTMLPlugInElement&gt; protect(*m_parentElement);
+    RefPtr&lt;Event&gt; event = Event::create(eventName, false, true);
+    m_parentElement-&gt;dispatchEvent(event.get());
+}
+
+#if PLATFORM(IOS)
+static JSValue *jsValueWithDataInContext(NSData *data, const String&amp; mimeType, JSContext *context)
+{
+    Vector&lt;char&gt; base64Data;
+    base64Encode([data bytes], [data length], base64Data);
+
+    String data64;
+    if (!mimeType.isEmpty())
+        data64 = &quot;data:&quot; + mimeType + &quot;;base64,&quot; + base64Data;
+    else
+        data64 = &quot;data:text/plain;base64,&quot; + 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], &amp;exception);
+    if (exception)
+        return [JSValue valueWithUndefinedInContext:context];
+
+    NSUInteger count = [array count];
+    for (NSUInteger i = 0; i &lt; count; ++i) {
+        JSValue *value = jsValueWithValueInContext([array objectAtIndex:i], context);
+        if (!value)
+            continue;
+
+        JSObjectSetPropertyAtIndex([context JSGlobalContextRef], resultObject, (unsigned)i, [value JSValueRef], &amp;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], &amp;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, &amp;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:@&quot;keyspace&quot;];
+
+    if (item.key)
+        [dictionary setObject:item.key forKey:@&quot;key&quot;];
+
+    if (item.locale)
+        [dictionary setObject:item.locale forKey:@&quot;locale&quot;];
+
+    if (CMTIME_IS_VALID(item.time)) {
+        CFDictionaryRef timeDict = CMTimeCopyAsDictionary(item.time, kCFAllocatorDefault);
+
+        if (timeDict) {
+            [dictionary setObject:(id)timeDict forKey:@&quot;timestamp&quot;];
+            CFRelease(timeDict);
+        }
+    }
+    
+    if (item.value) {
+        id value = item.value;
+        NSString *mimeType = [[item extraAttributes] objectForKey:@&quot;MIMEtype&quot;];
+        if ([value isKindOfClass:[NSData class]] &amp;&amp; mimeType) {
+            Vector&lt;char&gt; base64Data;
+            base64Encode([value bytes], [value length], base64Data);
+            String data64 = &quot;data:&quot; + String(mimeType) + &quot;;base64,&quot; + base64Data;
+            [dictionary setObject:(id)data64.createCFString().get() forKey:@&quot;value&quot;];
+        } else
+            [dictionary setObject:value forKey:@&quot;value&quot;];
+    }
+
+    return jsValueWithDictionaryInContext(dictionary, context);
+}
+#endif
+
+JSC::JSValue JSQuickTimePluginReplacement::timedMetaData(JSC::ExecState* exec) const
+{
+#if PLATFORM(IOS)
+    HTMLVideoElement* parent = impl().parentElement();
+    if (!parent || !parent-&gt;player())
+        return JSC::jsNull();
+
+    Frame* frame = parent-&gt;document().frame();
+    if (!frame)
+        return JSC::jsNull();
+
+    NSArray *metaData = parent-&gt;player()-&gt;timedMetadata();
+    if (!metaData)
+        return JSC::jsNull();
+
+    JSContext *jsContext = frame-&gt;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-&gt;player())
+        return JSC::jsNull();
+
+    Frame* frame = parent-&gt;document().frame();
+    if (!frame)
+        return JSC::jsNull();
+
+    JSValue *dictionary = [JSValue valueWithNewObjectInContext:frame-&gt;script().javaScriptContext()];
+    String accessLogString = parent-&gt;player()-&gt;accessLog();
+    [dictionary setValue:static_cast&lt;NSString *&gt;(accessLogString) forProperty:(NSString *)CFSTR(&quot;extendedLog&quot;)];
+
+    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-&gt;player())
+        return JSC::jsNull();
+
+    Frame* frame = parent-&gt;document().frame();
+    if (!frame)
+        return JSC::jsNull();
+
+    JSValue *dictionary = [JSValue valueWithNewObjectInContext:frame-&gt;script().javaScriptContext()];
+    String errorLogString = parent-&gt;player()-&gt;errorLog();
+    [dictionary setValue:static_cast&lt;NSString *&gt;(errorLogString) forProperty:(NSString *)CFSTR(&quot;extendedLog&quot;)];
+
+    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 = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0729B14F17CFCCA0004F1D60 /* MediaStreamCenterMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaStreamCenterMac.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PluginReplacement.h; path = plugins/PluginReplacement.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QuickTimePluginReplacement.cpp; path = plugins/QuickTimePluginReplacement.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><ins>+                072AE1E0183C0741000A5988 /* QuickTimePluginReplacement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = QuickTimePluginReplacement.mm; path = plugins/QuickTimePluginReplacement.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 072AE1E1183C0741000A5988 /* QuickTimePluginReplacement.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = QuickTimePluginReplacement.css; path = plugins/QuickTimePluginReplacement.css; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QuickTimePluginReplacement.h; path = plugins/QuickTimePluginReplacement.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 072AE1E3183C0741000A5988 /* QuickTimePluginReplacement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = QuickTimePluginReplacement.idl; path = plugins/QuickTimePluginReplacement.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</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-&gt;setVideoFullscreenGravity(gravity);
</span><span class="cx"> }
</span><ins>+
+NSArray* MediaPlayer::timedMetadata() const
+{
+    return m_private-&gt;timedMetadata();
+}
+
+String MediaPlayer::accessLog() const
+{
+    return m_private-&gt;accessLog();
+}
+
+String MediaPlayer::errorLog() const
+{
+    return m_private-&gt;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&lt;NSArray&gt;);
</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&lt;NSArray&gt; m_cachedSeekableRanges;
</span><span class="cx">     mutable RetainPtr&lt;NSArray&gt; m_cachedLoadedRanges;
</span><span class="cx">     RetainPtr&lt;NSArray&gt; m_cachedTracks;
</span><ins>+    RetainPtr&lt;NSArray&gt; 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&lt;NSString&gt; 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&lt;NSString&gt; 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&lt;NSArray&gt; metadata)
+{
+    if (!metadata || [metadata isKindOfClass:[NSNull class]])
+        return;
+
+    m_currentMetaData = metadata;
+}
+
</ins><span class="cx"> void MediaPlayerPrivateAVFoundationObjC::tracksDidChange(RetainPtr&lt;NSArray&gt; tracks)
</span><span class="cx"> {
</span><span class="cx">     m_cachedTracks = tracks;
</span><span class="lines">@@ -2270,6 +2312,7 @@
</span><span class="cx">                 @&quot;playbackBufferEmpty&quot;,
</span><span class="cx">                 @&quot;duration&quot;,
</span><span class="cx">                 @&quot;hasEnabledAudio&quot;,
</span><ins>+                @&quot;timedMetadata&quot;,
</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(&amp;MediaPlayerPrivateAVFoundationObjC::presentationSizeDidChange, m_callback, FloatSize([newValue sizeValue]));
</span><span class="cx">         else if ([keyPath isEqualToString:@&quot;duration&quot;])
</span><span class="cx">             function = WTF::bind(&amp;MediaPlayerPrivateAVFoundationObjC::durationDidChange, m_callback, CMTimeGetSeconds([newValue CMTimeValue]));
</span><ins>+        else if ([keyPath isEqualToString:@&quot;timedMetadata&quot;] &amp;&amp; newValue)
+            function = WTF::bind(&amp;MediaPlayerPrivateAVFoundationObjC::metadataDidArrive, m_callback, RetainPtr&lt;NSArray&gt;(newValue));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (context == MediaPlayerAVFoundationObservationContextPlayer &amp;&amp; !willChange) {
</span></span></pre>
</div>
</div>

</body>
</html>