<!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>[172552] 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/172552">172552</a></dd>
<dt>Author</dt> <dd>lforschler@apple.com</dd>
<dt>Date</dt> <dd>2014-08-13 20:19:02 -0700 (Wed, 13 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merged <a href="http://trac.webkit.org/projects/webkit/changeset/172382">r172382</a>.  &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="#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 (172551 => 172552)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/ChangeLog        2014-08-14 03:12:57 UTC (rev 172551)
+++ branches/safari-600.1-branch/Source/WebKit2/ChangeLog        2014-08-14 03:19:02 UTC (rev 172552)
</span><span class="lines">@@ -1,3 +1,124 @@
</span><ins>+2014-08-13  Lucas Forschler  &lt;lforschler@apple.com&gt;
+
+        Merge r172382
+
+    2014-08-10  Tim Horton  &lt;timothy_horton@apple.com&gt;
+
+            Refactor ServiceOverlayController in preparation for fading between highlights
+            https://bugs.webkit.org/show_bug.cgi?id=135787
+            &lt;rdar://problem/17935736&gt;
+
+            Reviewed by Brady Eidson.
+
+            Rework ServicesOverlayController so that we always keep a set of generic
+            &quot;potential highlights&quot;, which are refcounted Highlight objects and
+            wrap a DDHighlightRef, as well as a type (Selection or TelephoneNumber),
+            Range (only used in the case of TelephoneNumber), and potentially more
+            things in the future (like, say, fade state!).
+
+            We eagerly update the list of potential highlights when the selection or set
+            of detected telephone numbers changes, and use this information to install
+            or uninstall the page overlay as needed.
+
+            When we need to recompute the &quot;active&quot; highlight from this set (for example,
+            we need to handle a mouse event or paint the highlight), we look through
+            the set of potential highlights and decide. This moves the &quot;active&quot; highlight
+            decision logic into one small and confined place.
+
+            * WebProcess/WebPage/ServicesOverlayController.h:
+            (WebKit::ServicesOverlayController::Highlight):
+            Add the new aforementioned refcounted Highlight class.
+            Rename m_lastHoveredHighlightChangeTime to m_lastActiveHighlightChangeTime.
+            Make m_webPage a reference.
+            The rest is just added/removed/adjusted functions for the refactoring.
+
+            (WebKit::TelephoneNumberData::TelephoneNumberData): Deleted.
+            * WebProcess/WebPage/mac/ServicesOverlayController.mm:
+            (WebKit::ServicesOverlayController::Highlight::createForSelection):
+            (WebKit::ServicesOverlayController::Highlight::createForTelephoneNumber):
+            Create Highlights for the two different highlight types.
+
+            (WebKit::ServicesOverlayController::ServicesOverlayController):
+            (WebKit::ServicesOverlayController::willMoveToWebPage):
+            Our WebPage pointer is always valid because it owns us; don't clear it.
+            We need to keep it around so that we can uninstall the overlay and
+            install it again later, anyway.
+
+            (WebKit::ServicesOverlayController::selectionRectsDidChange):
+            (WebKit::ServicesOverlayController::selectedTelephoneNumberRangesChanged):
+            When selection rects or detected telephone numbers change, rebuild potential highlights.
+            This will have the side-effect of installing the overlay if needed.
+
+            (WebKit::ServicesOverlayController::mouseIsOverHighlight):
+            Make this function take a Highlight instead of a DDHighlightRef.
+
+            (WebKit::ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown):
+            Make this function take a Highlight instead of a DDHighlightRef.
+
+            (WebKit::ServicesOverlayController::drawHighlight):
+            Make this function take a Highlight instead of a DDHighlightRef.
+            There's no reason to do the translation separately from the layer blit,
+            also allowing us to avoid the StateSaver.
+
+            (WebKit::ServicesOverlayController::drawRect):
+            drawRect now always paints the active highlight, instead of duplicating
+            logic about which highlight should be active.
+            Also, it will update the active highlight before painting.
+            We no longer need to re-determine whether the active highlight's phone
+            number range is still a valid phone number range, because we rebuild
+            the potential highlights whenever the set of phone number ranges changes.
+
+            (WebKit::ServicesOverlayController::clearActiveHighlight):
+            Mostly an adoption of new names.
+
+            (WebKit::ServicesOverlayController::removeAllPotentialHighlightsOfType):
+            Run through the list of potential highlights and remove any of the given type.
+            The two highlight building functions use this helper to clear the old ones before building.
+
+            (WebKit::ServicesOverlayController::buildPhoneNumberHighlights):
+            (WebKit::ServicesOverlayController::buildSelectionHighlight):
+            Rebuild the list of potential highlights, replacing all highlights of
+            the given type with new ones.
+
+            (WebKit::ServicesOverlayController::hasRelevantSelectionServices):
+            Factor out the code that decides whether our current selection is
+            viable for servicing based on whether we have plain-text and/or rich-text services.
+
+            (WebKit::ServicesOverlayController::didRebuildPotentialHighlights):
+            When rebuilding potential highlights, if we have no potential highlights at all,
+            uninstall the page overlay; we don't need mouse tracking and don't need to
+            paint anything. This improves memory use and compositing performance significantly,
+            where previously we were leaving the overlay up forever after creating it.
+
+            If we have either detected telephone numbers or relevant selection services,
+            create and install the overlay if it doesn't already exist.
+
+            (WebKit::ServicesOverlayController::createOverlayIfNeeded):
+            This just moved from elsehwere, except that it now uses FadeMode::DoNotFade.
+            It doesn't make sense to fade on install/uninstall (which happens even before hover)
+            but not on changing the active highlight; fading will be re-addressed in the next patch.
+
+            (WebKit::ServicesOverlayController::highlightsAreEquivalent):
+            Determine whether two highlights are equivalent. While we may have
+            created a new Highlight at rebuild time, if two telephone number
+            highlights have equivalent ranges, there's no need to 'transition' to the new one.
+
+            (WebKit::ServicesOverlayController::determineActiveHighlight):
+            Run through the list of services, and try to find one that is hovered.
+            We prefer telephone number highlights to selection highlights, and
+            we will never make a selection highlight active if it is both
+            not serviceable and there are no telephone numbers to show in the combined menu.
+            This is the centralized location for determination of which highlight
+            should be considered active. If the active highlight changed, update
+            the time since last change and cancel the mouse-down tracking.
+
+            (WebKit::ServicesOverlayController::mouseEvent):
+            Adjust some comments to be more explanatory.
+            A bunch of code moved out of here and into determineActiveHighlight.
+
+            (WebKit::ServicesOverlayController::handleClick):
+            Adjust to take a reference and use Highlight instead of DDHighlightRef.
+
</ins><span class="cx"> 2014-08-12  Matthew Hanson  &lt;matthew_hanson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rollout 172395. &lt;rdar://problem/17837670&gt;
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebKit2WebProcessWebPageServicesOverlayControllerh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h (172551 => 172552)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h        2014-08-14 03:12:57 UTC (rev 172551)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h        2014-08-14 03:19:02 UTC (rev 172552)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;PageOverlay.h&quot;
</span><span class="cx"> #include &lt;WebCore/Range.h&gt;
</span><span class="cx"> #include &lt;WebCore/Timer.h&gt;
</span><ins>+#include &lt;wtf/RefCounted.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> typedef void* DDHighlightRef;
</span><span class="cx"> 
</span><span class="lines">@@ -44,19 +45,6 @@
</span><span class="cx"> 
</span><span class="cx"> class WebPage;
</span><span class="cx"> 
</span><del>-typedef void* DDHighlightRef;
-
-struct TelephoneNumberData {
-    TelephoneNumberData(RetainPtr&lt;DDHighlightRef&gt; highlight, PassRefPtr&lt;WebCore::Range&gt; range)
-        : highlight(highlight)
-        , range(range)
-    {
-    }
-
-    RetainPtr&lt;DDHighlightRef&gt; highlight;
-    RefPtr&lt;WebCore::Range&gt; range;
-};
-
</del><span class="cx"> class ServicesOverlayController : private PageOverlay::Client {
</span><span class="cx"> public:
</span><span class="cx">     ServicesOverlayController(WebPage&amp;);
</span><span class="lines">@@ -66,49 +54,81 @@
</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>-    void createOverlayIfNeeded();
-    void handleClick(const WebCore::IntPoint&amp;, DDHighlightRef);
-    void clearHighlightState();
</del><ins>+    class Highlight : public RefCounted&lt;Highlight&gt; {
+        WTF_MAKE_NONCOPYABLE(Highlight);
+    public:
+        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;);
</ins><span class="cx"> 
</span><ins>+        DDHighlightRef ddHighlight() const { return m_ddHighlight.get(); }
+        WebCore::Range* range() const { return m_range.get(); }
+
+        enum class Type {
+            TelephoneNumber,
+            Selection
+        };
+        Type type() const { return m_type; }
+
+    private:
+        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);
+        }
+
+        RetainPtr&lt;DDHighlightRef&gt; m_ddHighlight;
+        RefPtr&lt;WebCore::Range&gt; m_range;
+        Type m_type;
+    };
+
+    // PageOverlay::Client
</ins><span class="cx">     virtual void pageOverlayDestroyed(PageOverlay*) override;
</span><span class="cx">     virtual void willMoveToWebPage(PageOverlay*, WebPage*) override;
</span><span class="cx">     virtual void didMoveToWebPage(PageOverlay*, WebPage*) override;
</span><span class="cx">     virtual void drawRect(PageOverlay*, WebCore::GraphicsContext&amp;, const WebCore::IntRect&amp; dirtyRect) override;
</span><span class="cx">     virtual bool mouseEvent(PageOverlay*, const WebMouseEvent&amp;) override;
</span><span class="cx"> 
</span><del>-    bool drawTelephoneNumberHighlightIfVisible(WebCore::GraphicsContext&amp;, const WebCore::IntRect&amp; dirtyRect);
-    void drawSelectionHighlight(WebCore::GraphicsContext&amp;, const WebCore::IntRect&amp; dirtyRect);
-    void drawHighlight(DDHighlightRef, WebCore::GraphicsContext&amp;);
</del><ins>+    void createOverlayIfNeeded();
+    void handleClick(const WebCore::IntPoint&amp;, Highlight&amp;);
</ins><span class="cx"> 
</span><del>-    void establishHoveredTelephoneHighlight(bool&amp; mouseIsOverButton);
-    void maybeCreateSelectionHighlight();
</del><ins>+    void drawHighlight(Highlight&amp;, WebCore::GraphicsContext&amp;);
</ins><span class="cx"> 
</span><del>-    void clearSelectionHighlight();
-    void clearHoveredTelephoneNumberHighlight();
</del><ins>+    void removeAllPotentialHighlightsOfType(Highlight::Type);
+    void buildPhoneNumberHighlights();
+    void buildSelectionHighlight();
+    void didRebuildPotentialHighlights();
</ins><span class="cx"> 
</span><del>-    bool mouseIsOverHighlight(DDHighlightRef, bool&amp; mouseIsOverButton) const;
</del><ins>+    void determineActiveHighlight(bool&amp; mouseIsOverButton);
+    void clearActiveHighlight();
+
+    bool hasRelevantSelectionServices();
+
+    bool mouseIsOverHighlight(Highlight&amp;, bool&amp; mouseIsOverButton) const;
</ins><span class="cx">     std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown() const;
</span><span class="cx">     void repaintHighlightTimerFired(WebCore::Timer&lt;ServicesOverlayController&gt;&amp;);
</span><span class="cx"> 
</span><del>-    WebPage* m_webPage;
</del><ins>+    static bool highlightsAreEquivalent(const Highlight* a, const Highlight* b);
+
+    WebPage&amp; m_webPage;
</ins><span class="cx">     PageOverlay* m_servicesOverlay;
</span><del>-    
</del><ins>+
+    RefPtr&lt;Highlight&gt; m_activeHighlight;
+    HashSet&lt;RefPtr&lt;Highlight&gt;&gt; m_potentialHighlights;
+
+    Vector&lt;RefPtr&lt;WebCore::Range&gt;&gt; m_currentTelephoneNumberRanges;
</ins><span class="cx">     Vector&lt;WebCore::LayoutRect&gt; m_currentSelectionRects;
</span><del>-    RetainPtr&lt;DDHighlightRef&gt; m_selectionHighlight;
</del><span class="cx">     bool m_isTextOnly;
</span><ins>+
</ins><span class="cx">     std::chrono::steady_clock::time_point m_lastSelectionChangeTime;
</span><del>-    std::chrono::steady_clock::time_point m_lastHoveredHighlightChangeTime;
</del><ins>+    std::chrono::steady_clock::time_point m_lastActiveHighlightChangeTime;
</ins><span class="cx"> 
</span><del>-    Vector&lt;RefPtr&lt;WebCore::Range&gt;&gt; m_currentTelephoneNumberRanges;
-    Vector&lt;RetainPtr&lt;DDHighlightRef&gt;&gt; m_telephoneNumberHighlights;
-    std::unique_ptr&lt;TelephoneNumberData&gt; m_hoveredTelephoneNumberData;
</del><ins>+    RefPtr&lt;Highlight&gt; m_currentMouseDownOnButtonHighlight;
+    WebCore::IntPoint m_mousePosition;
</ins><span class="cx"> 
</span><del>-    RetainPtr&lt;DDHighlightRef&gt; m_currentHoveredHighlight;
-    RetainPtr&lt;DDHighlightRef&gt; m_currentMouseDownOnButtonHighlight;
-
</del><span class="cx">     WebCore::Timer&lt;ServicesOverlayController&gt; m_repaintHighlightTimer;
</span><del>-
-    WebCore::IntPoint m_mousePosition;
</del><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 (172551 => 172552)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm        2014-08-14 03:12:57 UTC (rev 172551)
+++ branches/safari-600.1-branch/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm        2014-08-14 03:19:02 UTC (rev 172552)
</span><span class="lines">@@ -63,6 +63,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><ins>+PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForSelection(RetainPtr&lt;DDHighlightRef&gt; ddHighlight)
+{
+    return adoptRef(new Highlight(Type::Selection, ddHighlight, nullptr));
+}
+
+PassRefPtr&lt;ServicesOverlayController::Highlight&gt; ServicesOverlayController::Highlight::createForTelephoneNumber(RetainPtr&lt;DDHighlightRef&gt; ddHighlight, PassRefPtr&lt;Range&gt; range)
+{
+    return adoptRef(new Highlight(Type::TelephoneNumber, ddHighlight, range));
+}
+
</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">@@ -74,7 +84,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ServicesOverlayController::ServicesOverlayController(WebPage&amp; webPage)
</span><del>-    : m_webPage(&amp;webPage)
</del><ins>+    : m_webPage(webPage)
</ins><span class="cx">     , m_servicesOverlay(nullptr)
</span><span class="cx">     , m_isTextOnly(false)
</span><span class="cx">     , m_repaintHighlightTimer(this, &amp;ServicesOverlayController::repaintHighlightTimerFired)
</span><span class="lines">@@ -99,31 +109,12 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(m_servicesOverlay);
</span><span class="cx">     m_servicesOverlay = nullptr;
</span><del>-
-    ASSERT(m_webPage);
-    m_webPage = nullptr;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::didMoveToWebPage(PageOverlay*, WebPage*)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::createOverlayIfNeeded()
-{
-    if (m_servicesOverlay) {
-        m_servicesOverlay-&gt;setNeedsDisplay();
-        return;
-    }
-
-    if (m_currentTelephoneNumberRanges.isEmpty() &amp;&amp; (!WebProcess::shared().hasSelectionServices() || m_currentSelectionRects.isEmpty()))
-        return;
-
-    RefPtr&lt;PageOverlay&gt; overlay = PageOverlay::create(this, PageOverlay::OverlayType::Document);
-    m_servicesOverlay = overlay.get();
-    m_webPage-&gt;installPageOverlay(overlay.release(), PageOverlay::FadeMode::Fade);
-    m_servicesOverlay-&gt;setNeedsDisplay();
-}
-
</del><span class="cx"> static const uint8_t AlignmentNone = 0;
</span><span class="cx"> static const uint8_t AlignmentLeft = 1 &lt;&lt; 0;
</span><span class="cx"> static const uint8_t AlignmentRight = 1 &lt;&lt; 1;
</span><span class="lines">@@ -215,7 +206,6 @@
</span><span class="cx"> void ServicesOverlayController::selectionRectsDidChange(const Vector&lt;LayoutRect&gt;&amp; rects, const Vector&lt;GapRects&gt;&amp; gapRects, bool isTextOnly)
</span><span class="cx"> {
</span><span class="cx"> #if __MAC_OS_X_VERSION_MIN_REQUIRED &gt; 1090
</span><del>-    clearSelectionHighlight();
</del><span class="cx">     m_currentSelectionRects = rects;
</span><span class="cx">     m_isTextOnly = isTextOnly;
</span><span class="cx"> 
</span><span class="lines">@@ -228,7 +218,7 @@
</span><span class="cx"> 
</span><span class="cx">     LOG(Services, &quot;ServicesOverlayController - Selection rects changed - Now have %lu\n&quot;, rects.size());
</span><span class="cx"> 
</span><del>-    createOverlayIfNeeded();
</del><ins>+    buildSelectionHighlight();
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(rects);
</span><span class="cx"> #endif
</span><span class="lines">@@ -239,95 +229,17 @@
</span><span class="cx"> #if PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &gt; 1090
</span><span class="cx">     LOG(Services, &quot;ServicesOverlayController - Telephone number ranges changed - Had %lu, now have %lu\n&quot;, m_currentTelephoneNumberRanges.size(), ranges.size());
</span><span class="cx">     m_currentTelephoneNumberRanges = ranges;
</span><del>-    m_telephoneNumberHighlights.clear();
-    m_telephoneNumberHighlights.resize(ranges.size());
</del><span class="cx"> 
</span><del>-    createOverlayIfNeeded();
</del><ins>+    buildPhoneNumberHighlights();
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(ranges);
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::clearHighlightState()
</del><ins>+bool ServicesOverlayController::mouseIsOverHighlight(Highlight&amp; highlight, bool&amp; mouseIsOverButton) const
</ins><span class="cx"> {
</span><del>-    clearSelectionHighlight();
-    clearHoveredTelephoneNumberHighlight();
-
-    m_telephoneNumberHighlights.clear();
-}
-
-void ServicesOverlayController::drawRect(PageOverlay* overlay, WebCore::GraphicsContext&amp; graphicsContext, const WebCore::IntRect&amp; dirtyRect)
-{
-    if (m_currentSelectionRects.isEmpty() &amp;&amp; m_currentTelephoneNumberRanges.isEmpty()) {
-        clearHighlightState();
-        return;
-    }
-
-    if (drawTelephoneNumberHighlightIfVisible(graphicsContext, dirtyRect))
-        return;
-
-    drawSelectionHighlight(graphicsContext, dirtyRect);
-}
-
-void ServicesOverlayController::drawSelectionHighlight(WebCore::GraphicsContext&amp; graphicsContext, const WebCore::IntRect&amp; dirtyRect)
-{
-    // It's possible to end up drawing the selection highlight before we've actually received the selection rects.
-    // If that happens we'll end up here again once we have the rects.
-    if (m_currentSelectionRects.isEmpty())
-        return;
-
-    // If there are no appropriate installed selection services and we have no phone numbers detected, then we have nothing to draw.
-    if ((!WebProcess::shared().hasSelectionServices() || (!WebProcess::shared().hasRichContentServices() &amp;&amp; !m_isTextOnly)) &amp;&amp; m_currentTelephoneNumberRanges.isEmpty())
-        return;
-
-    if (!m_selectionHighlight)
-        maybeCreateSelectionHighlight();
-
-    if (m_selectionHighlight)
-        drawHighlight(m_selectionHighlight.get(), graphicsContext);
-}
-
-bool ServicesOverlayController::drawTelephoneNumberHighlightIfVisible(WebCore::GraphicsContext&amp; graphicsContext, const WebCore::IntRect&amp; dirtyRect)
-{
-    // Make sure the hovered telephone number highlight is still hovered.
-    if (m_hoveredTelephoneNumberData) {
-        Boolean onButton;
-        if (!DDHighlightPointIsOnHighlight(m_hoveredTelephoneNumberData-&gt;highlight.get(), (CGPoint)m_mousePosition, &amp;onButton))
-            clearHoveredTelephoneNumberHighlight();
-
-        bool foundMatchingRange = false;
-
-        // Make sure the hovered highlight still corresponds to a current telephone number range.
-        for (auto&amp; range : m_currentTelephoneNumberRanges) {
-            if (areRangesEqual(range.get(), m_hoveredTelephoneNumberData-&gt;range.get())) {
-                foundMatchingRange = true;
-                break;
-            }
-        }
-
-        if (!foundMatchingRange)
-            clearHoveredTelephoneNumberHighlight();
-    }
-
-    // Found out which - if any - telephone number is hovered.
-    if (!m_hoveredTelephoneNumberData) {
-        bool mouseIsOverButton;
-        establishHoveredTelephoneHighlight(mouseIsOverButton);
-    }
-
-    // If a telephone number is actually hovered, draw it.
-    if (m_hoveredTelephoneNumberData) {
-        drawHighlight(m_hoveredTelephoneNumberData-&gt;highlight.get(), graphicsContext);
-        return true;
-    }
-
-    return false;
-}
-
-bool ServicesOverlayController::mouseIsOverHighlight(DDHighlightRef highlight, bool&amp; mouseIsOverButton) const
-{
</del><span class="cx">     Boolean onButton;
</span><del>-    bool hovered = DDHighlightPointIsOnHighlight(highlight, (CGPoint)m_mousePosition, &amp;onButton);
</del><ins>+    bool hovered = DDHighlightPointIsOnHighlight(highlight.ddHighlight(), (CGPoint)m_mousePosition, &amp;onButton);
</ins><span class="cx">     mouseIsOverButton = onButton;
</span><span class="cx">     return hovered;
</span><span class="cx"> }
</span><span class="lines">@@ -336,16 +248,16 @@
</span><span class="cx"> {
</span><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_hoveredTelephoneNumberData)
</del><ins>+    if (m_activeHighlight-&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 timeSinceMouseOverSelection = now - m_lastHoveredHighlightChangeTime;
</del><ins>+    auto timeSinceHighlightBecameActive = now - m_lastActiveHighlightChangeTime;
</ins><span class="cx"> 
</span><del>-    return std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::max(minimumTimeUntilHighlightShouldBeShown - timeSinceLastSelectionChange, minimumTimeUntilHighlightShouldBeShown - timeSinceMouseOverSelection));
</del><ins>+    return std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::max(minimumTimeUntilHighlightShouldBeShown - timeSinceLastSelectionChange, minimumTimeUntilHighlightShouldBeShown - timeSinceHighlightBecameActive));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void ServicesOverlayController::repaintHighlightTimerFired(WebCore::Timer&lt;ServicesOverlayController&gt;&amp;)
</span><span class="lines">@@ -354,10 +266,8 @@
</span><span class="cx">         m_servicesOverlay-&gt;setNeedsDisplay();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::drawHighlight(DDHighlightRef highlight, WebCore::GraphicsContext&amp; graphicsContext)
</del><ins>+void ServicesOverlayController::drawHighlight(Highlight&amp; highlight, WebCore::GraphicsContext&amp; graphicsContext)
</ins><span class="cx"> {
</span><del>-    ASSERT(highlight);
-
</del><span class="cx">     bool mouseIsOverButton;
</span><span class="cx">     if (!mouseIsOverHighlight(highlight, mouseIsOverButton)) {
</span><span class="cx">         LOG(Services, &quot;ServicesOverlayController::drawHighlight - Mouse is not over highlight, so drawing nothing&quot;);
</span><span class="lines">@@ -372,86 +282,74 @@
</span><span class="cx"> 
</span><span class="cx">     CGContextRef cgContext = graphicsContext.platformContext();
</span><span class="cx">     
</span><del>-    CGLayerRef highlightLayer = DDHighlightGetLayerWithContext(highlight, cgContext);
-    CGRect highlightBoundingRect = DDHighlightGetBoundingRect(highlight);
-    
-    GraphicsContextStateSaver stateSaver(graphicsContext);
</del><ins>+    CGLayerRef highlightLayer = DDHighlightGetLayerWithContext(highlight.ddHighlight(), cgContext);
+    CGRect highlightBoundingRect = DDHighlightGetBoundingRect(highlight.ddHighlight());
</ins><span class="cx"> 
</span><del>-    graphicsContext.translate(toFloatSize(highlightBoundingRect.origin));
</del><ins>+    CGContextDrawLayerInRect(cgContext, highlightBoundingRect, highlightLayer);
+}
</ins><span class="cx"> 
</span><del>-    CGRect highlightDrawRect = highlightBoundingRect;
-    highlightDrawRect.origin.x = 0;
-    highlightDrawRect.origin.y = 0;
-    
-    CGContextDrawLayerInRect(cgContext, highlightDrawRect, highlightLayer);
</del><ins>+void ServicesOverlayController::drawRect(PageOverlay* overlay, WebCore::GraphicsContext&amp; graphicsContext, const WebCore::IntRect&amp; dirtyRect)
+{
+    bool mouseIsOverButton;
+    determineActiveHighlight(mouseIsOverButton);
+
+    if (m_activeHighlight)
+        drawHighlight(*m_activeHighlight, graphicsContext);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::clearSelectionHighlight()
</del><ins>+void ServicesOverlayController::clearActiveHighlight()
</ins><span class="cx"> {
</span><del>-    if (!m_selectionHighlight)
</del><ins>+    if (!m_activeHighlight)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    if (m_currentHoveredHighlight == m_selectionHighlight)
-        m_currentHoveredHighlight = nullptr;
-    if (m_currentMouseDownOnButtonHighlight == m_selectionHighlight)
</del><ins>+    if (m_currentMouseDownOnButtonHighlight == m_activeHighlight)
</ins><span class="cx">         m_currentMouseDownOnButtonHighlight = nullptr;
</span><del>-    m_selectionHighlight = nullptr;
</del><ins>+    m_activeHighlight = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::clearHoveredTelephoneNumberHighlight()
</del><ins>+void ServicesOverlayController::removeAllPotentialHighlightsOfType(Highlight::Type type)
</ins><span class="cx"> {
</span><del>-    if (!m_hoveredTelephoneNumberData)
-        return;
</del><ins>+    Vector&lt;RefPtr&lt;Highlight&gt;&gt; highlightsToRemove;
+    for (auto&amp; highlight : m_potentialHighlights) {
+        if (highlight-&gt;type() == type)
+            highlightsToRemove.append(highlight);
+    }
</ins><span class="cx"> 
</span><del>-    if (m_currentHoveredHighlight == m_hoveredTelephoneNumberData-&gt;highlight)
-        m_currentHoveredHighlight = nullptr;
-    if (m_currentMouseDownOnButtonHighlight == m_hoveredTelephoneNumberData-&gt;highlight)
-        m_currentMouseDownOnButtonHighlight = nullptr;
-    m_hoveredTelephoneNumberData = nullptr;
</del><ins>+    while (!highlightsToRemove.isEmpty())
+        m_potentialHighlights.remove(highlightsToRemove.takeLast());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::establishHoveredTelephoneHighlight(bool&amp; mouseIsOverButton)
</del><ins>+void ServicesOverlayController::buildPhoneNumberHighlights()
</ins><span class="cx"> {
</span><del>-    ASSERT(m_currentTelephoneNumberRanges.size() == m_telephoneNumberHighlights.size());
</del><ins>+    removeAllPotentialHighlightsOfType(Highlight::Type::TelephoneNumber);
</ins><span class="cx"> 
</span><span class="cx">     for (unsigned i = 0; i &lt; m_currentTelephoneNumberRanges.size(); ++i) {
</span><del>-        if (!m_telephoneNumberHighlights[i]) {
-            // FIXME: This will choke if the range wraps around the edge of the view.
-            // What should we do in that case?
-            IntRect rect = textQuadsToBoundingRectForRange(*m_currentTelephoneNumberRanges[i]);
</del><ins>+        // FIXME: This will choke if the range wraps around the edge of the view.
+        // What should we do in that case?
+        IntRect rect = textQuadsToBoundingRectForRange(*m_currentTelephoneNumberRanges[i]);
</ins><span class="cx"> 
</span><del>-            // Convert to the main document's coordinate space.
-            // FIXME: It's a little crazy to call contentsToWindow and then windowToContents in order to get the right coordinate space.
-            // We should consider adding conversion functions to ScrollView for contentsToDocument(). Right now, contentsToRootView() is
-            // not equivalent to what we need when you have a topContentInset or a header banner.
-            FrameView* viewForRange = m_currentTelephoneNumberRanges[i]-&gt;ownerDocument().view();
-            if (!viewForRange)
-                continue;
-            FrameView&amp; mainFrameView = *m_webPage-&gt;corePage()-&gt;mainFrame().view();
-            rect.setLocation(mainFrameView.windowToContents(viewForRange-&gt;contentsToWindow(rect.location())));
-
-            CGRect cgRect = rect;
-            m_telephoneNumberHighlights[i] = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, &amp;cgRect, 1, mainFrameView.visibleContentRect(), DDHighlightOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
-        }
-
-        if (!mouseIsOverHighlight(m_telephoneNumberHighlights[i].get(), mouseIsOverButton))
</del><ins>+        // Convert to the main document's coordinate space.
+        // FIXME: It's a little crazy to call contentsToWindow and then windowToContents in order to get the right coordinate space.
+        // We should consider adding conversion functions to ScrollView for contentsToDocument(). Right now, contentsToRootView() is
+        // not equivalent to what we need when you have a topContentInset or a header banner.
+        FrameView* viewForRange = m_currentTelephoneNumberRanges[i]-&gt;ownerDocument().view();
+        if (!viewForRange)
</ins><span class="cx">             continue;
</span><ins>+        FrameView&amp; mainFrameView = *m_webPage.corePage()-&gt;mainFrame().view();
+        rect.setLocation(mainFrameView.windowToContents(viewForRange-&gt;contentsToWindow(rect.location())));
</ins><span class="cx"> 
</span><del>-        if (!m_hoveredTelephoneNumberData || m_hoveredTelephoneNumberData-&gt;highlight != m_telephoneNumberHighlights[i])
-            m_hoveredTelephoneNumberData = std::make_unique&lt;TelephoneNumberData&gt;(m_telephoneNumberHighlights[i], m_currentTelephoneNumberRanges[i]);
</del><ins>+        CGRect cgRect = rect;
+        RetainPtr&lt;DDHighlightRef&gt; ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, &amp;cgRect, 1, mainFrameView.visibleContentRect(), DDHighlightOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
</ins><span class="cx"> 
</span><del>-        m_servicesOverlay-&gt;setNeedsDisplay();
-        return;
</del><ins>+        m_potentialHighlights.add(Highlight::createForTelephoneNumber(ddHighlight, m_currentTelephoneNumberRanges[i]));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    clearHoveredTelephoneNumberHighlight();
-    mouseIsOverButton = false;
</del><ins>+    didRebuildPotentialHighlights();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::maybeCreateSelectionHighlight()
</del><ins>+void ServicesOverlayController::buildSelectionHighlight()
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_selectionHighlight);
-    ASSERT(m_servicesOverlay);
</del><ins>+    removeAllPotentialHighlightsOfType(Highlight::Type::Selection);
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;CGRect&gt; cgRects;
</span><span class="cx">     cgRects.reserveCapacity(m_currentSelectionRects.size());
</span><span class="lines">@@ -460,105 +358,163 @@
</span><span class="cx">         cgRects.append((CGRect)pixelSnappedIntRect(rect));
</span><span class="cx"> 
</span><span class="cx">     if (!cgRects.isEmpty()) {
</span><del>-        CGRect visibleRect = m_webPage-&gt;corePage()-&gt;mainFrame().view()-&gt;visibleContentRect();
-        m_selectionHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, cgRects.begin(), cgRects.size(), visibleRect, DDHighlightNoOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
</del><ins>+        CGRect visibleRect = m_webPage.corePage()-&gt;mainFrame().view()-&gt;visibleContentRect();
+        RetainPtr&lt;DDHighlightRef&gt; ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, cgRects.begin(), cgRects.size(), visibleRect, DDHighlightNoOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
+        
+        m_potentialHighlights.add(Highlight::createForSelection(ddHighlight));
+    }
</ins><span class="cx"> 
</span><ins>+    didRebuildPotentialHighlights();
+}
+
+bool ServicesOverlayController::hasRelevantSelectionServices()
+{
+    return (m_isTextOnly &amp;&amp; WebProcess::shared().hasSelectionServices()) || WebProcess::shared().hasRichContentServices();
+}
+
+void ServicesOverlayController::didRebuildPotentialHighlights()
+{
+    if (m_potentialHighlights.isEmpty()) {
+        if (m_servicesOverlay)
+            m_webPage.uninstallPageOverlay(m_servicesOverlay);
+        return;
+    }
+
+    if (m_currentTelephoneNumberRanges.isEmpty() &amp;&amp; !hasRelevantSelectionServices())
+        return;
+
+    createOverlayIfNeeded();
+}
+
+void ServicesOverlayController::createOverlayIfNeeded()
+{
+    if (m_servicesOverlay) {
</ins><span class="cx">         m_servicesOverlay-&gt;setNeedsDisplay();
</span><ins>+        return;
</ins><span class="cx">     }
</span><ins>+
+    RefPtr&lt;PageOverlay&gt; overlay = PageOverlay::create(this, PageOverlay::OverlayType::Document);
+    m_servicesOverlay = overlay.get();
+    m_webPage.installPageOverlay(overlay.release(), PageOverlay::FadeMode::DoNotFade);
+    m_servicesOverlay-&gt;setNeedsDisplay();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ServicesOverlayController::mouseEvent(PageOverlay*, const WebMouseEvent&amp; event)
</del><ins>+bool ServicesOverlayController::highlightsAreEquivalent(const Highlight* a, const Highlight* b)
</ins><span class="cx"> {
</span><del>-    m_mousePosition = m_webPage-&gt;corePage()-&gt;mainFrame().view()-&gt;rootViewToContents(event.position());
</del><ins>+    if (a == b)
+        return true;
</ins><span class="cx"> 
</span><del>-    DDHighlightRef oldHoveredHighlight = m_currentHoveredHighlight.get();
</del><ins>+    if (!a || !b)
+        return false;
</ins><span class="cx"> 
</span><del>-    bool mouseIsOverButton = false;
-    establishHoveredTelephoneHighlight(mouseIsOverButton);
-    if (m_hoveredTelephoneNumberData) {
-        ASSERT(m_hoveredTelephoneNumberData-&gt;highlight);
-        m_currentHoveredHighlight = m_hoveredTelephoneNumberData-&gt;highlight;
-    } else {
-        if (!m_selectionHighlight)
-            maybeCreateSelectionHighlight();
</del><ins>+    if (a-&gt;type() == Highlight::Type::TelephoneNumber &amp;&amp; b-&gt;type() == Highlight::Type::TelephoneNumber &amp;&amp; areRangesEqual(a-&gt;range(), b-&gt;range()))
+        return true;
</ins><span class="cx"> 
</span><del>-        if (m_selectionHighlight &amp;&amp; mouseIsOverHighlight(m_selectionHighlight.get(), mouseIsOverButton))
-            m_currentHoveredHighlight = m_selectionHighlight;
-        else
-            m_currentHoveredHighlight = nullptr;
</del><ins>+    return false;
+}
+
+void ServicesOverlayController::determineActiveHighlight(bool&amp; mouseIsOverActiveHighlightButton)
+{
+    mouseIsOverActiveHighlightButton = false;
+
+    RefPtr&lt;Highlight&gt; oldActiveHighlight = m_activeHighlight.release();
+
+    for (auto&amp; highlight : m_potentialHighlights) {
+        if (highlight-&gt;type() == Highlight::Type::Selection) {
+            // If we've already found a new active highlight, and it's
+            // a telephone number highlight, prefer that over this selection highlight.
+            if (m_activeHighlight &amp;&amp; m_activeHighlight-&gt;type() == Highlight::Type::TelephoneNumber)
+                continue;
+
+            // If this highlight has no compatible services, it can't be active, unless we have telephone number highlights to show in the combined menu.
+            if (m_currentTelephoneNumberRanges.isEmpty() &amp;&amp; !hasRelevantSelectionServices())
+                continue;
+        }
+
+        // If this highlight isn't hovered, it can't be active.
+        bool mouseIsOverButton;
+        if (!mouseIsOverHighlight(*highlight, mouseIsOverButton))
+            continue;
+
+        m_activeHighlight = highlight;
+        mouseIsOverActiveHighlightButton = mouseIsOverButton;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (oldHoveredHighlight != m_currentHoveredHighlight) {
-        m_lastHoveredHighlightChangeTime = std::chrono::steady_clock::now();
</del><ins>+    if (!highlightsAreEquivalent(oldActiveHighlight.get(), m_activeHighlight.get())) {
+        m_lastActiveHighlightChangeTime = std::chrono::steady_clock::now();
</ins><span class="cx">         m_servicesOverlay-&gt;setNeedsDisplay();
</span><ins>+        m_currentMouseDownOnButtonHighlight = nullptr;
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    // If this event has nothing to do with the left button, it clears the current mouse down tracking and we're done processing it.
</del><ins>+bool ServicesOverlayController::mouseEvent(PageOverlay*, const WebMouseEvent&amp; event)
+{
+    m_mousePosition = m_webPage.corePage()-&gt;mainFrame().view()-&gt;rootViewToContents(event.position());
+
+    bool mouseIsOverActiveHighlightButton = false;
+    determineActiveHighlight(mouseIsOverActiveHighlightButton);
+
+    // Cancel the potential click if any button other than the left button changes state, and ignore the event.
</ins><span class="cx">     if (event.button() != WebMouseEvent::LeftButton) {
</span><span class="cx">         m_currentMouseDownOnButtonHighlight = nullptr;
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Check and see if the mouse went up and we have a current mouse down highlight button.
</del><ins>+    // If the mouse lifted while still over the highlight button that it went down on, then that is a click.
</ins><span class="cx">     if (event.type() == WebEvent::MouseUp) {
</span><del>-        RetainPtr&lt;DDHighlightRef&gt; mouseDownHighlight = std::move(m_currentMouseDownOnButtonHighlight);
</del><ins>+        RefPtr&lt;Highlight&gt; mouseDownHighlight = m_currentMouseDownOnButtonHighlight;
+        m_currentMouseDownOnButtonHighlight = nullptr;
</ins><span class="cx"> 
</span><del>-        // If the mouse lifted while still over the highlight button that it went down on, then that is a click.
-        if (mouseIsOverButton &amp;&amp; mouseDownHighlight &amp;&amp; remainingTimeUntilHighlightShouldBeShown() &lt;= std::chrono::steady_clock::duration::zero()) {
-            handleClick(m_mousePosition, mouseDownHighlight.get());
</del><ins>+        if (mouseIsOverActiveHighlightButton &amp;&amp; mouseDownHighlight &amp;&amp; remainingTimeUntilHighlightShouldBeShown() &lt;= std::chrono::steady_clock::duration::zero()) {
+            handleClick(m_mousePosition, *mouseDownHighlight);
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Check and see if the mouse moved within the confines of the DD highlight button.
</del><ins>+    // If the mouse moved outside of the button tracking a potential click, stop tracking the click.
</ins><span class="cx">     if (event.type() == WebEvent::MouseMove) {
</span><del>-        // Moving with the mouse button down is okay as long as the mouse never leaves the highlight button.
-        if (m_currentMouseDownOnButtonHighlight &amp;&amp; mouseIsOverButton)
</del><ins>+        if (m_currentMouseDownOnButtonHighlight &amp;&amp; mouseIsOverActiveHighlightButton)
</ins><span class="cx">             return true;
</span><span class="cx"> 
</span><span class="cx">         m_currentMouseDownOnButtonHighlight = nullptr;
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Check and see if the mouse went down over a DD highlight button.
</del><ins>+    // If the mouse went down over the active highlight's button, track this as a potential click.
</ins><span class="cx">     if (event.type() == WebEvent::MouseDown) {
</span><del>-        if (m_currentHoveredHighlight &amp;&amp; mouseIsOverButton) {
-            m_currentMouseDownOnButtonHighlight = m_currentHoveredHighlight;
</del><ins>+        if (m_activeHighlight &amp;&amp; mouseIsOverActiveHighlightButton) {
+            m_currentMouseDownOnButtonHighlight = m_activeHighlight;
</ins><span class="cx">             m_servicesOverlay-&gt;setNeedsDisplay();
</span><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><del>-        
</del><ins>+
</ins><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ServicesOverlayController::handleClick(const WebCore::IntPoint&amp; clickPoint, DDHighlightRef highlight)
</del><ins>+void ServicesOverlayController::handleClick(const WebCore::IntPoint&amp; clickPoint, Highlight&amp; highlight)
</ins><span class="cx"> {
</span><del>-    ASSERT(highlight);
-
-    FrameView* frameView = m_webPage-&gt;mainFrameView();
</del><ins>+    FrameView* frameView = m_webPage.mainFrameView();
</ins><span class="cx">     if (!frameView)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     IntPoint windowPoint = frameView-&gt;contentsToWindow(clickPoint);
</span><span class="cx"> 
</span><del>-    if (highlight == m_selectionHighlight) {
</del><ins>+    if (highlight.type() == Highlight::Type::Selection) {
</ins><span class="cx">         Vector&lt;String&gt; selectedTelephoneNumbers;
</span><span class="cx">         selectedTelephoneNumbers.reserveCapacity(m_currentTelephoneNumberRanges.size());
</span><span class="cx">         for (auto&amp; range : m_currentTelephoneNumberRanges)
</span><span class="cx">             selectedTelephoneNumbers.append(range-&gt;text());
</span><span class="cx"> 
</span><del>-        m_webPage-&gt;handleSelectionServiceClick(m_webPage-&gt;corePage()-&gt;mainFrame().selection(), selectedTelephoneNumbers, windowPoint);
-    } else if (m_hoveredTelephoneNumberData &amp;&amp; m_hoveredTelephoneNumberData-&gt;highlight == highlight)
-        m_webPage-&gt;handleTelephoneNumberClick(m_hoveredTelephoneNumberData-&gt;range-&gt;text(), windowPoint);
-    else
-        ASSERT_NOT_REACHED();
</del><ins>+        m_webPage.handleSelectionServiceClick(m_webPage.corePage()-&gt;mainFrame().selection(), selectedTelephoneNumbers, windowPoint);
+    } else if (highlight.type() == Highlight::Type::TelephoneNumber)
+        m_webPage.handleTelephoneNumberClick(highlight.range()-&gt;text(), windowPoint);
</ins><span class="cx"> }
</span><del>-    
</del><ins>+
</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>