<!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>[172555] branches/safari-600.1-branch/Source/WebKit2</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/172555">172555</a></dd>
<dt>Author</dt> <dd>lforschler@apple.com</dd>
<dt>Date</dt> <dd>2014-08-13 20:43:43 -0700 (Wed, 13 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merged <a href="http://trac.webkit.org/projects/webkit/changeset/172483">r172483</a>.  r&lt;rdar://problem/17935736&gt;</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari6001branchSourceWebKit2ChangeLog">branches/safari-600.1-branch/Source/WebKit2/ChangeLog</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlaycpp">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayh">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.h</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayControllercpp">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayControllerh">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.h</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPageServicesOverlayControllerh">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h</a></li>
<li><a href="#branchessafari6001branchSourceWebKit2WebProcessWebPagemacServicesOverlayControllermm">branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari6001branchSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/ChangeLog (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/ChangeLog        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/ChangeLog        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -1,5 +1,108 @@
</span><span class="cx"> 2014-08-13  Lucas Forschler  &lt;lforschler@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Merge r172483
+
+    2014-08-12  Tim Horton  &lt;timothy_horton@apple.com&gt;
+
+            Add a fade transition to services highlights
+            https://bugs.webkit.org/show_bug.cgi?id=135829
+            &lt;rdar://problem/17935736&gt;
+
+            Reviewed by Enrica Casucci.
+
+            Add a smooth fade to highlight installation and uninstallation.
+            To do so, we make each highlight paint into its own small layer.
+
+            * WebProcess/WebPage/PageOverlay.cpp:
+            (WebKit::PageOverlay::layer):
+            * WebProcess/WebPage/PageOverlay.h:
+            * WebProcess/WebPage/PageOverlayController.cpp:
+            (WebKit::PageOverlayController::layerForOverlay):
+            * WebProcess/WebPage/PageOverlayController.h:
+            Expose the GraphicsLayer on PageOverlay.
+
+            * WebProcess/WebPage/ServicesOverlayController.h:
+            (WebKit::ServicesOverlayController::Highlight::layer):
+            (WebKit::ServicesOverlayController::activeHighlight):
+            (WebKit::ServicesOverlayController::webPage):
+            (WebKit::ServicesOverlayController::Highlight::Highlight): Deleted.
+
+            * WebProcess/WebPage/mac/ServicesOverlayController.mm:
+            (WebKit::ServicesOverlayController::Highlight::createForSelection):
+            (WebKit::ServicesOverlayController::Highlight::createForTelephoneNumber):
+            (WebKit::ServicesOverlayController::Highlight::Highlight):
+            Highlights now own a GraphicsLayer, which are later installed
+            as sublayers of the ServicesOverlayController's PageOverlay layer.
+            These layers are sized and positioned according to the DDHighlight's bounds.
+
+            (WebKit::ServicesOverlayController::Highlight::~Highlight):
+            (WebKit::ServicesOverlayController::Highlight::invalidate):
+            ServicesOverlayController will invalidate any remaining highlights
+            when it is torn down, so they can clear their backpointers.
+
+            (WebKit::ServicesOverlayController::Highlight::notifyFlushRequired):
+            Forward flush notifications to the DrawingArea.
+
+            (WebKit::ServicesOverlayController::Highlight::paintContents):
+            Paint the DDHighlight into the layer. Translation is done by the layer position,
+            so we zero the bounds origin when painting.
+
+            (WebKit::ServicesOverlayController::Highlight::deviceScaleFactor):
+            Forward the deviceScaleFactor so that things are painted at the right scale.
+
+            (WebKit::ServicesOverlayController::Highlight::fadeIn):
+            (WebKit::ServicesOverlayController::Highlight::fadeOut):
+            Apply a fade animation to the layer.
+
+            (WebKit::ServicesOverlayController::Highlight::didFinishFadeOutAnimation):
+            When the fade completes, unparent the layer, unless it has become active again.
+
+            (WebKit::ServicesOverlayController::ServicesOverlayController):
+            (WebKit::ServicesOverlayController::~ServicesOverlayController):
+            Invalidate all highlights, so they can clear their backpointers.
+
+            (WebKit::ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown):
+            Make remainingTimeUntilHighlightShouldBeShown act upon a particular highlight
+            instead of always the active highlight.
+
+            (WebKit::ServicesOverlayController::determineActiveHighlightTimerFired): Rename.
+
+            (WebKit::ServicesOverlayController::drawRect):
+            drawRect is no longer called and will no longer do anything; all of the
+            painting is done in sublayers.
+
+            (WebKit::ServicesOverlayController::buildPhoneNumberHighlights):
+            Ensure that phone number Highlights stay stable even while the selection
+            changes, by comparing the underlying Ranges and keeping around old Highlights
+            that match the new ones. This enables us to e.g. fade in while changing
+            the selection within a phone number.
+
+            (WebKit::ServicesOverlayController::buildSelectionHighlight):
+            (WebKit::ServicesOverlayController::didRebuildPotentialHighlights):
+            (WebKit::ServicesOverlayController::createOverlayIfNeeded):
+            Don't call setNeedsDisplay; the overlay doesn't have backing store.
+            Instead, call determineActiveHighlight, which will install/uninstall
+            highlights as necessary.
+
+            (WebKit::ServicesOverlayController::determineActiveHighlight):
+            Apply fade in/fade out to the overlays.
+            Keep track of which highlight we're going to activate, until the hysteresis
+            delay is up, then actually make it active/parent it/fade it in.
+            We now will have no active highlight between the fade out of the previous one
+            and the fade in of the new one (during the hysteresis delay).
+
+            (WebKit::ServicesOverlayController::mouseEvent):
+            The overlay now will not become active until the delay is up, so we don't
+            need to check it again here.
+
+            (WebKit::ServicesOverlayController::handleClick):
+            (WebKit::ServicesOverlayController::didCreateHighlight):
+            (WebKit::ServicesOverlayController::willDestroyHighlight):
+            (WebKit::ServicesOverlayController::repaintHighlightTimerFired): Deleted.
+            (WebKit::ServicesOverlayController::drawHighlight): Deleted.
+
+2014-08-13  Lucas Forschler  &lt;lforschler@apple.com&gt;
+
</ins><span class="cx">         Merge r172395
</span><span class="cx"> 
</span><span class="cx">     2014-08-08  Enrica Casucci  &lt;enrica@apple.com&gt;
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlaycpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -233,4 +233,9 @@
</span><span class="cx">     m_webPage-&gt;pageOverlayController().clearPageOverlay(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+WebCore::GraphicsLayer* PageOverlay::layer()
+{
+    return m_webPage-&gt;pageOverlayController().layerForOverlay(*this);
+}
+
</ins><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.h (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.h        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlay.h        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> class GraphicsContext;
</span><ins>+class GraphicsLayer;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="lines">@@ -95,6 +96,8 @@
</span><span class="cx"> 
</span><span class="cx">     WebCore::RGBA32 backgroundColor() const { return m_backgroundColor; }
</span><span class="cx">     void setBackgroundColor(WebCore::RGBA32);
</span><ins>+
+    WebCore::GraphicsLayer* layer();
</ins><span class="cx">     
</span><span class="cx"> protected:
</span><span class="cx">     explicit PageOverlay(Client*, OverlayType);
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayControllercpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.cpp (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.cpp        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.cpp        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -171,6 +171,12 @@
</span><span class="cx">     m_overlayGraphicsLayers.get(&amp;overlay)-&gt;setDrawsContent(false);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+GraphicsLayer* PageOverlayController::layerForOverlay(PageOverlay&amp; overlay) const
+{
+    ASSERT(m_pageOverlays.contains(&amp;overlay));
+    return m_overlayGraphicsLayers.get(&amp;overlay);
+}
+
</ins><span class="cx"> void PageOverlayController::didChangeViewSize()
</span><span class="cx"> {
</span><span class="cx">     for (auto&amp; overlayAndLayer : m_overlayGraphicsLayers) {
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPagePageOverlayControllerh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.h (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.h        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/PageOverlayController.h        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx">     void setPageOverlayNeedsDisplay(PageOverlay&amp;, const WebCore::IntRect&amp;);
</span><span class="cx">     void setPageOverlayOpacity(PageOverlay&amp;, float);
</span><span class="cx">     void clearPageOverlay(PageOverlay&amp;);
</span><ins>+    WebCore::GraphicsLayer* layerForOverlay(PageOverlay&amp;) const;
</ins><span class="cx"> 
</span><span class="cx">     void didChangeViewSize();
</span><span class="cx">     void didChangeDocumentSize();
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPageServicesOverlayControllerh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;PageOverlay.h&quot;
</span><span class="cx"> #include &quot;WebFrame.h&quot;
</span><ins>+#include &lt;WebCore/GraphicsLayerClient.h&gt;
</ins><span class="cx"> #include &lt;WebCore/Range.h&gt;
</span><span class="cx"> #include &lt;WebCore/Timer.h&gt;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="lines">@@ -55,14 +56,18 @@
</span><span class="cx">     void selectionRectsDidChange(const Vector&lt;WebCore::LayoutRect&gt;&amp;, const Vector&lt;WebCore::GapRects&gt;&amp;, bool isTextOnly);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    class Highlight : public RefCounted&lt;Highlight&gt; {
</del><ins>+    class Highlight : public RefCounted&lt;Highlight&gt;, private WebCore::GraphicsLayerClient {
</ins><span class="cx">         WTF_MAKE_NONCOPYABLE(Highlight);
</span><span class="cx">     public:
</span><del>-        static PassRefPtr&lt;Highlight&gt; createForSelection(RetainPtr&lt;DDHighlightRef&gt;);
-        static PassRefPtr&lt;Highlight&gt; createForTelephoneNumber(RetainPtr&lt;DDHighlightRef&gt;, PassRefPtr&lt;WebCore::Range&gt;);
</del><ins>+        static PassRefPtr&lt;Highlight&gt; createForSelection(ServicesOverlayController&amp;, RetainPtr&lt;DDHighlightRef&gt;);
+        static PassRefPtr&lt;Highlight&gt; createForTelephoneNumber(ServicesOverlayController&amp;, RetainPtr&lt;DDHighlightRef&gt;, PassRefPtr&lt;WebCore::Range&gt;);
+        ~Highlight();
</ins><span class="cx"> 
</span><ins>+        void invalidate();
+
</ins><span class="cx">         DDHighlightRef ddHighlight() const { return m_ddHighlight.get(); }
</span><span class="cx">         WebCore::Range* range() const { return m_range.get(); }
</span><ins>+        WebCore::GraphicsLayer* layer() const { return m_graphicsLayer.get(); }
</ins><span class="cx"> 
</span><span class="cx">         enum class Type {
</span><span class="cx">             TelephoneNumber,
</span><span class="lines">@@ -70,19 +75,25 @@
</span><span class="cx">         };
</span><span class="cx">         Type type() const { return m_type; }
</span><span class="cx"> 
</span><ins>+        void fadeIn();
+        void fadeOut();
+
</ins><span class="cx">     private:
</span><del>-        explicit Highlight(Type type, RetainPtr&lt;DDHighlightRef&gt; ddHighlight, PassRefPtr&lt;WebCore::Range&gt; range)
-            : m_ddHighlight(ddHighlight)
-            , m_range(range)
-            , m_type(type)
-        {
-            ASSERT(m_ddHighlight);
-            ASSERT(type != Type::TelephoneNumber || m_range);
-        }
</del><ins>+        explicit Highlight(ServicesOverlayController&amp;, Type, RetainPtr&lt;DDHighlightRef&gt;, PassRefPtr&lt;WebCore::Range&gt;);
</ins><span class="cx"> 
</span><ins>+        // GraphicsLayerClient
+        virtual void notifyAnimationStarted(const WebCore::GraphicsLayer*, double time) override { }
+        virtual void notifyFlushRequired(const WebCore::GraphicsLayer*) override;
+        virtual void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&amp;, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect&amp; inClip) override;
+        virtual float deviceScaleFactor() const override;
+
+        void didFinishFadeOutAnimation();
+
</ins><span class="cx">         RetainPtr&lt;DDHighlightRef&gt; m_ddHighlight;
</span><span class="cx">         RefPtr&lt;WebCore::Range&gt; m_range;
</span><ins>+        std::unique_ptr&lt;WebCore::GraphicsLayer&gt; m_graphicsLayer;
</ins><span class="cx">         Type m_type;
</span><ins>+        ServicesOverlayController* m_controller;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     // PageOverlay::Client
</span><span class="lines">@@ -104,33 +115,44 @@
</span><span class="cx"> 
</span><span class="cx">     void determineActiveHighlight(bool&amp; mouseIsOverButton);
</span><span class="cx">     void clearActiveHighlight();
</span><ins>+    Highlight* activeHighlight() const { return m_activeHighlight.get(); }
</ins><span class="cx"> 
</span><span class="cx">     bool hasRelevantSelectionServices();
</span><span class="cx"> 
</span><span class="cx">     bool mouseIsOverHighlight(Highlight&amp;, bool&amp; mouseIsOverButton) const;
</span><del>-    std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown() const;
-    void repaintHighlightTimerFired(WebCore::Timer&lt;ServicesOverlayController&gt;&amp;);
</del><ins>+    std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown(Highlight*) const;
+    void determineActiveHighlightTimerFired(WebCore::Timer&lt;ServicesOverlayController&gt;&amp;);
</ins><span class="cx"> 
</span><span class="cx">     static bool highlightsAreEquivalent(const Highlight* a, const Highlight* b);
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;RefPtr&lt;WebCore::Range&gt;&gt; telephoneNumberRangesForFocusedFrame();
</span><span class="cx"> 
</span><ins>+    void didCreateHighlight(Highlight*);
+    void willDestroyHighlight(Highlight*);
+    void didFinishFadingOutHighlight(Highlight*);
+
+    WebPage&amp; webPage() const { return m_webPage; }
+
</ins><span class="cx">     WebPage&amp; m_webPage;
</span><span class="cx">     PageOverlay* m_servicesOverlay;
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;Highlight&gt; m_activeHighlight;
</span><ins>+    RefPtr&lt;Highlight&gt; m_nextActiveHighlight;
</ins><span class="cx">     HashSet&lt;RefPtr&lt;Highlight&gt;&gt; m_potentialHighlights;
</span><ins>+    HashSet&lt;RefPtr&lt;Highlight&gt;&gt; m_animatingHighlights;
</ins><span class="cx"> 
</span><ins>+    HashSet&lt;Highlight*&gt; m_highlights;
+
</ins><span class="cx">     Vector&lt;WebCore::LayoutRect&gt; m_currentSelectionRects;
</span><span class="cx">     bool m_isTextOnly;
</span><span class="cx"> 
</span><span class="cx">     std::chrono::steady_clock::time_point m_lastSelectionChangeTime;
</span><del>-    std::chrono::steady_clock::time_point m_lastActiveHighlightChangeTime;
</del><ins>+    std::chrono::steady_clock::time_point m_nextActiveHighlightChangeTime;
</ins><span class="cx"> 
</span><span class="cx">     RefPtr&lt;Highlight&gt; m_currentMouseDownOnButtonHighlight;
</span><span class="cx">     WebCore::IntPoint m_mousePosition;
</span><span class="cx"> 
</span><del>-    WebCore::Timer&lt;ServicesOverlayController&gt; m_repaintHighlightTimer;
</del><ins>+    WebCore::Timer&lt;ServicesOverlayController&gt; m_determineActiveHighlightTimer;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPagemacServicesOverlayControllermm"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm (172554 => 172555)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm        2014-08-14 03:41:10 UTC (rev 172554)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm        2014-08-14 03:43:43 UTC (rev 172555)
</span><span class="lines">@@ -31,13 +31,17 @@
</span><span class="cx"> #import &quot;Logging.h&quot;
</span><span class="cx"> #import &quot;WebPage.h&quot;
</span><span class="cx"> #import &quot;WebProcess.h&quot;
</span><ins>+#import &lt;QuartzCore/QuartzCore.h&gt;
</ins><span class="cx"> #import &lt;WebCore/Document.h&gt;
</span><span class="cx"> #import &lt;WebCore/FloatQuad.h&gt;
</span><span class="cx"> #import &lt;WebCore/FocusController.h&gt;
</span><span class="cx"> #import &lt;WebCore/FrameView.h&gt;
</span><span class="cx"> #import &lt;WebCore/GapRects.h&gt;
</span><span class="cx"> #import &lt;WebCore/GraphicsContext.h&gt;
</span><ins>+#import &lt;WebCore/GraphicsLayer.h&gt;
+#import &lt;WebCore/GraphicsLayerCA.h&gt;
</ins><span class="cx"> #import &lt;WebCore/MainFrame.h&gt;
</span><ins>+#import &lt;WebCore/PlatformCAAnimationMac.h&gt;
</ins><span class="cx"> #import &lt;WebCore/SoftLinking.h&gt;
</span><span class="cx"> 
</span><span class="cx"> #if __has_include(&lt;DataDetectors/DDHighlightDrawing.h&gt;)
</span><span class="lines">@@ -50,6 +54,8 @@
</span><span class="cx"> #import &lt;DataDetectors/DDHighlightDrawing_Private.h&gt;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+const float highlightFadeAnimationDuration = 0.3;
+
</ins><span class="cx"> typedef NSUInteger DDHighlightStyle;
</span><span class="cx"> static const DDHighlightStyle DDHighlightNoOutlineWithArrow = (1 &lt;&lt; 16);
</span><span class="cx"> static const DDHighlightStyle DDHighlightOutlineWithArrow = (1 &lt;&lt; 16) | 1;
</span><span class="lines">@@ -64,16 +70,123 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><del>-PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForSelection(RetainPtr&lt;DDHighlightRef&gt; ddHighlight)
</del><ins>+PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForSelection(ServicesOverlayController&amp; controller, RetainPtr&lt;DDHighlightRef&gt; ddHighlight)
</ins><span class="cx"> {
</span><del>-    return adoptRef(new Highlight(Type::Selection, ddHighlight, nullptr));
</del><ins>+    return adoptRef(new Highlight(controller, Type::Selection, ddHighlight, nullptr));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForTelephoneNumber(RetainPtr&lt;DDHighlightRef&gt; ddHighlight, PassRefPtr&lt;Range&gt; range)
</del><ins>+PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForTelephoneNumber(ServicesOverlayController&amp; controller, RetainPtr&lt;DDHighlightRef&gt; ddHighlight, PassRefPtr&lt;Range&gt; range)
</ins><span class="cx"> {
</span><del>-    return adoptRef(new Highlight(Type::TelephoneNumber, ddHighlight, range));
</del><ins>+    return adoptRef(new Highlight(controller, Type::TelephoneNumber, ddHighlight, range));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ServicesOverlayController::Highlight::Highlight(ServicesOverlayController&amp; controller, Type type, RetainPtr&lt;DDHighlightRef&gt; ddHighlight, PassRefPtr&lt;WebCore::Range&gt; range)
+    : m_ddHighlight(ddHighlight)
+    , m_range(range)
+    , m_type(type)
+    , m_controller(&amp;controller)
+{
+    ASSERT(m_ddHighlight);
+    ASSERT(type != Type::TelephoneNumber || m_range);
+
+    DrawingArea* drawingArea = controller.webPage().drawingArea();
+    m_graphicsLayer = GraphicsLayer::create(drawingArea ? drawingArea-&gt;graphicsLayerFactory() : nullptr, *this);
+    m_graphicsLayer-&gt;setDrawsContent(true);
+    m_graphicsLayer-&gt;setNeedsDisplay();
+
+    CGRect highlightBoundingRect = DDHighlightGetBoundingRect(ddHighlight.get());
+    m_graphicsLayer-&gt;setPosition(FloatPoint(highlightBoundingRect.origin));
+    m_graphicsLayer-&gt;setSize(FloatSize(highlightBoundingRect.size));
+
+    // Set directly on the PlatformCALayer so that when we leave the 'from' value implicit
+    // in our animations, we get the right initial value regardless of flush timing.
+    toGraphicsLayerCA(layer())-&gt;platformCALayer()-&gt;setOpacity(0);
+
+    controller.didCreateHighlight(this);
+}
+
+ServicesOverlayController::Highlight::~Highlight()
+{
+    if (m_controller)
+        m_controller-&gt;willDestroyHighlight(this);
+}
+
+void ServicesOverlayController::Highlight::invalidate()
+{
+    layer()-&gt;removeFromParent();
+    m_controller = nullptr;
+}
+
+void ServicesOverlayController::Highlight::notifyFlushRequired(const GraphicsLayer*)
+{
+    if (!m_controller)
+        return;
+
+    if (DrawingArea* drawingArea = m_controller-&gt;webPage().drawingArea())
+        drawingArea-&gt;scheduleCompositingLayerFlush();
+}
+
+void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext&amp; graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&amp; inClip)
+{
+    CGContextRef cgContext = graphicsContext.platformContext();
+
+    CGLayerRef highlightLayer = DDHighlightGetLayerWithContext(ddHighlight(), cgContext);
+    CGRect highlightBoundingRect = DDHighlightGetBoundingRect(ddHighlight());
+    highlightBoundingRect.origin = CGPointZero;
+
+    CGContextDrawLayerInRect(cgContext, highlightBoundingRect, highlightLayer);
+}
+
+float ServicesOverlayController::Highlight::deviceScaleFactor() const
+{
+    if (!m_controller)
+        return 1;
+
+    return m_controller-&gt;webPage().deviceScaleFactor();
+}
+
+void ServicesOverlayController::Highlight::fadeIn()
+{
+    RetainPtr&lt;CABasicAnimation&gt; animation = [CABasicAnimation animationWithKeyPath:@&quot;opacity&quot;];
+    [animation setDuration:highlightFadeAnimationDuration];
+    [animation setFillMode:kCAFillModeForwards];
+    [animation setRemovedOnCompletion:false];
+    [animation setToValue:@1];
+
+    RefPtr&lt;PlatformCAAnimation&gt; platformAnimation = PlatformCAAnimationMac::create(animation.get());
+    toGraphicsLayerCA(layer())-&gt;platformCALayer()-&gt;addAnimationForKey(&quot;FadeHighlightIn&quot;, platformAnimation.get());
+}
+
+void ServicesOverlayController::Highlight::fadeOut()
+{
+    RetainPtr&lt;CABasicAnimation&gt; animation = [CABasicAnimation animationWithKeyPath:@&quot;opacity&quot;];
+    [animation setDuration:highlightFadeAnimationDuration];
+    [animation setFillMode:kCAFillModeForwards];
+    [animation setRemovedOnCompletion:false];
+    [animation setToValue:@0];
+
+    RefPtr&lt;Highlight&gt; retainedSelf = this;
+    [CATransaction begin];
+    [CATransaction setCompletionBlock:[retainedSelf] () {
+        retainedSelf-&gt;didFinishFadeOutAnimation();
+    }];
+
+    RefPtr&lt;PlatformCAAnimation&gt; platformAnimation = PlatformCAAnimationMac::create(animation.get());
+    toGraphicsLayerCA(layer())-&gt;platformCALayer()-&gt;addAnimationForKey(&quot;FadeHighlightOut&quot;, platformAnimation.get());
+    [CATransaction commit];
+}
+
+void ServicesOverlayController::Highlight::didFinishFadeOutAnimation()
+{
+    if (!m_controller)
+        return;
+
+    if (m_controller-&gt;activeHighlight() == this)
+        return;
+
+    layer()-&gt;removeFromParent();
+}
+
</ins><span class="cx"> static IntRect textQuadsToBoundingRectForRange(Range&amp; range)
</span><span class="cx"> {
</span><span class="cx">     Vector&lt;FloatQuad&gt; textQuads;
</span><span class="lines">@@ -88,12 +201,14 @@
</span><span class="cx">     : m_webPage(webPage)
</span><span class="cx">     , m_servicesOverlay(nullptr)
</span><span class="cx">     , m_isTextOnly(false)
</span><del>-    , m_repaintHighlightTimer(this, &amp;ServicesOverlayController::repaintHighlightTimerFired)
</del><ins>+    , m_determineActiveHighlightTimer(this, &amp;ServicesOverlayController::determineActiveHighlightTimerFired)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ServicesOverlayController::~ServicesOverlayController()
</span><span class="cx"> {
</span><ins>+    for (auto&amp; highlight : m_highlights)
+        highlight-&gt;invalidate();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::pageOverlayDestroyed(PageOverlay*)
</span><span class="lines">@@ -280,57 +395,33 @@
</span><span class="cx">     return hovered;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-std::chrono::milliseconds ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown() const
</del><ins>+std::chrono::milliseconds ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown(Highlight* highlight) const
</ins><span class="cx"> {
</span><ins>+    if (!highlight)
+        return std::chrono::milliseconds::zero();
+
</ins><span class="cx">     // Highlight hysteresis is only for selection services, because telephone number highlights are already much more stable
</span><span class="cx">     // by virtue of being expanded to include the entire telephone number.
</span><del>-    if (m_activeHighlight-&gt;type() == Highlight::Type::TelephoneNumber)
</del><ins>+    if (highlight-&gt;type() == Highlight::Type::TelephoneNumber)
</ins><span class="cx">         return std::chrono::milliseconds::zero();
</span><span class="cx"> 
</span><span class="cx">     std::chrono::steady_clock::duration minimumTimeUntilHighlightShouldBeShown = 200_ms;
</span><span class="cx"> 
</span><span class="cx">     auto now = std::chrono::steady_clock::now();
</span><span class="cx">     auto timeSinceLastSelectionChange = now - m_lastSelectionChangeTime;
</span><del>-    auto timeSinceHighlightBecameActive = now - m_lastActiveHighlightChangeTime;
</del><ins>+    auto timeSinceHighlightBecameActive = now - m_nextActiveHighlightChangeTime;
</ins><span class="cx"> 
</span><span class="cx">     return std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::max(minimumTimeUntilHighlightShouldBeShown - timeSinceLastSelectionChange, minimumTimeUntilHighlightShouldBeShown - timeSinceHighlightBecameActive));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::repaintHighlightTimerFired(WebCore::Timer&lt;ServicesOverlayController&gt;&amp;)
</del><ins>+void ServicesOverlayController::determineActiveHighlightTimerFired(Timer&lt;ServicesOverlayController&gt;&amp;)
</ins><span class="cx"> {
</span><del>-    if (m_servicesOverlay)
-        m_servicesOverlay-&gt;setNeedsDisplay();
-}
-
-void ServicesOverlayController::drawHighlight(Highlight&amp; highlight, WebCore::GraphicsContext&amp; graphicsContext)
-{
</del><span class="cx">     bool mouseIsOverButton;
</span><del>-    if (!mouseIsOverHighlight(highlight, mouseIsOverButton)) {
-        LOG(Services, &quot;ServicesOverlayController::drawHighlight - Mouse is not over highlight, so drawing nothing&quot;);
-        return;
-    }
-
-    auto remainingTimeUntilHighlightShouldBeShown = this-&gt;remainingTimeUntilHighlightShouldBeShown();
-    if (remainingTimeUntilHighlightShouldBeShown &gt; std::chrono::steady_clock::duration::zero()) {
-        m_repaintHighlightTimer.startOneShot(remainingTimeUntilHighlightShouldBeShown);
-        return;
-    }
-
-    CGContextRef cgContext = graphicsContext.platformContext();
-    
-    CGLayerRef highlightLayer = DDHighlightGetLayerWithContext(highlight.ddHighlight(), cgContext);
-    CGRect highlightBoundingRect = DDHighlightGetBoundingRect(highlight.ddHighlight());
-
-    CGContextDrawLayerInRect(cgContext, highlightBoundingRect, highlightLayer);
</del><ins>+    determineActiveHighlight(mouseIsOverButton);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::drawRect(PageOverlay* overlay, WebCore::GraphicsContext&amp; graphicsContext, const WebCore::IntRect&amp; dirtyRect)
</del><ins>+void ServicesOverlayController::drawRect(PageOverlay* overlay, GraphicsContext&amp; graphicsContext, const IntRect&amp; dirtyRect)
</ins><span class="cx"> {
</span><del>-    bool mouseIsOverButton;
-    determineActiveHighlight(mouseIsOverButton);
-
-    if (m_activeHighlight)
-        drawHighlight(*m_activeHighlight, graphicsContext);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::clearActiveHighlight()
</span><span class="lines">@@ -357,7 +448,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::buildPhoneNumberHighlights()
</span><span class="cx"> {
</span><del>-    removeAllPotentialHighlightsOfType(Highlight::Type::TelephoneNumber);
</del><ins>+    HashSet&lt;RefPtr&lt;Highlight&gt;&gt; newPotentialHighlights;
</ins><span class="cx"> 
</span><span class="cx">     Frame* mainFrame = m_webPage.mainFrame();
</span><span class="cx">     FrameView&amp; mainFrameView = *mainFrame-&gt;view();
</span><span class="lines">@@ -381,10 +472,32 @@
</span><span class="cx">             CGRect cgRect = rect;
</span><span class="cx">             RetainPtr&lt;DDHighlightRef&gt; ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, &amp;cgRect, 1, mainFrameView.visibleContentRect(), DDHighlightOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
</span><span class="cx"> 
</span><del>-            m_potentialHighlights.add(Highlight::createForTelephoneNumber(ddHighlight, range));
</del><ins>+            newPotentialHighlights.add(Highlight::createForTelephoneNumber(*this, ddHighlight, range));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // If any old Highlights are equivalent (by Range) to a new Highlight, reuse the old
+    // one so that any metadata is retained.
+    HashSet&lt;RefPtr&lt;Highlight&gt;&gt; reusedPotentialHighlights;
+
+    for (auto&amp; oldHighlight : m_potentialHighlights) {
+        if (oldHighlight-&gt;type() != Highlight::Type::TelephoneNumber)
+            continue;
+
+        for (auto&amp; newHighlight : newPotentialHighlights) {
+            if (highlightsAreEquivalent(oldHighlight.get(), newHighlight.get())) {
+                reusedPotentialHighlights.add(oldHighlight);
+                newPotentialHighlights.remove(newHighlight);
+                break;
+            }
+        }
+    }
+
+    removeAllPotentialHighlightsOfType(Highlight::Type::TelephoneNumber);
+
+    m_potentialHighlights.add(newPotentialHighlights.begin(), newPotentialHighlights.end());
+    m_potentialHighlights.add(reusedPotentialHighlights.begin(), reusedPotentialHighlights.end());
+
</ins><span class="cx">     didRebuildPotentialHighlights();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -402,7 +515,7 @@
</span><span class="cx">         CGRect visibleRect = m_webPage.corePage()-&gt;mainFrame().view()-&gt;visibleContentRect();
</span><span class="cx">         RetainPtr&lt;DDHighlightRef&gt; ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, cgRects.begin(), cgRects.size(), visibleRect, DDHighlightNoOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
</span><span class="cx">         
</span><del>-        m_potentialHighlights.add(Highlight::createForSelection(ddHighlight));
</del><ins>+        m_potentialHighlights.add(Highlight::createForSelection(*this, ddHighlight));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     didRebuildPotentialHighlights();
</span><span class="lines">@@ -425,19 +538,19 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     createOverlayIfNeeded();
</span><ins>+
+    bool mouseIsOverButton;
+    determineActiveHighlight(mouseIsOverButton);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::createOverlayIfNeeded()
</span><span class="cx"> {
</span><del>-    if (m_servicesOverlay) {
-        m_servicesOverlay-&gt;setNeedsDisplay();
</del><ins>+    if (m_servicesOverlay)
</ins><span class="cx">         return;
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx">     RefPtr&lt;PageOverlay&gt; overlay = PageOverlay::create(this, PageOverlay::OverlayType::Document);
</span><span class="cx">     m_servicesOverlay = overlay.get();
</span><span class="cx">     m_webPage.installPageOverlay(overlay.release(), PageOverlay::FadeMode::DoNotFade);
</span><del>-    m_servicesOverlay-&gt;setNeedsDisplay();
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Vector&lt;RefPtr&lt;Range&gt;&gt; ServicesOverlayController::telephoneNumberRangesForFocusedFrame()
</span><span class="lines">@@ -467,13 +580,13 @@
</span><span class="cx"> {
</span><span class="cx">     mouseIsOverActiveHighlightButton = false;
</span><span class="cx"> 
</span><del>-    RefPtr&lt;Highlight&gt; oldActiveHighlight = m_activeHighlight.release();
</del><ins>+    RefPtr&lt;Highlight&gt; newActiveHighlight;
</ins><span class="cx"> 
</span><span class="cx">     for (auto&amp; highlight : m_potentialHighlights) {
</span><span class="cx">         if (highlight-&gt;type() == Highlight::Type::Selection) {
</span><span class="cx">             // If we've already found a new active highlight, and it's
</span><span class="cx">             // a telephone number highlight, prefer that over this selection highlight.
</span><del>-            if (m_activeHighlight &amp;&amp; m_activeHighlight-&gt;type() == Highlight::Type::TelephoneNumber)
</del><ins>+            if (newActiveHighlight &amp;&amp; newActiveHighlight-&gt;type() == Highlight::Type::TelephoneNumber)
</ins><span class="cx">                 continue;
</span><span class="cx"> 
</span><span class="cx">             // If this highlight has no compatible services, it can't be active, unless we have telephone number highlights to show in the combined menu.
</span><span class="lines">@@ -486,14 +599,38 @@
</span><span class="cx">         if (!mouseIsOverHighlight(*highlight, mouseIsOverButton))
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        m_activeHighlight = highlight;
</del><ins>+        newActiveHighlight = highlight;
</ins><span class="cx">         mouseIsOverActiveHighlightButton = mouseIsOverButton;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!highlightsAreEquivalent(oldActiveHighlight.get(), m_activeHighlight.get())) {
-        m_lastActiveHighlightChangeTime = std::chrono::steady_clock::now();
-        m_servicesOverlay-&gt;setNeedsDisplay();
</del><ins>+    if (!this-&gt;highlightsAreEquivalent(m_activeHighlight.get(), newActiveHighlight.get())) {
+        // When transitioning to a new highlight, we might end up in determineActiveHighlight multiple times
+        // before the new highlight actually becomes active. Keep track of the last next-but-not-yet-active
+        // highlight, and only reset the active highlight hysteresis when that changes.
+        if (m_nextActiveHighlight != newActiveHighlight) {
+            m_nextActiveHighlight = newActiveHighlight;
+            m_nextActiveHighlightChangeTime = std::chrono::steady_clock::now();
+        }
+
</ins><span class="cx">         m_currentMouseDownOnButtonHighlight = nullptr;
</span><ins>+
+        if (m_activeHighlight) {
+            m_activeHighlight-&gt;fadeOut();
+            m_activeHighlight = nullptr;
+        }
+
+        auto remainingTimeUntilHighlightShouldBeShown = this-&gt;remainingTimeUntilHighlightShouldBeShown(newActiveHighlight.get());
+        if (remainingTimeUntilHighlightShouldBeShown &gt; std::chrono::steady_clock::duration::zero()) {
+            m_determineActiveHighlightTimer.startOneShot(remainingTimeUntilHighlightShouldBeShown);
+            return;
+        }
+
+        m_activeHighlight = m_nextActiveHighlight.release();
+
+        if (m_activeHighlight) {
+            m_servicesOverlay-&gt;layer()-&gt;addChild(m_activeHighlight-&gt;layer());
+            m_activeHighlight-&gt;fadeIn();
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -515,7 +652,7 @@
</span><span class="cx">         RefPtr&lt;Highlight&gt; mouseDownHighlight = m_currentMouseDownOnButtonHighlight;
</span><span class="cx">         m_currentMouseDownOnButtonHighlight = nullptr;
</span><span class="cx"> 
</span><del>-        if (mouseIsOverActiveHighlightButton &amp;&amp; mouseDownHighlight &amp;&amp; remainingTimeUntilHighlightShouldBeShown() &lt;= std::chrono::steady_clock::duration::zero()) {
</del><ins>+        if (mouseIsOverActiveHighlightButton &amp;&amp; mouseDownHighlight) {
</ins><span class="cx">             handleClick(m_mousePosition, *mouseDownHighlight);
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="lines">@@ -536,7 +673,6 @@
</span><span class="cx">     if (event.type() == WebEvent::MouseDown) {
</span><span class="cx">         if (m_activeHighlight &amp;&amp; mouseIsOverActiveHighlightButton) {
</span><span class="cx">             m_currentMouseDownOnButtonHighlight = m_activeHighlight;
</span><del>-            m_servicesOverlay-&gt;setNeedsDisplay();
</del><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -546,7 +682,7 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::handleClick(const WebCore::IntPoint&amp; clickPoint, Highlight&amp; highlight)
</del><ins>+void ServicesOverlayController::handleClick(const IntPoint&amp; clickPoint, Highlight&amp; highlight)
</ins><span class="cx"> {
</span><span class="cx">     FrameView* frameView = m_webPage.mainFrameView();
</span><span class="cx">     if (!frameView)
</span><span class="lines">@@ -566,6 +702,18 @@
</span><span class="cx">         m_webPage.handleTelephoneNumberClick(highlight.range()-&gt;text(), windowPoint);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ServicesOverlayController::didCreateHighlight(Highlight* highlight)
+{
+    ASSERT(!m_highlights.contains(highlight));
+    m_highlights.add(highlight);
+}
+
+void ServicesOverlayController::willDestroyHighlight(Highlight* highlight)
+{
+    ASSERT(m_highlights.contains(highlight));
+    m_highlights.remove(highlight);
+}
+
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #endif // #if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION) &amp;&amp; PLATFORM(MAC)
</span></span></pre>
</div>
</div>

</body>
</html>