<!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>[173117] trunk/Source/WebInspectorUI</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/173117">173117</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2014-08-29 13:10:05 -0700 (Fri, 29 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Fix how Popover animates
https://bugs.webkit.org/show_bug.cgi?id=136353

Patch by Saam Barati &lt;sbarati@apple.com&gt; on 2014-08-29
Reviewed by Timothy Hatcher.

Popovers currently don't animate properly because they use
window.requestAnimationFrame which won't fire its callback
while the inspector is paused in the debugger. This patches
switches the callback mechanism to setTimeout and also changes
how a Popover's anchor animates to prevent visual glitches.

Popover also has a new function that allows a new target
frame and new content to be set simultaneously and to
animate to show the new content while changing the
location of the popover frame.

SourceCodeTextEditor uses Popover's new API for animating
between popovers when paused in the debugger. SourceCodeTextEditor
also now ensures proper balancing of popover tracking event
listeners.

* UserInterface/Views/Popover.js:
(WebInspector.Popover.prototype.present):
(WebInspector.Popover.prototype.presentNewContentWithFrame):
(WebInspector.Popover.prototype.dismiss):
(WebInspector.Popover.prototype._update):
(WebInspector.Popover.prototype.drawBackground):
(WebInspector.Popover.prototype._animateFrame):
(WebInspector.Popover.prototype._drawFrame):
(WebInspector.Popover.prototype._addListenersIfNeeded):
(WebInspector.Popover.prototype._animateFrame.drawBackground): Deleted.
* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype._showPopover):
(WebInspector.SourceCodeTextEditor.prototype._dismissPopover):
(WebInspector.SourceCodeTextEditor.prototype._trackPopoverEvents):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsPopoverjs">trunk/Source/WebInspectorUI/UserInterface/Views/Popover.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs">trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (173116 => 173117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-08-29 18:15:19 UTC (rev 173116)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-08-29 20:10:05 UTC (rev 173117)
</span><span class="lines">@@ -1,3 +1,41 @@
</span><ins>+2014-08-29  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Web Inspector: Fix how Popover animates
+        https://bugs.webkit.org/show_bug.cgi?id=136353
+
+        Reviewed by Timothy Hatcher.
+
+        Popovers currently don't animate properly because they use 
+        window.requestAnimationFrame which won't fire its callback 
+        while the inspector is paused in the debugger. This patches
+        switches the callback mechanism to setTimeout and also changes
+        how a Popover's anchor animates to prevent visual glitches.
+
+        Popover also has a new function that allows a new target
+        frame and new content to be set simultaneously and to
+        animate to show the new content while changing the 
+        location of the popover frame.
+
+        SourceCodeTextEditor uses Popover's new API for animating
+        between popovers when paused in the debugger. SourceCodeTextEditor 
+        also now ensures proper balancing of popover tracking event 
+        listeners.
+
+        * UserInterface/Views/Popover.js:
+        (WebInspector.Popover.prototype.present):
+        (WebInspector.Popover.prototype.presentNewContentWithFrame):
+        (WebInspector.Popover.prototype.dismiss):
+        (WebInspector.Popover.prototype._update):
+        (WebInspector.Popover.prototype.drawBackground):
+        (WebInspector.Popover.prototype._animateFrame):
+        (WebInspector.Popover.prototype._drawFrame):
+        (WebInspector.Popover.prototype._addListenersIfNeeded):
+        (WebInspector.Popover.prototype._animateFrame.drawBackground): Deleted.
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype._showPopover):
+        (WebInspector.SourceCodeTextEditor.prototype._dismissPopover):
+        (WebInspector.SourceCodeTextEditor.prototype._trackPopoverEvents):
+
</ins><span class="cx"> 2014-08-28  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Write tests for ScriptSyntaxTree and fix bugs in the data structure
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsPopoverjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Popover.js (173116 => 173117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/Popover.js        2014-08-29 18:15:19 UTC (rev 173116)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Popover.js        2014-08-29 20:10:05 UTC (rev 173117)
</span><span class="lines">@@ -122,17 +122,32 @@
</span><span class="cx">         if (!this._content)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        window.addEventListener(&quot;mousedown&quot;, this, true);
-        window.addEventListener(&quot;scroll&quot;, this, true);
</del><ins>+        this._addListenersIfNeeded();
</ins><span class="cx"> 
</span><span class="cx">         this._update();
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    presentNewContentWithFrame: function(content, targetFrame, preferredEdges)
+    {
+        this._content = content;
+        this._contentNeedsUpdate = true;
+
+        this._targetFrame = targetFrame;
+        this._preferredEdges = preferredEdges;
+
+        this._addListenersIfNeeded();
+
+        var shouldAnimate = this.visible;
+        this._update(shouldAnimate);
+    },
+
</ins><span class="cx">     dismiss: function()
</span><span class="cx">     {
</span><span class="cx">         if (this._element.parentNode !== document.body)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><ins>+        console.assert(this._isListeningForPopoverEvents);
+        this._isListeningForPopoverEvents = false;
</ins><span class="cx">         window.removeEventListener(&quot;mousedown&quot;, this, true);
</span><span class="cx">         window.removeEventListener(&quot;scroll&quot;, this, true);
</span><span class="cx"> 
</span><span class="lines">@@ -259,7 +274,7 @@
</span><span class="cx">             this._element.classList.add(this._cssClassNameForEdge());
</span><span class="cx"> 
</span><span class="cx">             if (shouldAnimate &amp;&amp; this._edge === previousEdge)
</span><del>-                this._animateFrame(bestFrame);
</del><ins>+                this._animateFrame(bestFrame, anchorPoint);
</ins><span class="cx">             else {
</span><span class="cx">                  this.frame = bestFrame;
</span><span class="cx">                  this._setAnchorPoint(anchorPoint);
</span><span class="lines">@@ -305,7 +320,7 @@
</span><span class="cx">         this._anchorPoint = anchorPoint;
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    _animateFrame: function(toFrame)
</del><ins>+    _animateFrame: function(toFrame, toAnchor)
</ins><span class="cx">     {
</span><span class="cx">         var startTime = Date.now();
</span><span class="cx">         var duration = 350;
</span><span class="lines">@@ -313,12 +328,8 @@
</span><span class="cx">         var spline = new WebInspector.UnitBezier(0.25, 0.1, 0.25, 1);
</span><span class="cx"> 
</span><span class="cx">         var fromFrame = this._frame.copy();
</span><ins>+        var fromAnchor = this._anchorPoint.copy();
</ins><span class="cx"> 
</span><del>-        var absoluteAnchorPoint = new WebInspector.Point(
-            fromFrame.minX() + this._anchorPoint.x,
-            fromFrame.minY() + this._anchorPoint.y
-        );
-
</del><span class="cx">         function animatedValue(from, to, progress)
</span><span class="cx">         {
</span><span class="cx">             return from + (to - from) * progress;
</span><span class="lines">@@ -336,14 +347,19 @@
</span><span class="cx">             ).round();
</span><span class="cx"> 
</span><span class="cx">             this._setAnchorPoint(new WebInspector.Point(
</span><del>-                absoluteAnchorPoint.x - this._frame.minX(),
-                absoluteAnchorPoint.y - this._frame.minY()
</del><ins>+                animatedValue(fromAnchor.x, toAnchor.x, progress),
+                animatedValue(fromAnchor.y, toAnchor.y, progress)
</ins><span class="cx">             ));
</span><span class="cx"> 
</span><span class="cx">             this._drawBackground();
</span><span class="cx"> 
</span><del>-            if (progress &lt; 1)
-                window.requestAnimationFrame(drawBackground.bind(this));
</del><ins>+            if (progress &lt; 1) {
+                // FIXME: Revert to using window.requestAnimationFrame when Inspector is out of process.
+                // It can't currently use window.requestAnimationFrame because the callback passed into
+                // it won't fire while paused in the debugger inside the Inspector.
+                const animationRate60FPS = 17;
+                setTimeout(drawBackground.bind(this), animationRate60FPS);
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         drawBackground.call(this);
</span><span class="lines">@@ -534,8 +550,16 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         ctx.closePath();
</span><ins>+    },
+
+    _addListenersIfNeeded: function()
+    {
+        if (!this._isListeningForPopoverEvents) {
+            this._isListeningForPopoverEvents = true;
+            window.addEventListener(&quot;mousedown&quot;, this, true);
+            window.addEventListener(&quot;scroll&quot;, this, true);
+        }
</ins><span class="cx">     }
</span><del>-
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.Popover.prototype.__proto__ = WebInspector.Object.prototype;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js (173116 => 173117)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js        2014-08-29 18:15:19 UTC (rev 173116)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js        2014-08-29 20:10:05 UTC (rev 173117)
</span><span class="lines">@@ -1144,8 +1144,7 @@
</span><span class="cx">         var bounds = WebInspector.Rect.unionOfRects(rects);
</span><span class="cx"> 
</span><span class="cx">         this._popover = this._popover || new WebInspector.Popover(this);
</span><del>-        this._popover.content = content;
-        this._popover.present(bounds.pad(5), [WebInspector.RectEdge.MIN_Y, WebInspector.RectEdge.MAX_Y, WebInspector.RectEdge.MAX_X]);
</del><ins>+        this._popover.presentNewContentWithFrame(content, bounds.pad(5), [WebInspector.RectEdge.MIN_Y, WebInspector.RectEdge.MAX_Y, WebInspector.RectEdge.MAX_X]);
</ins><span class="cx"> 
</span><span class="cx">         this._trackPopoverEvents();
</span><span class="cx"> 
</span><span class="lines">@@ -1278,17 +1277,22 @@
</span><span class="cx"> 
</span><span class="cx">         this._popover.dismiss();
</span><span class="cx"> 
</span><del>-        if (this._popoverEventListeners)
</del><ins>+        if (this._popoverEventListeners &amp;&amp; this._popoverEventListenersAreRegistered) {
+            this._popoverEventListenersAreRegistered = false;
</ins><span class="cx">             this._popoverEventListeners.unregister();
</span><ins>+        }
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _trackPopoverEvents: function()
</span><span class="cx">     {
</span><span class="cx">         if (!this._popoverEventListeners) 
</span><span class="cx">             this._popoverEventListeners = new WebInspector.EventListenerSet(this, &quot;Popover listeners&quot;);
</span><del>-        this._popoverEventListeners.register(this._popover.element, &quot;mouseover&quot;, this._popoverMouseover);
-        this._popoverEventListeners.register(this._popover.element, &quot;mouseout&quot;, this._popoverMouseout);
-        this._popoverEventListeners.install();
</del><ins>+        if (!this._popoverEventListenersAreRegistered) {
+            this._popoverEventListenersAreRegistered = true;
+            this._popoverEventListeners.register(this._popover.element, &quot;mouseover&quot;, this._popoverMouseover);
+            this._popoverEventListeners.register(this._popover.element, &quot;mouseout&quot;, this._popoverMouseout);
+            this._popoverEventListeners.install();
+        }
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _popoverMouseover: function(event)
</span></span></pre>
</div>
</div>

</body>
</html>