Diff
Modified: trunk/Source/WebCore/ChangeLog (174523 => 174524)
--- trunk/Source/WebCore/ChangeLog 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/ChangeLog 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1,3 +1,61 @@
+2014-10-09 Tim Horton <timothy_hor...@apple.com>
+
+ Move ServicesOverlayController to WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=137416
+ <rdar://problem/18546283>
+
+ Reviewed by Anders Carlsson.
+
+ Move ServicesOverlayController from WebKit2 to WebCore, as it can be used by both Legacy WebKit and WebKit2.
+
+ * WebCore.xcodeproj/project.pbxproj:
+ * editing/Editor.cpp:
+ (WebCore::Editor::scanSelectionForTelephoneNumbers):
+ * editing/SelectionRectGatherer.cpp:
+ (WebCore::SelectionRectGatherer::Notifier::~Notifier):
+ Notify ServicesOverlayController of changes via Page instead of EditorClient.
+
+ * page/ChromeClient.h:
+ (WebCore::ChromeClient::handleTelephoneNumberClick):
+ (WebCore::ChromeClient::handleSelectionServiceClick):
+ (WebCore::ChromeClient::hasRelevantSelectionServices):
+ Add ChromeClient functions for services actions.
+
+ * page/EditorClient.h:
+ (WebCore::EditorClient::selectedTelephoneNumberRangesChanged): Deleted.
+ (WebCore::EditorClient::selectionRectsDidChange): Deleted.
+ Remove EditorClient functions for notifying ServicesOverlayController of changes,
+ because it lives in WebCore proper now.
+
+ * page/Page.cpp:
+ (WebCore::Page::Page):
+ * page/Page.h:
+ (WebCore::Page::servicesOverlayController):
+ Keep a ServicesOverlayController on Page.
+
+ * page/PageOverlay.cpp:
+ (WebCore::PageOverlay::mouseEvent):
+ Use windowToContents instead of rootViewToContents; events come in in window coordinates.
+
+ * page/PageOverlayController.cpp:
+ (WebCore::PageOverlayController::updateSettingsForLayer):
+ Get Settings from MainFrame, not Page.
+
+ * page/Settings.in:
+ Add servicesControlsEnabled setting.
+
+ * page/mac/ServicesOverlayController.h: Renamed from Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h.
+ * page/mac/ServicesOverlayController.mm: Renamed from Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm.
+ Moved from WebKit2. Mostly mechanical changes, plus:
+ - Use windowToContents instead of rootViewToContents; events come in in window coordinates.
+ - Cut off rebuild* if serviceControlsEnabled setting is false
+ - Don't create the overlay if serviceControlsEnabled setting is false
+ - Send click events via ChromeClient.
+ - Tie our lifetime to MainFrame instead of Page, and get lots of things from MainFrame instead.
+
+ * platform/Logging.h:
+ Add Services logging channel (moved from WebKit2).
+
2014-10-09 Brent Fulgham <bfulg...@apple.com>
[Win] Unreviewed build fix: Revert r174378
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (174523 => 174524)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1106,6 +1106,8 @@
2D8FEBDD143E3EF70072502B /* CSSCrossfadeValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D8FEBDB143E3EF70072502B /* CSSCrossfadeValue.h */; };
2D9066060BE141D400956998 /* LayoutState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D9066040BE141D400956998 /* LayoutState.cpp */; };
2D9066070BE141D400956998 /* LayoutState.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D9066050BE141D400956998 /* LayoutState.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 2D93AEE319DF5641002A86C3 /* ServicesOverlayController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D93AEE119DF5641002A86C3 /* ServicesOverlayController.h */; };
+ 2D93AEE419DF5641002A86C3 /* ServicesOverlayController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D93AEE219DF5641002A86C3 /* ServicesOverlayController.mm */; };
2D97F04719DD413C001EE9C3 /* MockPageOverlayClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DAAE32C19DCAF6000E002D2 /* MockPageOverlayClient.cpp */; };
2D97F04819DD4140001EE9C3 /* MockPageOverlayClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DAAE32D19DCAF6000E002D2 /* MockPageOverlayClient.h */; };
2D9A246E15B9BD0000D34527 /* DOMSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D9A246B15B9BBDD00D34527 /* DOMSecurityPolicy.h */; };
@@ -8106,6 +8108,8 @@
2D9066040BE141D400956998 /* LayoutState.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutState.cpp; sourceTree = "<group>"; };
2D9066050BE141D400956998 /* LayoutState.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LayoutState.h; sourceTree = "<group>"; };
2D90660C0665D937006B6F1A /* DataTransferMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataTransferMac.mm; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
+ 2D93AEE119DF5641002A86C3 /* ServicesOverlayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServicesOverlayController.h; sourceTree = "<group>"; };
+ 2D93AEE219DF5641002A86C3 /* ServicesOverlayController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ServicesOverlayController.mm; sourceTree = "<group>"; };
2D9A246A15B9BBDD00D34527 /* DOMSecurityPolicy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMSecurityPolicy.cpp; sourceTree = "<group>"; };
2D9A246B15B9BBDD00D34527 /* DOMSecurityPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMSecurityPolicy.h; sourceTree = "<group>"; };
2D9A247015B9C29500D34527 /* DOMDOMSecurityPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMDOMSecurityPolicy.h; sourceTree = "<group>"; };
@@ -17553,6 +17557,8 @@
A718788F0B2D04AC00A16ECE /* DragControllerMac.mm */,
93C09A7E0B064EEF005ABD4D /* EventHandlerMac.mm */,
1C26497B0D7E24EC00BD10F2 /* PageMac.cpp */,
+ 2D93AEE119DF5641002A86C3 /* ServicesOverlayController.h */,
+ 2D93AEE219DF5641002A86C3 /* ServicesOverlayController.mm */,
E1C2F2481533A2120083F974 /* SettingsMac.mm */,
26255F0218878E110006E1FD /* UserAgentMac.mm */,
F587854C02DE375901EA4122 /* WebCoreFrameView.h */,
@@ -23494,6 +23500,7 @@
FD315FFF12B0267600C1A359 /* ChannelMergerNode.h in Headers */,
FD31600212B0267600C1A359 /* ChannelSplitterNode.h in Headers */,
6550B6A0099DF0270090D781 /* CharacterData.h in Headers */,
+ 2D93AEE319DF5641002A86C3 /* ServicesOverlayController.h in Headers */,
97B8FFD116AE7F960038388D /* CharacterReferenceParserInlines.h in Headers */,
B2C3DA2A0D006C1D00EF6F26 /* CharsetData.h in Headers */,
F55B3DB21251F12D003EF269 /* CheckboxInputType.h in Headers */,
@@ -28400,6 +28407,7 @@
E1A5F99B0E7EAA2500AF85EA /* JSMessageChannelCustom.cpp in Sources */,
75793EC80D0CE72D007FC0AC /* JSMessageEvent.cpp in Sources */,
410B7E721045FAB000D8224F /* JSMessageEventCustom.cpp in Sources */,
+ 2D93AEE419DF5641002A86C3 /* ServicesOverlayController.mm in Sources */,
E1ADEDDB0E76BD93004A1A5E /* JSMessagePort.cpp in Sources */,
E1ADED470E76B8DD004A1A5E /* JSMessagePortCustom.cpp in Sources */,
A86629D209DA2B48009633A5 /* JSMouseEvent.cpp in Sources */,
Modified: trunk/Source/WebCore/editing/Editor.cpp (174523 => 174524)
--- trunk/Source/WebCore/editing/Editor.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/editing/Editor.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -61,6 +61,7 @@
#include "InsertListCommand.h"
#include "KeyboardEvent.h"
#include "KillRing.h"
+#include "MainFrame.h"
#include "ModifySelectionListLevel.h"
#include "NodeList.h"
#include "NodeTraversal.h"
@@ -102,6 +103,10 @@
#include <wtf/text/WTFString.h>
#endif
+#if PLATFORM(MAC)
+#include "ServicesOverlayController.h"
+#endif
+
namespace WebCore {
class ClearTextCommand : public DeleteSelectionCommand {
@@ -3348,7 +3353,7 @@
FrameSelection& frameSelection = m_frame.selection();
if (!frameSelection.isRange()) {
- client()->selectedTelephoneNumberRangesChanged();
+ m_frame.mainFrame().servicesOverlayController().selectedTelephoneNumberRangesChanged();
return;
}
RefPtr<Range> selectedRange = frameSelection.toNormalizedRange();
@@ -3376,7 +3381,7 @@
RefPtr<Range> extendedRange = extendedSelection.toNormalizedRange();
if (!extendedRange) {
- client()->selectedTelephoneNumberRangesChanged();
+ m_frame.mainFrame().servicesOverlayController().selectedTelephoneNumberRangesChanged();
return;
}
@@ -3388,7 +3393,7 @@
m_detectedTelephoneNumberRanges.append(range);
}
- client()->selectedTelephoneNumberRangesChanged();
+ m_frame.mainFrame().servicesOverlayController().selectedTelephoneNumberRangesChanged();
}
void Editor::scanRangeForTelephoneNumbers(Range& range, const StringView& stringView, Vector<RefPtr<Range>>& markedRanges)
Modified: trunk/Source/WebCore/editing/SelectionRectGatherer.cpp (174523 => 174524)
--- trunk/Source/WebCore/editing/SelectionRectGatherer.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/editing/SelectionRectGatherer.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -26,13 +26,15 @@
#include "config.h"
#include "SelectionRectGatherer.h"
+#if ENABLE(SERVICE_CONTROLS)
+
#include "Editor.h"
#include "EditorClient.h"
#include "Frame.h"
+#include "MainFrame.h"
#include "RenderView.h"
+#include "ServicesOverlayController.h"
-#if ENABLE(SERVICE_CONTROLS)
-
namespace WebCore {
SelectionRectGatherer::SelectionRectGatherer(RenderView& renderView)
@@ -70,8 +72,7 @@
SelectionRectGatherer::Notifier::~Notifier()
{
- if (EditorClient* client = m_gatherer.m_renderView.view().frame().editor().client())
- client->selectionRectsDidChange(m_gatherer.m_rects, m_gatherer.m_gapRects, m_gatherer.isTextOnly());
+ m_gatherer.m_renderView.view().frame().mainFrame().servicesOverlayController().selectionRectsDidChange(m_gatherer.m_rects, m_gatherer.m_gapRects, m_gatherer.isTextOnly());
}
std::unique_ptr<SelectionRectGatherer::Notifier> SelectionRectGatherer::clearAndCreateNotifier()
Modified: trunk/Source/WebCore/page/ChromeClient.h (174523 => 174524)
--- trunk/Source/WebCore/page/ChromeClient.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/ChromeClient.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -438,6 +438,14 @@
virtual bool unwrapCryptoKey(const Vector<uint8_t>&, Vector<uint8_t>&) const { return false; }
#endif
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)
+ virtual void handleTelephoneNumberClick(const String&, const WebCore::IntPoint&) { }
+#endif
+#if ENABLE(SERVICE_CONTROLS)
+ virtual void handleSelectionServiceClick(WebCore::FrameSelection&, const Vector<String>&, const WebCore::IntPoint&) { }
+ virtual bool hasRelevantSelectionServices(bool /* isTextOnly */) const { return false; }
+#endif
+
protected:
virtual ~ChromeClient() { }
};
Modified: trunk/Source/WebCore/page/EditorClient.h (174523 => 174524)
--- trunk/Source/WebCore/page/EditorClient.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/EditorClient.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -181,11 +181,6 @@
virtual void willSetInputMethodState() = 0;
virtual void setInputMethodState(bool enabled) = 0;
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
- virtual void selectedTelephoneNumberRangesChanged() { }
- virtual void selectionRectsDidChange(const Vector<LayoutRect>&, const Vector<GapRects>&, bool) { }
-#endif
-
// Support for global selections, used on platforms like the X Window System that treat
// selection as a type of clipboard.
virtual bool supportsGlobalSelection() { return false; }
Modified: trunk/Source/WebCore/page/MainFrame.cpp (174523 => 174524)
--- trunk/Source/WebCore/page/MainFrame.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/MainFrame.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -30,6 +30,10 @@
#include "ScrollLatchingState.h"
#include "WheelEventDeltaTracker.h"
+#if PLATFORM(MAC)
+#include "ServicesOverlayController.h"
+#endif
+
namespace WebCore {
inline MainFrame::MainFrame(Page& page, FrameLoaderClient& client)
@@ -37,7 +41,10 @@
, m_selfOnlyRefCount(0)
#if PLATFORM(MAC)
, m_latchingState(std::make_unique<ScrollLatchingState>())
+#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
+ , m_servicesOverlayController(std::make_unique<ServicesOverlayController>(*this))
#endif
+#endif
, m_recentWheelEventDeltaTracker(std::make_unique<WheelEventDeltaTracker>())
, m_pageOverlayController(std::make_unique<PageOverlayController>(*this))
{
Modified: trunk/Source/WebCore/page/MainFrame.h (174523 => 174524)
--- trunk/Source/WebCore/page/MainFrame.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/MainFrame.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -32,6 +32,7 @@
class PageOverlayController;
class ScrollLatchingState;
+class ServicesOverlayController;
class WheelEventDeltaTracker;
class MainFrame final : public Frame {
@@ -47,9 +48,13 @@
PageOverlayController& pageOverlayController() { return *m_pageOverlayController; }
#if PLATFORM(MAC)
+#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
+ ServicesOverlayController& servicesOverlayController() { return *m_servicesOverlayController; }
+#endif // ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
+
ScrollLatchingState* latchingState() { return m_latchingState.get(); }
void resetLatchingState();
-#endif
+#endif // PLATFORM(MAC)
private:
MainFrame(Page&, FrameLoaderClient&);
@@ -60,7 +65,10 @@
#if PLATFORM(MAC)
std::unique_ptr<ScrollLatchingState> m_latchingState;
+#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
+ std::unique_ptr<ServicesOverlayController> m_servicesOverlayController;
#endif
+#endif
std::unique_ptr<WheelEventDeltaTracker> m_recentWheelEventDeltaTracker;
std::unique_ptr<PageOverlayController> m_pageOverlayController;
};
Modified: trunk/Source/WebCore/page/PageOverlay.cpp (174523 => 174524)
--- trunk/Source/WebCore/page/PageOverlay.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/PageOverlay.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -168,7 +168,7 @@
IntPoint mousePositionInOverlayCoordinates(mouseEvent.position());
if (m_overlayType == PageOverlay::OverlayType::Document)
- mousePositionInOverlayCoordinates = m_page->mainFrame().view()->rootViewToContents(mousePositionInOverlayCoordinates);
+ mousePositionInOverlayCoordinates = m_page->mainFrame().view()->windowToContents(mousePositionInOverlayCoordinates);
// Ignore events outside the bounds.
if (!bounds().contains(mousePositionInOverlayCoordinates))
Modified: trunk/Source/WebCore/page/PageOverlayController.cpp (174523 => 174524)
--- trunk/Source/WebCore/page/PageOverlayController.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/PageOverlayController.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -260,7 +260,7 @@
void PageOverlayController::updateSettingsForLayer(GraphicsLayer& layer)
{
- Settings& settings = m_mainFrame.page()->settings();
+ Settings& settings = m_mainFrame.settings();
layer.setAcceleratesDrawing(settings.acceleratedDrawingEnabled());
layer.setShowDebugBorder(settings.showDebugBorders());
layer.setShowRepaintCounter(settings.showRepaintCounter());
Modified: trunk/Source/WebCore/page/Settings.in (174523 => 174524)
--- trunk/Source/WebCore/page/Settings.in 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/page/Settings.in 2014-10-09 20:53:02 UTC (rev 174524)
@@ -231,3 +231,5 @@
maximumSourceBufferSize type=int, initial=318767104, conditional=MEDIA_SOURCE
longMousePressEnabled initial=false
+
+serviceControlsEnabled initial=false, conditional=SERVICE_CONTROLS
Added: trunk/Source/WebCore/page/mac/ServicesOverlayController.h (0 => 174524)
--- trunk/Source/WebCore/page/mac/ServicesOverlayController.h (rev 0)
+++ trunk/Source/WebCore/page/mac/ServicesOverlayController.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ServicesOverlayController_h
+#define ServicesOverlayController_h
+
+#if (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)) && PLATFORM(MAC)
+
+#include "GraphicsLayerClient.h"
+#include "PageOverlay.h"
+#include "Range.h"
+#include "Timer.h"
+#include <wtf/RefCounted.h>
+
+typedef struct __DDHighlight DDHighlight, *DDHighlightRef;
+
+namespace WebCore {
+class LayoutRect;
+class MainFrame;
+struct GapRects;
+}
+
+namespace WebCore {
+
+class ServicesOverlayController : private PageOverlay::Client {
+public:
+ explicit ServicesOverlayController(MainFrame&);
+ ~ServicesOverlayController();
+
+ void selectedTelephoneNumberRangesChanged();
+ void selectionRectsDidChange(const Vector<LayoutRect>&, const Vector<GapRects>&, bool isTextOnly);
+
+private:
+ class Highlight : public RefCounted<Highlight>, private GraphicsLayerClient {
+ WTF_MAKE_NONCOPYABLE(Highlight);
+ public:
+ static PassRefPtr<Highlight> createForSelection(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<Range>);
+ static PassRefPtr<Highlight> createForTelephoneNumber(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<Range>);
+ ~Highlight();
+
+ void invalidate();
+
+ DDHighlightRef ddHighlight() const { return m_ddHighlight.get(); }
+ Range* range() const { return m_range.get(); }
+ GraphicsLayer* layer() const { return m_graphicsLayer.get(); }
+
+ enum class Type {
+ TelephoneNumber,
+ Selection
+ };
+ Type type() const { return m_type; }
+
+ void fadeIn();
+ void fadeOut();
+
+ void setDDHighlight(DDHighlightRef);
+
+ private:
+ explicit Highlight(ServicesOverlayController&, Type, RetainPtr<DDHighlightRef>, PassRefPtr<Range>);
+
+ // GraphicsLayerClient
+ virtual void notifyFlushRequired(const GraphicsLayer*) override;
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& inClip) override;
+ virtual float deviceScaleFactor() const override;
+
+ void didFinishFadeOutAnimation();
+
+ RetainPtr<DDHighlightRef> m_ddHighlight;
+ RefPtr<Range> m_range;
+ std::unique_ptr<GraphicsLayer> m_graphicsLayer;
+ Type m_type;
+ ServicesOverlayController* m_controller;
+ };
+
+ // PageOverlay::Client
+ virtual void pageOverlayDestroyed(PageOverlay&) override;
+ virtual void willMoveToPage(PageOverlay&, Page*) override;
+ virtual void didMoveToPage(PageOverlay&, Page*) override;
+ virtual void drawRect(PageOverlay&, GraphicsContext&, const IntRect& dirtyRect) override;
+ virtual bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) override;
+ virtual void didScrollFrame(PageOverlay&, Frame&) override;
+
+ void createOverlayIfNeeded();
+ void handleClick(const IntPoint&, Highlight&);
+
+ void drawHighlight(Highlight&, GraphicsContext&);
+
+ void replaceHighlightsOfTypePreservingEquivalentHighlights(HashSet<RefPtr<Highlight>>&, Highlight::Type);
+ void removeAllPotentialHighlightsOfType(Highlight::Type);
+ void buildPhoneNumberHighlights();
+ void buildSelectionHighlight();
+ void didRebuildPotentialHighlights();
+
+ void determineActiveHighlight(bool& mouseIsOverButton);
+ void clearActiveHighlight();
+ Highlight* activeHighlight() const { return m_activeHighlight.get(); }
+
+ Highlight* findTelephoneNumberHighlightContainingSelectionHighlight(Highlight&);
+
+ bool hasRelevantSelectionServices();
+
+ bool mouseIsOverHighlight(Highlight&, bool& mouseIsOverButton) const;
+ std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown(Highlight*) const;
+ void determineActiveHighlightTimerFired(Timer<ServicesOverlayController>&);
+
+ static bool highlightsAreEquivalent(const Highlight* a, const Highlight* b);
+
+ Vector<RefPtr<Range>> telephoneNumberRangesForFocusedFrame();
+
+ void didCreateHighlight(Highlight*);
+ void willDestroyHighlight(Highlight*);
+ void didFinishFadingOutHighlight(Highlight*);
+
+ MainFrame& mainFrame() const { return m_mainFrame; }
+
+ MainFrame& m_mainFrame;
+ PageOverlay* m_servicesOverlay;
+
+ RefPtr<Highlight> m_activeHighlight;
+ RefPtr<Highlight> m_nextActiveHighlight;
+ HashSet<RefPtr<Highlight>> m_potentialHighlights;
+ HashSet<RefPtr<Highlight>> m_animatingHighlights;
+
+ HashSet<Highlight*> m_highlights;
+
+ // FIXME: These should move onto Highlight.
+ Vector<LayoutRect> m_currentSelectionRects;
+ bool m_isTextOnly;
+
+ std::chrono::steady_clock::time_point m_lastSelectionChangeTime;
+ std::chrono::steady_clock::time_point m_nextActiveHighlightChangeTime;
+ std::chrono::steady_clock::time_point m_lastMouseUpTime;
+
+ RefPtr<Highlight> m_currentMouseDownOnButtonHighlight;
+ IntPoint m_mousePosition;
+
+ Timer<ServicesOverlayController> m_determineActiveHighlightTimer;
+};
+
+} // namespace WebKit
+
+#endif // (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)) && PLATFORM(MAC)
+#endif // ServicesOverlayController_h
Added: trunk/Source/WebCore/page/mac/ServicesOverlayController.mm (0 => 174524)
--- trunk/Source/WebCore/page/mac/ServicesOverlayController.mm (rev 0)
+++ trunk/Source/WebCore/page/mac/ServicesOverlayController.mm 2014-10-09 20:53:02 UTC (rev 174524)
@@ -0,0 +1,855 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "ServicesOverlayController.h"
+
+#if (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)) && PLATFORM(MAC)
+
+#import "Chrome.h"
+#import "ChromeClient.h"
+#import "Document.h"
+#import "Editor.h"
+#import "EventHandler.h"
+#import "FloatQuad.h"
+#import "FocusController.h"
+#import "FrameSelection.h"
+#import "FrameView.h"
+#import "GapRects.h"
+#import "GraphicsContext.h"
+#import "GraphicsLayer.h"
+#import "GraphicsLayerCA.h"
+#import "Logging.h"
+#import "MainFrame.h"
+#import "Page.h"
+#import "PageOverlayController.h"
+#import "PlatformCAAnimationMac.h"
+#import "Settings.h"
+#import "SoftLinking.h"
+#import <QuartzCore/QuartzCore.h>
+
+#if __has_include(<DataDetectors/DDHighlightDrawing.h>)
+#import <DataDetectors/DDHighlightDrawing.h>
+#else
+typedef struct __DDHighlight DDHighlight, *DDHighlightRef;
+#endif
+
+#if __has_include(<DataDetectors/DDHighlightDrawing_Private.h>)
+#import <DataDetectors/DDHighlightDrawing_Private.h>
+#endif
+
+const float highlightFadeAnimationDuration = 0.3;
+
+typedef NSUInteger DDHighlightStyle;
+static const DDHighlightStyle DDHighlightNoOutlineWithArrow = (1 << 16);
+static const DDHighlightStyle DDHighlightOutlineWithArrow = (1 << 16) | 1;
+
+SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
+SOFT_LINK(DataDetectors, DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection, DDHighlightRef, (CFAllocatorRef allocator, CGRect* rects, CFIndex count, CGRect globalVisibleRect, DDHighlightStyle style, Boolean withArrow, NSWritingDirection writingDirection, Boolean endsWithEOL, Boolean flipped), (allocator, rects, count, globalVisibleRect, style, withArrow, writingDirection, endsWithEOL, flipped))
+SOFT_LINK(DataDetectors, DDHighlightGetLayerWithContext, CGLayerRef, (DDHighlightRef highlight, CGContextRef context), (highlight, context))
+SOFT_LINK(DataDetectors, DDHighlightGetBoundingRect, CGRect, (DDHighlightRef highlight), (highlight))
+SOFT_LINK(DataDetectors, DDHighlightPointIsOnHighlight, Boolean, (DDHighlightRef highlight, CGPoint point, Boolean* onButton), (highlight, point, onButton))
+
+namespace WebCore {
+
+PassRefPtr<ServicesOverlayController::Highlight> ServicesOverlayController::Highlight::createForSelection(ServicesOverlayController& controller, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<Range> range)
+{
+ return adoptRef(new Highlight(controller, Type::Selection, ddHighlight, range));
+}
+
+PassRefPtr<ServicesOverlayController::Highlight> ServicesOverlayController::Highlight::createForTelephoneNumber(ServicesOverlayController& controller, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<Range> range)
+{
+ return adoptRef(new Highlight(controller, Type::TelephoneNumber, ddHighlight, range));
+}
+
+ServicesOverlayController::Highlight::Highlight(ServicesOverlayController& controller, Type type, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<WebCore::Range> range)
+ : m_range(range)
+ , m_type(type)
+ , m_controller(&controller)
+{
+ ASSERT(ddHighlight);
+ ASSERT(m_range);
+
+ Page* page = controller.mainFrame().page();
+ m_graphicsLayer = GraphicsLayer::create(page ? page->chrome().client().graphicsLayerFactory() : nullptr, *this);
+ m_graphicsLayer->setDrawsContent(true);
+
+ setDDHighlight(ddHighlight.get());
+
+ // 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())->platformCALayer()->setOpacity(0);
+
+ controller.didCreateHighlight(this);
+}
+
+ServicesOverlayController::Highlight::~Highlight()
+{
+ if (m_controller)
+ m_controller->willDestroyHighlight(this);
+}
+
+void ServicesOverlayController::Highlight::setDDHighlight(DDHighlightRef highlight)
+{
+ if (!m_controller)
+ return;
+
+ m_ddHighlight = highlight;
+
+ if (!m_ddHighlight)
+ return;
+
+ CGRect highlightBoundingRect = DDHighlightGetBoundingRect(m_ddHighlight.get());
+ m_graphicsLayer->setPosition(FloatPoint(highlightBoundingRect.origin));
+ m_graphicsLayer->setSize(FloatSize(highlightBoundingRect.size));
+
+ m_graphicsLayer->setNeedsDisplay();
+}
+
+void ServicesOverlayController::Highlight::invalidate()
+{
+ layer()->removeFromParent();
+ m_controller = nullptr;
+}
+
+void ServicesOverlayController::Highlight::notifyFlushRequired(const GraphicsLayer*)
+{
+ if (!m_controller)
+ return;
+
+ Page* page = m_controller->mainFrame().page();
+ if (!page)
+ return;
+
+ page->chrome().client().scheduleCompositingLayerFlush();
+}
+
+void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&)
+{
+ 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;
+
+ Page* page = m_controller->mainFrame().page();
+ if (!page)
+ return 1;
+
+ return page->deviceScaleFactor();
+}
+
+void ServicesOverlayController::Highlight::fadeIn()
+{
+ RetainPtr<CABasicAnimation> animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ [animation setDuration:highlightFadeAnimationDuration];
+ [animation setFillMode:kCAFillModeForwards];
+ [animation setRemovedOnCompletion:false];
+ [animation setToValue:@1];
+
+ RefPtr<PlatformCAAnimation> platformAnimation = PlatformCAAnimationMac::create(animation.get());
+ toGraphicsLayerCA(layer())->platformCALayer()->addAnimationForKey("FadeHighlightIn", platformAnimation.get());
+}
+
+void ServicesOverlayController::Highlight::fadeOut()
+{
+ RetainPtr<CABasicAnimation> animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ [animation setDuration:highlightFadeAnimationDuration];
+ [animation setFillMode:kCAFillModeForwards];
+ [animation setRemovedOnCompletion:false];
+ [animation setToValue:@0];
+
+ RefPtr<Highlight> retainedSelf = this;
+ [CATransaction begin];
+ [CATransaction setCompletionBlock:[retainedSelf] () {
+ retainedSelf->didFinishFadeOutAnimation();
+ }];
+
+ RefPtr<PlatformCAAnimation> platformAnimation = PlatformCAAnimationMac::create(animation.get());
+ toGraphicsLayerCA(layer())->platformCALayer()->addAnimationForKey("FadeHighlightOut", platformAnimation.get());
+ [CATransaction commit];
+}
+
+void ServicesOverlayController::Highlight::didFinishFadeOutAnimation()
+{
+ if (!m_controller)
+ return;
+
+ if (m_controller->activeHighlight() == this)
+ return;
+
+ layer()->removeFromParent();
+}
+
+static IntRect textQuadsToBoundingRectForRange(Range& range)
+{
+ Vector<FloatQuad> textQuads;
+ range.textQuads(textQuads);
+ FloatRect boundingRect;
+ for (auto& quad : textQuads)
+ boundingRect.unite(quad.boundingBox());
+ return enclosingIntRect(boundingRect);
+}
+
+ServicesOverlayController::ServicesOverlayController(MainFrame& mainFrame)
+ : m_mainFrame(mainFrame)
+ , m_servicesOverlay(nullptr)
+ , m_isTextOnly(false)
+ , m_determineActiveHighlightTimer(this, &ServicesOverlayController::determineActiveHighlightTimerFired)
+{
+}
+
+ServicesOverlayController::~ServicesOverlayController()
+{
+ for (auto& highlight : m_highlights)
+ highlight->invalidate();
+}
+
+void ServicesOverlayController::pageOverlayDestroyed(PageOverlay&)
+{
+ // Before the overlay is destroyed, it should have moved out of the Page,
+ // at which point we already cleared our back pointer.
+ ASSERT(!m_servicesOverlay);
+}
+
+void ServicesOverlayController::willMoveToPage(PageOverlay&, Page* page)
+{
+ if (page)
+ return;
+
+ ASSERT(m_servicesOverlay);
+ m_servicesOverlay = nullptr;
+}
+
+void ServicesOverlayController::didMoveToPage(PageOverlay&, Page*)
+{
+}
+
+static const uint8_t AlignmentNone = 0;
+static const uint8_t AlignmentLeft = 1 << 0;
+static const uint8_t AlignmentRight = 1 << 1;
+
+static void expandForGap(Vector<LayoutRect>& rects, uint8_t* alignments, const GapRects& gap)
+{
+ if (!gap.left().isEmpty()) {
+ LayoutUnit leftEdge = gap.left().x();
+ for (unsigned i = 0; i < rects.size(); ++i) {
+ if (alignments[i] & AlignmentLeft)
+ rects[i].shiftXEdgeTo(leftEdge);
+ }
+ }
+
+ if (!gap.right().isEmpty()) {
+ LayoutUnit rightEdge = gap.right().maxX();
+ for (unsigned i = 0; i < rects.size(); ++i) {
+ if (alignments[i] & AlignmentRight)
+ rects[i].shiftMaxXEdgeTo(rightEdge);
+ }
+ }
+}
+
+static inline void stitchRects(Vector<LayoutRect>& rects)
+{
+ if (rects.size() <= 1)
+ return;
+
+ Vector<LayoutRect> newRects;
+
+ // FIXME: Need to support vertical layout.
+ // First stitch together all the rects on the first line of the selection.
+ size_t indexFromStart = 0;
+ LayoutUnit firstTop = rects[indexFromStart].y();
+ LayoutRect& currentRect = rects[indexFromStart];
+ while (indexFromStart < rects.size() && rects[indexFromStart].y() == firstTop)
+ currentRect.unite(rects[indexFromStart++]);
+
+ newRects.append(currentRect);
+ if (indexFromStart == rects.size()) {
+ // All the rects are on one line. There is nothing else to do.
+ rects.swap(newRects);
+ return;
+ }
+
+ // Next stitch together all the rects on the last line of the selection.
+ size_t indexFromEnd = rects.size() - 1;
+ LayoutUnit lastTop = rects[indexFromEnd].y();
+ LayoutRect lastRect = rects[indexFromEnd];
+ while (indexFromEnd >= indexFromStart && rects[indexFromEnd].y() == lastTop)
+ lastRect.unite(rects[indexFromEnd--]);
+
+ // indexFromStart is the index of the first rectangle on the second line.
+ // indexFromEnd is the index of the last rectangle on the second to the last line.
+ // if they are equal, there is one additional rectangle for the line in the middle.
+ if (indexFromEnd == indexFromStart)
+ newRects.append(rects[indexFromStart]);
+
+ if (indexFromEnd <= indexFromStart) {
+ // There are no more rects to stitch. Just append the last line.
+ newRects.append(lastRect);
+ rects.swap(newRects);
+ return;
+ }
+
+ // Stitch together all the rects after the first line until the second to the last included.
+ currentRect = rects[indexFromStart];
+ while (indexFromStart != indexFromEnd)
+ currentRect.unite(rects[++indexFromStart]);
+
+ newRects.append(currentRect);
+ newRects.append(lastRect);
+
+ rects.swap(newRects);
+}
+
+static void compactRectsWithGapRects(Vector<LayoutRect>& rects, const Vector<GapRects>& gapRects)
+{
+ stitchRects(rects);
+
+ // FIXME: The following alignments are correct for LTR text.
+ // We should also account for RTL.
+ uint8_t alignments[3];
+ if (rects.size() == 1) {
+ alignments[0] = AlignmentLeft | AlignmentRight;
+ alignments[1] = AlignmentNone;
+ alignments[2] = AlignmentNone;
+ } else if (rects.size() == 2) {
+ alignments[0] = AlignmentRight;
+ alignments[1] = AlignmentLeft;
+ alignments[2] = AlignmentNone;
+ } else {
+ alignments[0] = AlignmentRight;
+ alignments[1] = AlignmentLeft | AlignmentRight;
+ alignments[2] = AlignmentLeft;
+ }
+
+ // Account for each GapRects by extending the edge of certain LayoutRects to meet the gap.
+ for (auto& gap : gapRects)
+ expandForGap(rects, alignments, gap);
+
+ // If we have 3 rects we might need one final GapRects to align the edges.
+ if (rects.size() == 3) {
+ LayoutRect left;
+ LayoutRect right;
+ for (unsigned i = 0; i < 3; ++i) {
+ if (alignments[i] & AlignmentLeft) {
+ if (left.isEmpty())
+ left = rects[i];
+ else if (rects[i].x() < left.x())
+ left = rects[i];
+ }
+ if (alignments[i] & AlignmentRight) {
+ if (right.isEmpty())
+ right = rects[i];
+ else if ((rects[i].x() + rects[i].width()) > (right.x() + right.width()))
+ right = rects[i];
+ }
+ }
+
+ if (!left.isEmpty() || !right.isEmpty()) {
+ GapRects gap;
+ gap.uniteLeft(left);
+ gap.uniteRight(right);
+ expandForGap(rects, alignments, gap);
+ }
+ }
+}
+
+void ServicesOverlayController::selectionRectsDidChange(const Vector<LayoutRect>& rects, const Vector<GapRects>& gapRects, bool isTextOnly)
+{
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1090
+ m_currentSelectionRects = rects;
+ m_isTextOnly = isTextOnly;
+
+ m_lastSelectionChangeTime = std::chrono::steady_clock::now();
+
+ compactRectsWithGapRects(m_currentSelectionRects, gapRects);
+
+ // DataDetectors needs these reversed in order to place the arrow in the right location.
+ m_currentSelectionRects.reverse();
+
+ LOG(Services, "ServicesOverlayController - Selection rects changed - Now have %lu\n", rects.size());
+
+ buildSelectionHighlight();
+#else
+ UNUSED_PARAM(rects);
+ UNUSED_PARAM(gapRects);
+ UNUSED_PARAM(isTextOnly);
+#endif
+}
+
+void ServicesOverlayController::selectedTelephoneNumberRangesChanged()
+{
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1090
+ LOG(Services, "ServicesOverlayController - Telephone number ranges changed\n");
+ buildPhoneNumberHighlights();
+#endif
+}
+
+bool ServicesOverlayController::mouseIsOverHighlight(Highlight& highlight, bool& mouseIsOverButton) const
+{
+ Boolean onButton;
+ bool hovered = DDHighlightPointIsOnHighlight(highlight.ddHighlight(), (CGPoint)m_mousePosition, &onButton);
+ mouseIsOverButton = onButton;
+ return hovered;
+}
+
+std::chrono::milliseconds ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown(Highlight* highlight) const
+{
+ if (!highlight)
+ return std::chrono::milliseconds::zero();
+
+ auto minimumTimeUntilHighlightShouldBeShown = 200_ms;
+ Page* page = m_mainFrame.page();
+ if (page && page->focusController().focusedOrMainFrame().selection().selection().isContentEditable())
+ minimumTimeUntilHighlightShouldBeShown = 1000_ms;
+
+ bool mousePressed = m_mainFrame.eventHandler().mousePressed();
+
+ // Highlight hysteresis is only for selection services, because telephone number highlights are already much more stable
+ // by virtue of being expanded to include the entire telephone number. However, we will still avoid highlighting
+ // telephone numbers while the mouse is down.
+ if (highlight->type() == Highlight::Type::TelephoneNumber)
+ return mousePressed ? minimumTimeUntilHighlightShouldBeShown : 0_ms;
+
+ auto now = std::chrono::steady_clock::now();
+ auto timeSinceLastSelectionChange = now - m_lastSelectionChangeTime;
+ auto timeSinceHighlightBecameActive = now - m_nextActiveHighlightChangeTime;
+ auto timeSinceLastMouseUp = mousePressed ? 0_ms : now - m_lastMouseUpTime;
+
+ auto remainingDelay = minimumTimeUntilHighlightShouldBeShown - std::min(std::min(timeSinceLastSelectionChange, timeSinceHighlightBecameActive), timeSinceLastMouseUp);
+ return std::chrono::duration_cast<std::chrono::milliseconds>(remainingDelay);
+}
+
+void ServicesOverlayController::determineActiveHighlightTimerFired(Timer<ServicesOverlayController>&)
+{
+ bool mouseIsOverButton;
+ determineActiveHighlight(mouseIsOverButton);
+}
+
+void ServicesOverlayController::drawRect(PageOverlay&, GraphicsContext&, const IntRect&)
+{
+}
+
+void ServicesOverlayController::clearActiveHighlight()
+{
+ if (!m_activeHighlight)
+ return;
+
+ if (m_currentMouseDownOnButtonHighlight == m_activeHighlight)
+ m_currentMouseDownOnButtonHighlight = nullptr;
+ m_activeHighlight = nullptr;
+}
+
+void ServicesOverlayController::removeAllPotentialHighlightsOfType(Highlight::Type type)
+{
+ Vector<RefPtr<Highlight>> highlightsToRemove;
+ for (auto& highlight : m_potentialHighlights) {
+ if (highlight->type() == type)
+ highlightsToRemove.append(highlight);
+ }
+
+ while (!highlightsToRemove.isEmpty())
+ m_potentialHighlights.remove(highlightsToRemove.takeLast());
+}
+
+void ServicesOverlayController::buildPhoneNumberHighlights()
+{
+ if (!DataDetectorsLibrary())
+ return;
+
+ if (!m_mainFrame.settings().serviceControlsEnabled())
+ return;
+
+ HashSet<RefPtr<Highlight>> newPotentialHighlights;
+
+ FrameView& mainFrameView = *m_mainFrame.view();
+
+ for (Frame* frame = &m_mainFrame; frame; frame = frame->tree().traverseNext()) {
+ auto& ranges = frame->editor().detectedTelephoneNumberRanges();
+ for (auto& range : ranges) {
+ // FIXME: This will choke if the range wraps around the edge of the view.
+ // What should we do in that case?
+ IntRect rect = textQuadsToBoundingRectForRange(*range);
+
+ // 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 = range->ownerDocument().view();
+ if (!viewForRange)
+ continue;
+ rect.setLocation(mainFrameView.windowToContents(viewForRange->contentsToWindow(rect.location())));
+
+ CGRect cgRect = rect;
+ RetainPtr<DDHighlightRef> ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, &cgRect, 1, mainFrameView.visibleContentRect(), DDHighlightOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
+
+ newPotentialHighlights.add(Highlight::createForTelephoneNumber(*this, ddHighlight, range));
+ }
+ }
+
+ replaceHighlightsOfTypePreservingEquivalentHighlights(newPotentialHighlights, Highlight::Type::TelephoneNumber);
+
+ didRebuildPotentialHighlights();
+}
+
+void ServicesOverlayController::buildSelectionHighlight()
+{
+ if (!DataDetectorsLibrary())
+ return;
+
+ if (!m_mainFrame.settings().serviceControlsEnabled())
+ return;
+
+ Page* page = m_mainFrame.page();
+ if (!page)
+ return;
+
+ HashSet<RefPtr<Highlight>> newPotentialHighlights;
+
+ Vector<CGRect> cgRects;
+ cgRects.reserveCapacity(m_currentSelectionRects.size());
+
+ RefPtr<Range> selectionRange = page->selection().firstRange();
+ if (selectionRange) {
+ FrameView* mainFrameView = m_mainFrame.view();
+ if (!mainFrameView)
+ return;
+
+ FrameView* viewForRange = selectionRange->ownerDocument().view();
+
+ for (auto& rect : m_currentSelectionRects) {
+ IntRect currentRect = snappedIntRect(rect);
+ currentRect.setLocation(mainFrameView->windowToContents(viewForRange->contentsToWindow(currentRect.location())));
+ cgRects.append((CGRect)currentRect);
+ }
+
+ if (!cgRects.isEmpty()) {
+ CGRect visibleRect = mainFrameView->visibleContentRect();
+ RetainPtr<DDHighlightRef> ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, cgRects.begin(), cgRects.size(), visibleRect, DDHighlightNoOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
+
+ newPotentialHighlights.add(Highlight::createForSelection(*this, ddHighlight, selectionRange));
+ }
+ }
+
+ replaceHighlightsOfTypePreservingEquivalentHighlights(newPotentialHighlights, Highlight::Type::Selection);
+
+ didRebuildPotentialHighlights();
+}
+
+void ServicesOverlayController::replaceHighlightsOfTypePreservingEquivalentHighlights(HashSet<RefPtr<Highlight>>& newPotentialHighlights, Highlight::Type type)
+{
+ // If any old Highlights are equivalent (by Range) to a new Highlight, reuse the old
+ // one so that any metadata is retained.
+ HashSet<RefPtr<Highlight>> reusedPotentialHighlights;
+
+ for (auto& oldHighlight : m_potentialHighlights) {
+ if (oldHighlight->type() != type)
+ continue;
+
+ for (auto& newHighlight : newPotentialHighlights) {
+ if (highlightsAreEquivalent(oldHighlight.get(), newHighlight.get())) {
+ oldHighlight->setDDHighlight(newHighlight->ddHighlight());
+
+ reusedPotentialHighlights.add(oldHighlight);
+ newPotentialHighlights.remove(newHighlight);
+
+ break;
+ }
+ }
+ }
+
+ removeAllPotentialHighlightsOfType(type);
+
+ m_potentialHighlights.add(newPotentialHighlights.begin(), newPotentialHighlights.end());
+ m_potentialHighlights.add(reusedPotentialHighlights.begin(), reusedPotentialHighlights.end());
+}
+
+bool ServicesOverlayController::hasRelevantSelectionServices()
+{
+ if (Page* page = m_mainFrame.page())
+ return page->chrome().client().hasRelevantSelectionServices(m_isTextOnly);
+ return false;
+}
+
+void ServicesOverlayController::didRebuildPotentialHighlights()
+{
+ if (m_potentialHighlights.isEmpty()) {
+ if (m_servicesOverlay)
+ m_mainFrame.pageOverlayController().uninstallPageOverlay(m_servicesOverlay, PageOverlay::FadeMode::DoNotFade);
+ return;
+ }
+
+ if (telephoneNumberRangesForFocusedFrame().isEmpty() && !hasRelevantSelectionServices())
+ return;
+
+ createOverlayIfNeeded();
+
+ bool mouseIsOverButton;
+ determineActiveHighlight(mouseIsOverButton);
+}
+
+void ServicesOverlayController::createOverlayIfNeeded()
+{
+ if (m_servicesOverlay)
+ return;
+
+ if (!m_mainFrame.settings().serviceControlsEnabled())
+ return;
+
+ RefPtr<PageOverlay> overlay = PageOverlay::create(*this, PageOverlay::OverlayType::Document);
+ m_servicesOverlay = overlay.get();
+ m_mainFrame.pageOverlayController().installPageOverlay(overlay.release(), PageOverlay::FadeMode::DoNotFade);
+}
+
+Vector<RefPtr<Range>> ServicesOverlayController::telephoneNumberRangesForFocusedFrame()
+{
+ Page* page = m_mainFrame.page();
+ if (!page)
+ return { };
+
+ return page->focusController().focusedOrMainFrame().editor().detectedTelephoneNumberRanges();
+}
+
+bool ServicesOverlayController::highlightsAreEquivalent(const Highlight* a, const Highlight* b)
+{
+ if (a == b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ if (a->type() == b->type() && areRangesEqual(a->range(), b->range()))
+ return true;
+
+ return false;
+}
+
+ServicesOverlayController::Highlight* ServicesOverlayController::findTelephoneNumberHighlightContainingSelectionHighlight(Highlight& selectionHighlight)
+{
+ if (selectionHighlight.type() != Highlight::Type::Selection)
+ return nullptr;
+
+ Page* page = m_mainFrame.page();
+ if (!page)
+ return nullptr;
+
+ const VisibleSelection& selection = page->selection();
+ if (!selection.isRange())
+ return nullptr;
+
+ RefPtr<Range> activeSelectionRange = selection.toNormalizedRange();
+ if (!activeSelectionRange)
+ return nullptr;
+
+ for (auto& highlight : m_potentialHighlights) {
+ if (highlight->type() != Highlight::Type::TelephoneNumber)
+ continue;
+
+ if (highlight->range()->contains(*activeSelectionRange))
+ return highlight.get();
+ }
+
+ return nullptr;
+}
+
+void ServicesOverlayController::determineActiveHighlight(bool& mouseIsOverActiveHighlightButton)
+{
+ mouseIsOverActiveHighlightButton = false;
+
+ RefPtr<Highlight> newActiveHighlight;
+
+ for (auto& highlight : m_potentialHighlights) {
+ if (highlight->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 (newActiveHighlight && newActiveHighlight->type() == Highlight::Type::TelephoneNumber)
+ continue;
+
+ // If this highlight has no compatible services, it can't be active.
+ if (!hasRelevantSelectionServices())
+ continue;
+ }
+
+ // If this highlight isn't hovered, it can't be active.
+ bool mouseIsOverButton;
+ if (!mouseIsOverHighlight(*highlight, mouseIsOverButton))
+ continue;
+
+ newActiveHighlight = highlight;
+ mouseIsOverActiveHighlightButton = mouseIsOverButton;
+ }
+
+ // If our new active highlight is a selection highlight that is completely contained
+ // by one of the phone number highlights, we'll make the phone number highlight active even if it's not hovered.
+ if (newActiveHighlight && newActiveHighlight->type() == Highlight::Type::Selection) {
+ if (Highlight* containedTelephoneNumberHighlight = findTelephoneNumberHighlightContainingSelectionHighlight(*newActiveHighlight)) {
+ newActiveHighlight = containedTelephoneNumberHighlight;
+
+ // We will always initially choose the telephone number highlight over the selection highlight if the
+ // mouse is over the telephone number highlight's button, so we know that it's not hovered if we got here.
+ mouseIsOverActiveHighlightButton = false;
+ }
+ }
+
+ if (!this->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();
+ }
+
+ m_currentMouseDownOnButtonHighlight = nullptr;
+
+ if (m_activeHighlight) {
+ m_activeHighlight->fadeOut();
+ m_activeHighlight = nullptr;
+ }
+
+ auto remainingTimeUntilHighlightShouldBeShown = this->remainingTimeUntilHighlightShouldBeShown(newActiveHighlight.get());
+ if (remainingTimeUntilHighlightShouldBeShown > std::chrono::steady_clock::duration::zero()) {
+ m_determineActiveHighlightTimer.startOneShot(remainingTimeUntilHighlightShouldBeShown);
+ return;
+ }
+
+ m_activeHighlight = m_nextActiveHighlight.release();
+
+ if (m_activeHighlight) {
+ m_servicesOverlay->layer().addChild(m_activeHighlight->layer());
+ m_activeHighlight->fadeIn();
+ }
+ }
+}
+
+bool ServicesOverlayController::mouseEvent(PageOverlay&, const PlatformMouseEvent& event)
+{
+ m_mousePosition = m_mainFrame.view()->windowToContents(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.
+ if (event.button() != MouseButton::LeftButton) {
+ m_currentMouseDownOnButtonHighlight = nullptr;
+ return false;
+ }
+
+ // If the mouse lifted while still over the highlight button that it went down on, then that is a click.
+ if (event.type() == PlatformEvent::MouseReleased) {
+ RefPtr<Highlight> mouseDownHighlight = m_currentMouseDownOnButtonHighlight;
+ m_currentMouseDownOnButtonHighlight = nullptr;
+
+ m_lastMouseUpTime = std::chrono::steady_clock::now();
+
+ if (mouseIsOverActiveHighlightButton && mouseDownHighlight) {
+ handleClick(m_mousePosition, *mouseDownHighlight);
+ return true;
+ }
+
+ return false;
+ }
+
+ // If the mouse moved outside of the button tracking a potential click, stop tracking the click.
+ if (event.type() == PlatformEvent::MouseMoved) {
+ if (m_currentMouseDownOnButtonHighlight && mouseIsOverActiveHighlightButton)
+ return true;
+
+ m_currentMouseDownOnButtonHighlight = nullptr;
+ return false;
+ }
+
+ // If the mouse went down over the active highlight's button, track this as a potential click.
+ if (event.type() == PlatformEvent::MousePressed) {
+ if (m_activeHighlight && mouseIsOverActiveHighlightButton) {
+ m_currentMouseDownOnButtonHighlight = m_activeHighlight;
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+void ServicesOverlayController::didScrollFrame(PageOverlay&, Frame& frame)
+{
+ if (frame.isMainFrame())
+ return;
+
+ buildPhoneNumberHighlights();
+ buildSelectionHighlight();
+
+ bool mouseIsOverActiveHighlightButton;
+ determineActiveHighlight(mouseIsOverActiveHighlightButton);
+}
+
+void ServicesOverlayController::handleClick(const IntPoint& clickPoint, Highlight& highlight)
+{
+ FrameView* frameView = m_mainFrame.view();
+ if (!frameView)
+ return;
+
+ Page* page = m_mainFrame.page();
+ if (!page)
+ return;
+
+ IntPoint windowPoint = frameView->contentsToWindow(clickPoint);
+
+ if (highlight.type() == Highlight::Type::Selection) {
+ auto telephoneNumberRanges = telephoneNumberRangesForFocusedFrame();
+ Vector<String> selectedTelephoneNumbers;
+ selectedTelephoneNumbers.reserveCapacity(telephoneNumberRanges.size());
+ for (auto& range : telephoneNumberRanges)
+ selectedTelephoneNumbers.append(range->text());
+
+ page->chrome().client().handleSelectionServiceClick(page->focusController().focusedOrMainFrame().selection(), selectedTelephoneNumbers, windowPoint);
+ } else if (highlight.type() == Highlight::Type::TelephoneNumber)
+ page->chrome().client().handleTelephoneNumberClick(highlight.range()->text(), windowPoint);
+}
+
+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);
+}
+
+} // namespace WebKit
+
+#endif // (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)) && PLATFORM(MAC)
Modified: trunk/Source/WebCore/platform/Logging.h (174523 => 174524)
--- trunk/Source/WebCore/platform/Logging.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebCore/platform/Logging.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -72,6 +72,7 @@
M(WebAudio) \
M(WebGL) \
M(WebReplay) \
+ M(Services) \
#define DECLARE_LOG_CHANNEL(name) \
extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name);
Modified: trunk/Source/WebKit2/ChangeLog (174523 => 174524)
--- trunk/Source/WebKit2/ChangeLog 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/ChangeLog 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1,3 +1,40 @@
+2014-10-09 Tim Horton <timothy_hor...@apple.com>
+
+ Move ServicesOverlayController to WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=137416
+ <rdar://problem/18546283>
+
+ Reviewed by Anders Carlsson.
+
+ * Platform/Logging.h:
+ Move Services logging channel to WebCore.
+
+ * WebKit2.xcodeproj/project.pbxproj:
+ * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+ (WebKit::WebChromeClient::handleTelephoneNumberClick):
+ (WebKit::WebChromeClient::handleSelectionServiceClick):
+ (WebKit::WebChromeClient::hasRelevantSelectionServices):
+ Implement services-related ChromeClient callbacks.
+ Clicks are forwarded to WebPageMac where they do what they used to;
+ hasRelevantSelectionServices is implemented as it was when it lived
+ inside ServicesOverlayController.
+
+ * WebProcess/WebCoreSupport/WebChromeClient.h:
+ * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+ (WebKit::WebEditorClient::selectedTelephoneNumberRangesChanged): Deleted.
+ (WebKit::WebEditorClient::selectionRectsDidChange): Deleted.
+ * WebProcess/WebCoreSupport/WebEditorClient.h:
+ Remove WebEditorClient overrides for now-removed functions.
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::WebPage):
+ (WebKit::WebPage::updatePreferences):
+ Forward serviceControlsEnabled setting to WebCore.
+
+ (WebKit::WebPage::servicesOverlayController): Deleted.
+ * WebProcess/WebPage/WebPage.h:
+ (WebKit::WebPage::serviceControlsEnabled): Deleted.
+
2014-10-09 Andy Estes <aes...@apple.com>
[iOS] Crash in CFURLDownloadClient.didFail if the download has a null resumeData
Modified: trunk/Source/WebKit2/Platform/Logging.h (174523 => 174524)
--- trunk/Source/WebKit2/Platform/Logging.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/Platform/Logging.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -51,7 +51,6 @@
M(TextInput) \
M(View) \
M(IDB) \
- M(Services) \
#define DECLARE_LOG_CHANNEL(name) \
extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name);
Modified: trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (174523 => 174524)
--- trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj 2014-10-09 20:53:02 UTC (rev 174524)
@@ -931,7 +931,6 @@
518E8F0B16B2093700E91429 /* DownloadManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518E8F0216B2093700E91429 /* DownloadManager.cpp */; };
518E8F0C16B2093700E91429 /* DownloadManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 518E8F0316B2093700E91429 /* DownloadManager.h */; };
518E8F0D16B2093700E91429 /* DownloadMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 518E8F0516B2093700E91429 /* DownloadMac.mm */; };
- 5192D5761961FD0300CD19AA /* ServicesOverlayController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5192D5751961FD0300CD19AA /* ServicesOverlayController.mm */; };
51933DEF1965EB31008AC3EA /* MenuUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 51933DEB1965EB24008AC3EA /* MenuUtilities.h */; };
51933DF01965EB31008AC3EA /* MenuUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51933DEC1965EB24008AC3EA /* MenuUtilities.mm */; };
51A4D5A916CAC4FF000E615E /* StatisticsRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51A4D5A816CAC4FF000E615E /* StatisticsRequest.cpp */; };
@@ -2949,8 +2948,6 @@
518E8F0216B2093700E91429 /* DownloadManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DownloadManager.cpp; path = Downloads/DownloadManager.cpp; sourceTree = "<group>"; };
518E8F0316B2093700E91429 /* DownloadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DownloadManager.h; path = Downloads/DownloadManager.h; sourceTree = "<group>"; };
518E8F0516B2093700E91429 /* DownloadMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DownloadMac.mm; sourceTree = "<group>"; };
- 5192D5711961FA2F00CD19AA /* ServicesOverlayController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ServicesOverlayController.h; sourceTree = "<group>"; };
- 5192D5751961FD0300CD19AA /* ServicesOverlayController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ServicesOverlayController.mm; sourceTree = "<group>"; };
51933DEB1965EB24008AC3EA /* MenuUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuUtilities.h; sourceTree = "<group>"; };
51933DEC1965EB24008AC3EA /* MenuUtilities.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MenuUtilities.mm; sourceTree = "<group>"; };
51A4D5A816CAC4FF000E615E /* StatisticsRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StatisticsRequest.cpp; sourceTree = "<group>"; };
@@ -5699,7 +5696,6 @@
7CF47FF917275C57008ACB91 /* PageBanner.h */,
2D5C9D0319C81D8F00B3C5C1 /* WebPageOverlay.cpp */,
2D5C9D0419C81D8F00B3C5C1 /* WebPageOverlay.h */,
- 5192D5711961FA2F00CD19AA /* ServicesOverlayController.h */,
2D819B99186275B3001F03D1 /* ViewGestureGeometryCollector.cpp */,
2D819B9A186275B3001F03D1 /* ViewGestureGeometryCollector.h */,
2D819B9B186275B3001F03D1 /* ViewGestureGeometryCollector.messages.in */,
@@ -6468,7 +6464,6 @@
1AB16AE7164B3A8800290D62 /* RemoteLayerTreeContext.mm */,
1AB16ADC1648598400290D62 /* RemoteLayerTreeDrawingArea.h */,
1AB16ADB1648598400290D62 /* RemoteLayerTreeDrawingArea.mm */,
- 5192D5751961FD0300CD19AA /* ServicesOverlayController.mm */,
1AAF263714687C39004A1E8A /* TiledCoreAnimationDrawingArea.h */,
1AAF263614687C39004A1E8A /* TiledCoreAnimationDrawingArea.mm */,
1C8E2DAD1278C5B200BC7BD0 /* WebInspectorUIMac.mm */,
@@ -8729,7 +8724,6 @@
512F589612A8838800629530 /* AuthenticationChallengeProxy.cpp in Sources */,
1AE00D4C182D6EB000087DD7 /* WKBrowsingContextHandle.mm in Sources */,
512F589812A8838800629530 /* AuthenticationDecisionListener.cpp in Sources */,
- 5192D5761961FD0300CD19AA /* ServicesOverlayController.mm in Sources */,
518E8EF816B2091C00E91429 /* AuthenticationManager.cpp in Sources */,
518E8EFB16B2091C00E91429 /* AuthenticationManager.mac.mm in Sources */,
512F58A212A883AD00629530 /* AuthenticationManagerMessageReceiver.cpp in Sources */,
Modified: trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1074,5 +1074,24 @@
}
#endif
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)
+void WebChromeClient::handleTelephoneNumberClick(const String& number, const WebCore::IntPoint& point)
+{
+ m_page->handleTelephoneNumberClick(number, point);
+}
+#endif
+#if ENABLE(SERVICE_CONTROLS)
+void WebChromeClient::handleSelectionServiceClick(WebCore::FrameSelection& selection, const Vector<String>& telephoneNumbers, const WebCore::IntPoint& point)
+{
+ m_page->handleSelectionServiceClick(selection, telephoneNumbers, point);
+}
+
+bool WebChromeClient::hasRelevantSelectionServices(bool isTextOnly) const
+{
+ return (isTextOnly && WebProcess::shared().hasSelectionServices()) || WebProcess::shared().hasRichContentServices();
+}
+
+#endif
+
} // namespace WebKit
Modified: trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -305,6 +305,14 @@
virtual bool unwrapCryptoKey(const Vector<uint8_t>&, Vector<uint8_t>&) const override;
#endif
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)
+ virtual void handleTelephoneNumberClick(const String& number, const WebCore::IntPoint&) override;
+#endif
+#if ENABLE(SERVICE_CONTROLS)
+ virtual void handleSelectionServiceClick(WebCore::FrameSelection&, const Vector<String>& telephoneNumbers, const WebCore::IntPoint&) override;
+ virtual bool hasRelevantSelectionServices(bool isTextOnly) const override;
+#endif
+
String m_cachedToolTip;
mutable RefPtr<WebFrame> m_cachedFrameSetLargestFrame;
mutable bool m_cachedMainFrameHasHorizontalScrollbar;
Modified: trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -27,7 +27,6 @@
#include "WebEditorClient.h"
#include "EditorState.h"
-#include "ServicesOverlayController.h"
#include "WebCoreArgumentCoders.h"
#include "WebFrame.h"
#include "WebPage.h"
@@ -531,20 +530,4 @@
#endif
}
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
-void WebEditorClient::selectedTelephoneNumberRangesChanged()
-{
-#if PLATFORM(MAC)
- m_page->servicesOverlayController().selectedTelephoneNumberRangesChanged();
-#endif
-}
-void WebEditorClient::selectionRectsDidChange(const Vector<LayoutRect>& rects, const Vector<GapRects>& gapRects, bool isTextOnly)
-{
-#if PLATFORM(MAC)
- if (m_page->serviceControlsEnabled())
- m_page->servicesOverlayController().selectionRectsDidChange(rects, gapRects, isTextOnly);
-#endif
-}
-#endif // ENABLE(SERVICE_CONTROLS) && ENABLE(TELEPHONE_NUMBER_DETECTION)
-
} // namespace WebKit
Modified: trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebCoreSupport/WebEditorClient.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -168,11 +168,6 @@
virtual bool supportsGlobalSelection() override;
-#if ENABLE(TELEPHONE_NUMBER_DETECTION) || ENABLE(SERVICE_CONTROLS)
- virtual void selectedTelephoneNumberRangesChanged() override;
- virtual void selectionRectsDidChange(const Vector<WebCore::LayoutRect>&, const Vector<WebCore::GapRects>&, bool isTextOnly) override;
-#endif
-
WebPage* m_page;
};
Deleted: trunk/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ServicesOverlayController.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ServicesOverlayController_h
-#define ServicesOverlayController_h
-
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
-
-#include "WebFrame.h"
-#include <WebCore/GraphicsLayerClient.h>
-#include <WebCore/PageOverlay.h>
-#include <WebCore/Range.h>
-#include <WebCore/Timer.h>
-#include <wtf/RefCounted.h>
-
-typedef void* DDHighlightRef;
-
-namespace WebCore {
-class LayoutRect;
-struct GapRects;
-}
-
-namespace WebKit {
-
-class WebPage;
-
-class ServicesOverlayController : private WebCore::PageOverlay::Client {
-public:
- ServicesOverlayController(WebPage&);
- ~ServicesOverlayController();
-
- void selectedTelephoneNumberRangesChanged();
- void selectionRectsDidChange(const Vector<WebCore::LayoutRect>&, const Vector<WebCore::GapRects>&, bool isTextOnly);
-
-private:
- class Highlight : public RefCounted<Highlight>, private WebCore::GraphicsLayerClient {
- WTF_MAKE_NONCOPYABLE(Highlight);
- public:
- static PassRefPtr<Highlight> createForSelection(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
- static PassRefPtr<Highlight> createForTelephoneNumber(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
- ~Highlight();
-
- void invalidate();
-
- DDHighlightRef ddHighlight() const { return m_ddHighlight.get(); }
- WebCore::Range* range() const { return m_range.get(); }
- WebCore::GraphicsLayer* layer() const { return m_graphicsLayer.get(); }
-
- enum class Type {
- TelephoneNumber,
- Selection
- };
- Type type() const { return m_type; }
-
- void fadeIn();
- void fadeOut();
-
- void setDDHighlight(DDHighlightRef);
-
- private:
- explicit Highlight(ServicesOverlayController&, Type, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
-
- // GraphicsLayerClient
- virtual void notifyFlushRequired(const WebCore::GraphicsLayer*) override;
- virtual void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& inClip) override;
- virtual float deviceScaleFactor() const override;
-
- void didFinishFadeOutAnimation();
-
- RetainPtr<DDHighlightRef> m_ddHighlight;
- RefPtr<WebCore::Range> m_range;
- std::unique_ptr<WebCore::GraphicsLayer> m_graphicsLayer;
- Type m_type;
- ServicesOverlayController* m_controller;
- };
-
- // PageOverlay::Client
- virtual void pageOverlayDestroyed(WebCore::PageOverlay&) override;
- virtual void willMoveToPage(WebCore::PageOverlay&, WebCore::Page*) override;
- virtual void didMoveToPage(WebCore::PageOverlay&, WebCore::Page*) override;
- virtual void drawRect(WebCore::PageOverlay&, WebCore::GraphicsContext&, const WebCore::IntRect& dirtyRect) override;
- virtual bool mouseEvent(WebCore::PageOverlay&, const WebCore::PlatformMouseEvent&) override;
- virtual void didScrollFrame(WebCore::PageOverlay&, WebCore::Frame&) override;
-
- void createOverlayIfNeeded();
- void handleClick(const WebCore::IntPoint&, Highlight&);
-
- void drawHighlight(Highlight&, WebCore::GraphicsContext&);
-
- void replaceHighlightsOfTypePreservingEquivalentHighlights(HashSet<RefPtr<Highlight>>&, Highlight::Type);
- void removeAllPotentialHighlightsOfType(Highlight::Type);
- void buildPhoneNumberHighlights();
- void buildSelectionHighlight();
- void didRebuildPotentialHighlights();
-
- void determineActiveHighlight(bool& mouseIsOverButton);
- void clearActiveHighlight();
- Highlight* activeHighlight() const { return m_activeHighlight.get(); }
-
- Highlight* findTelephoneNumberHighlightContainingSelectionHighlight(Highlight&);
-
- bool hasRelevantSelectionServices();
-
- bool mouseIsOverHighlight(Highlight&, bool& mouseIsOverButton) const;
- std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown(Highlight*) const;
- void determineActiveHighlightTimerFired(WebCore::Timer<ServicesOverlayController>&);
-
- static bool highlightsAreEquivalent(const Highlight* a, const Highlight* b);
-
- Vector<RefPtr<WebCore::Range>> telephoneNumberRangesForFocusedFrame();
-
- void didCreateHighlight(Highlight*);
- void willDestroyHighlight(Highlight*);
- void didFinishFadingOutHighlight(Highlight*);
-
- WebPage& webPage() const { return m_webPage; }
-
- WebPage& m_webPage;
- WebCore::PageOverlay* m_servicesOverlay;
-
- RefPtr<Highlight> m_activeHighlight;
- RefPtr<Highlight> m_nextActiveHighlight;
- HashSet<RefPtr<Highlight>> m_potentialHighlights;
- HashSet<RefPtr<Highlight>> m_animatingHighlights;
-
- HashSet<Highlight*> m_highlights;
-
- // FIXME: These should move onto Highlight.
- Vector<WebCore::LayoutRect> m_currentSelectionRects;
- bool m_isTextOnly;
-
- std::chrono::steady_clock::time_point m_lastSelectionChangeTime;
- std::chrono::steady_clock::time_point m_nextActiveHighlightChangeTime;
- std::chrono::steady_clock::time_point m_lastMouseUpTime;
-
- RefPtr<Highlight> m_currentMouseDownOnButtonHighlight;
- WebCore::IntPoint m_mousePosition;
-
- WebCore::Timer<ServicesOverlayController> m_determineActiveHighlightTimer;
-};
-
-} // namespace WebKit
-
-#endif // ENABLE(SERVICE_CONTROLS) && ENABLE(TELEPHONE_NUMBER_DETECTION)
-#endif // ServicesOverlayController_h
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp 2014-10-09 20:53:02 UTC (rev 174524)
@@ -48,7 +48,6 @@
#include "PluginProxy.h"
#include "PluginView.h"
#include "PrintInfo.h"
-#include "ServicesOverlayController.h"
#include "SessionState.h"
#include "SessionStateConversion.h"
#include "SessionTracker.h"
@@ -263,9 +262,6 @@
, m_numberOfPrimarySnapshotDetectionAttempts(0)
, m_determinePrimarySnapshottedPlugInTimer(RunLoop::main(), this, &WebPage::determinePrimarySnapshottedPlugInTimerFired)
#endif
-#if ENABLE(SERVICE_CONTROLS)
- , m_serviceControlsEnabled(false)
-#endif
, m_layerHostingMode(parameters.layerHostingMode)
#if PLATFORM(COCOA)
, m_pdfPluginEnabled(false)
@@ -2626,10 +2622,6 @@
m_pdfPluginEnabled = store.getBoolValueForKey(WebPreferencesKey::pdfPluginEnabledKey());
#endif
-#if ENABLE(SERVICE_CONTROLS)
- m_serviceControlsEnabled = store.getBoolValueForKey(WebPreferencesKey::serviceControlsEnabledKey());
-#endif
-
// FIXME: This should be generated from macro expansion for all preferences,
// but we currently don't match the naming of WebCore exactly so we are
// handrolling the boolean and integer preferences until that is fixed.
@@ -2845,6 +2837,10 @@
RuntimeEnabledFeatures::sharedFeatures().setGamepadsEnabled(store.getBoolValueForKey(WebPreferencesKey::gamepadsEnabledKey()));
#endif
+#if ENABLE(SERVICE_CONTROLS)
+ settings.setServiceControlsEnabled(store.getBoolValueForKey(WebPreferencesKey::serviceControlsEnabledKey()));
+#endif
+
if (store.getBoolValueForKey(WebPreferencesKey::pageVisibilityBasedProcessSuppressionEnabledKey()))
m_processSuppressionDisabledByWebPreference.stop();
else
@@ -4778,17 +4774,7 @@
#endif
return false;
}
-
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
-ServicesOverlayController& WebPage::servicesOverlayController()
-{
- if (!m_servicesOverlayController)
- m_servicesOverlayController = std::make_unique<ServicesOverlayController>(*this);
- return *m_servicesOverlayController;
-}
-#endif
-
void WebPage::didChangeScrollOffsetForFrame(Frame* frame)
{
if (!frame->isMainFrame())
Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h 2014-10-09 20:53:02 UTC (rev 174524)
@@ -141,7 +141,6 @@
class NotificationPermissionRequestManager;
class PageBanner;
class PluginView;
-class ServicesOverlayController;
class VisibleContentRectUpdateInfo;
class WebColorChooser;
class WebContextMenu;
@@ -828,11 +827,9 @@
// While this is not ideal, it does not have to be applied to every platform at the moment.
static bool synchronousMessagesShouldSpinRunLoop();
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
- ServicesOverlayController& servicesOverlayController();
+#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
void handleTelephoneNumberClick(const String& number, const WebCore::IntPoint&);
void handleSelectionServiceClick(WebCore::FrameSelection&, const Vector<String>& telephoneNumbers, const WebCore::IntPoint&);
- bool serviceControlsEnabled() const { return m_serviceControlsEnabled; }
#endif
void didChangeScrollOffsetForFrame(WebCore::Frame*);
@@ -1091,10 +1088,6 @@
RunLoop::Timer<WebPage> m_determinePrimarySnapshottedPlugInTimer;
#endif
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
- bool m_serviceControlsEnabled;
-#endif
-
// The layer hosting mode.
LayerHostingMode m_layerHostingMode;
@@ -1269,10 +1262,6 @@
#if ENABLE(WEBGL)
WebCore::WebGLLoadPolicy m_systemWebGLPolicy;
#endif
-
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
- std::unique_ptr<ServicesOverlayController> m_servicesOverlayController;
-#endif
};
} // namespace WebKit
Deleted: trunk/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm (174523 => 174524)
--- trunk/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm 2014-10-09 20:51:55 UTC (rev 174523)
+++ trunk/Source/WebKit2/WebProcess/WebPage/mac/ServicesOverlayController.mm 2014-10-09 20:53:02 UTC (rev 174524)
@@ -1,823 +0,0 @@
-/*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "ServicesOverlayController.h"
-
-#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)
-
-#import "Logging.h"
-#import "WebPage.h"
-#import "WebProcess.h"
-#import <QuartzCore/QuartzCore.h>
-#import <WebCore/Document.h>
-#import <WebCore/EventHandler.h>
-#import <WebCore/FloatQuad.h>
-#import <WebCore/FocusController.h>
-#import <WebCore/FrameView.h>
-#import <WebCore/GapRects.h>
-#import <WebCore/GraphicsContext.h>
-#import <WebCore/GraphicsLayer.h>
-#import <WebCore/GraphicsLayerCA.h>
-#import <WebCore/MainFrame.h>
-#import <WebCore/PageOverlayController.h>
-#import <WebCore/PlatformCAAnimationMac.h>
-#import <WebCore/SoftLinking.h>
-
-#if __has_include(<DataDetectors/DDHighlightDrawing.h>)
-#import <DataDetectors/DDHighlightDrawing.h>
-#else
-typedef void* DDHighlightRef;
-#endif
-
-#if __has_include(<DataDetectors/DDHighlightDrawing_Private.h>)
-#import <DataDetectors/DDHighlightDrawing_Private.h>
-#endif
-
-const float highlightFadeAnimationDuration = 0.3;
-
-typedef NSUInteger DDHighlightStyle;
-static const DDHighlightStyle DDHighlightNoOutlineWithArrow = (1 << 16);
-static const DDHighlightStyle DDHighlightOutlineWithArrow = (1 << 16) | 1;
-
-SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
-SOFT_LINK(DataDetectors, DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection, DDHighlightRef, (CFAllocatorRef allocator, CGRect* rects, CFIndex count, CGRect globalVisibleRect, DDHighlightStyle style, Boolean withArrow, NSWritingDirection writingDirection, Boolean endsWithEOL, Boolean flipped), (allocator, rects, count, globalVisibleRect, style, withArrow, writingDirection, endsWithEOL, flipped))
-SOFT_LINK(DataDetectors, DDHighlightGetLayerWithContext, CGLayerRef, (DDHighlightRef highlight, CGContextRef context), (highlight, context))
-SOFT_LINK(DataDetectors, DDHighlightGetBoundingRect, CGRect, (DDHighlightRef highlight), (highlight))
-SOFT_LINK(DataDetectors, DDHighlightPointIsOnHighlight, Boolean, (DDHighlightRef highlight, CGPoint point, Boolean* onButton), (highlight, point, onButton))
-
-using namespace WebCore;
-
-namespace WebKit {
-
-PassRefPtr<ServicesOverlayController::Highlight> ServicesOverlayController::Highlight::createForSelection(ServicesOverlayController& controller, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<Range> range)
-{
- return adoptRef(new Highlight(controller, Type::Selection, ddHighlight, range));
-}
-
-PassRefPtr<ServicesOverlayController::Highlight> ServicesOverlayController::Highlight::createForTelephoneNumber(ServicesOverlayController& controller, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<Range> range)
-{
- return adoptRef(new Highlight(controller, Type::TelephoneNumber, ddHighlight, range));
-}
-
-ServicesOverlayController::Highlight::Highlight(ServicesOverlayController& controller, Type type, RetainPtr<DDHighlightRef> ddHighlight, PassRefPtr<WebCore::Range> range)
- : m_range(range)
- , m_type(type)
- , m_controller(&controller)
-{
- ASSERT(ddHighlight);
- ASSERT(m_range);
-
- DrawingArea* drawingArea = controller.webPage().drawingArea();
- m_graphicsLayer = GraphicsLayer::create(drawingArea ? drawingArea->graphicsLayerFactory() : nullptr, *this);
- m_graphicsLayer->setDrawsContent(true);
-
- setDDHighlight(ddHighlight.get());
-
- // 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())->platformCALayer()->setOpacity(0);
-
- controller.didCreateHighlight(this);
-}
-
-ServicesOverlayController::Highlight::~Highlight()
-{
- if (m_controller)
- m_controller->willDestroyHighlight(this);
-}
-
-void ServicesOverlayController::Highlight::setDDHighlight(DDHighlightRef highlight)
-{
- if (!m_controller)
- return;
-
- m_ddHighlight = highlight;
-
- if (!m_ddHighlight)
- return;
-
- CGRect highlightBoundingRect = DDHighlightGetBoundingRect(m_ddHighlight.get());
- m_graphicsLayer->setPosition(FloatPoint(highlightBoundingRect.origin));
- m_graphicsLayer->setSize(FloatSize(highlightBoundingRect.size));
-
- m_graphicsLayer->setNeedsDisplay();
-}
-
-void ServicesOverlayController::Highlight::invalidate()
-{
- layer()->removeFromParent();
- m_controller = nullptr;
-}
-
-void ServicesOverlayController::Highlight::notifyFlushRequired(const GraphicsLayer*)
-{
- if (!m_controller)
- return;
-
- if (DrawingArea* drawingArea = m_controller->webPage().drawingArea())
- drawingArea->scheduleCompositingLayerFlush();
-}
-
-void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& 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->webPage().deviceScaleFactor();
-}
-
-void ServicesOverlayController::Highlight::fadeIn()
-{
- RetainPtr<CABasicAnimation> animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
- [animation setDuration:highlightFadeAnimationDuration];
- [animation setFillMode:kCAFillModeForwards];
- [animation setRemovedOnCompletion:false];
- [animation setToValue:@1];
-
- RefPtr<PlatformCAAnimation> platformAnimation = PlatformCAAnimationMac::create(animation.get());
- toGraphicsLayerCA(layer())->platformCALayer()->addAnimationForKey("FadeHighlightIn", platformAnimation.get());
-}
-
-void ServicesOverlayController::Highlight::fadeOut()
-{
- RetainPtr<CABasicAnimation> animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
- [animation setDuration:highlightFadeAnimationDuration];
- [animation setFillMode:kCAFillModeForwards];
- [animation setRemovedOnCompletion:false];
- [animation setToValue:@0];
-
- RefPtr<Highlight> retainedSelf = this;
- [CATransaction begin];
- [CATransaction setCompletionBlock:[retainedSelf] () {
- retainedSelf->didFinishFadeOutAnimation();
- }];
-
- RefPtr<PlatformCAAnimation> platformAnimation = PlatformCAAnimationMac::create(animation.get());
- toGraphicsLayerCA(layer())->platformCALayer()->addAnimationForKey("FadeHighlightOut", platformAnimation.get());
- [CATransaction commit];
-}
-
-void ServicesOverlayController::Highlight::didFinishFadeOutAnimation()
-{
- if (!m_controller)
- return;
-
- if (m_controller->activeHighlight() == this)
- return;
-
- layer()->removeFromParent();
-}
-
-static IntRect textQuadsToBoundingRectForRange(Range& range)
-{
- Vector<FloatQuad> textQuads;
- range.textQuads(textQuads);
- FloatRect boundingRect;
- for (auto& quad : textQuads)
- boundingRect.unite(quad.boundingBox());
- return enclosingIntRect(boundingRect);
-}
-
-ServicesOverlayController::ServicesOverlayController(WebPage& webPage)
- : m_webPage(webPage)
- , m_servicesOverlay(nullptr)
- , m_isTextOnly(false)
- , m_determineActiveHighlightTimer(this, &ServicesOverlayController::determineActiveHighlightTimerFired)
-{
-}
-
-ServicesOverlayController::~ServicesOverlayController()
-{
- for (auto& highlight : m_highlights)
- highlight->invalidate();
-}
-
-void ServicesOverlayController::pageOverlayDestroyed(PageOverlay&)
-{
- // Before the overlay is destroyed, it should have moved out of the WebPage,
- // at which point we already cleared our back pointer.
- ASSERT(!m_servicesOverlay);
-}
-
-void ServicesOverlayController::willMoveToPage(PageOverlay&, Page* page)
-{
- if (page)
- return;
-
- ASSERT(m_servicesOverlay);
- m_servicesOverlay = nullptr;
-}
-
-void ServicesOverlayController::didMoveToPage(PageOverlay&, Page*)
-{
-}
-
-static const uint8_t AlignmentNone = 0;
-static const uint8_t AlignmentLeft = 1 << 0;
-static const uint8_t AlignmentRight = 1 << 1;
-
-static void expandForGap(Vector<LayoutRect>& rects, uint8_t* alignments, const GapRects& gap)
-{
- if (!gap.left().isEmpty()) {
- LayoutUnit leftEdge = gap.left().x();
- for (unsigned i = 0; i < rects.size(); ++i) {
- if (alignments[i] & AlignmentLeft)
- rects[i].shiftXEdgeTo(leftEdge);
- }
- }
-
- if (!gap.right().isEmpty()) {
- LayoutUnit rightEdge = gap.right().maxX();
- for (unsigned i = 0; i < rects.size(); ++i) {
- if (alignments[i] & AlignmentRight)
- rects[i].shiftMaxXEdgeTo(rightEdge);
- }
- }
-}
-
-static inline void stitchRects(Vector<LayoutRect>& rects)
-{
- if (rects.size() <= 1)
- return;
-
- Vector<LayoutRect> newRects;
-
- // FIXME: Need to support vertical layout.
- // First stitch together all the rects on the first line of the selection.
- size_t indexFromStart = 0;
- LayoutUnit firstTop = rects[indexFromStart].y();
- LayoutRect& currentRect = rects[indexFromStart];
- while (indexFromStart < rects.size() && rects[indexFromStart].y() == firstTop)
- currentRect.unite(rects[indexFromStart++]);
-
- newRects.append(currentRect);
- if (indexFromStart == rects.size()) {
- // All the rects are on one line. There is nothing else to do.
- rects.swap(newRects);
- return;
- }
-
- // Next stitch together all the rects on the last line of the selection.
- size_t indexFromEnd = rects.size() - 1;
- LayoutUnit lastTop = rects[indexFromEnd].y();
- LayoutRect lastRect = rects[indexFromEnd];
- while (indexFromEnd >= indexFromStart && rects[indexFromEnd].y() == lastTop)
- lastRect.unite(rects[indexFromEnd--]);
-
- // indexFromStart is the index of the first rectangle on the second line.
- // indexFromEnd is the index of the last rectangle on the second to the last line.
- // if they are equal, there is one additional rectangle for the line in the middle.
- if (indexFromEnd == indexFromStart)
- newRects.append(rects[indexFromStart]);
-
- if (indexFromEnd <= indexFromStart) {
- // There are no more rects to stitch. Just append the last line.
- newRects.append(lastRect);
- rects.swap(newRects);
- return;
- }
-
- // Stitch together all the rects after the first line until the second to the last included.
- currentRect = rects[indexFromStart];
- while (indexFromStart != indexFromEnd)
- currentRect.unite(rects[++indexFromStart]);
-
- newRects.append(currentRect);
- newRects.append(lastRect);
-
- rects.swap(newRects);
-}
-
-static void compactRectsWithGapRects(Vector<LayoutRect>& rects, const Vector<GapRects>& gapRects)
-{
- stitchRects(rects);
-
- // FIXME: The following alignments are correct for LTR text.
- // We should also account for RTL.
- uint8_t alignments[3];
- if (rects.size() == 1) {
- alignments[0] = AlignmentLeft | AlignmentRight;
- alignments[1] = AlignmentNone;
- alignments[2] = AlignmentNone;
- } else if (rects.size() == 2) {
- alignments[0] = AlignmentRight;
- alignments[1] = AlignmentLeft;
- alignments[2] = AlignmentNone;
- } else {
- alignments[0] = AlignmentRight;
- alignments[1] = AlignmentLeft | AlignmentRight;
- alignments[2] = AlignmentLeft;
- }
-
- // Account for each GapRects by extending the edge of certain LayoutRects to meet the gap.
- for (auto& gap : gapRects)
- expandForGap(rects, alignments, gap);
-
- // If we have 3 rects we might need one final GapRects to align the edges.
- if (rects.size() == 3) {
- LayoutRect left;
- LayoutRect right;
- for (unsigned i = 0; i < 3; ++i) {
- if (alignments[i] & AlignmentLeft) {
- if (left.isEmpty())
- left = rects[i];
- else if (rects[i].x() < left.x())
- left = rects[i];
- }
- if (alignments[i] & AlignmentRight) {
- if (right.isEmpty())
- right = rects[i];
- else if ((rects[i].x() + rects[i].width()) > (right.x() + right.width()))
- right = rects[i];
- }
- }
-
- if (!left.isEmpty() || !right.isEmpty()) {
- GapRects gap;
- gap.uniteLeft(left);
- gap.uniteRight(right);
- expandForGap(rects, alignments, gap);
- }
- }
-}
-
-void ServicesOverlayController::selectionRectsDidChange(const Vector<LayoutRect>& rects, const Vector<GapRects>& gapRects, bool isTextOnly)
-{
-#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1090
- m_currentSelectionRects = rects;
- m_isTextOnly = isTextOnly;
-
- m_lastSelectionChangeTime = std::chrono::steady_clock::now();
-
- compactRectsWithGapRects(m_currentSelectionRects, gapRects);
-
- // DataDetectors needs these reversed in order to place the arrow in the right location.
- m_currentSelectionRects.reverse();
-
- LOG(Services, "ServicesOverlayController - Selection rects changed - Now have %lu\n", rects.size());
-
- buildSelectionHighlight();
-#else
- UNUSED_PARAM(rects);
- UNUSED_PARAM(gapRects);
- UNUSED_PARAM(isTextOnly);
-#endif
-}
-
-void ServicesOverlayController::selectedTelephoneNumberRangesChanged()
-{
-#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED > 1090
- LOG(Services, "ServicesOverlayController - Telephone number ranges changed\n");
- buildPhoneNumberHighlights();
-#endif
-}
-
-bool ServicesOverlayController::mouseIsOverHighlight(Highlight& highlight, bool& mouseIsOverButton) const
-{
- Boolean onButton;
- bool hovered = DDHighlightPointIsOnHighlight(highlight.ddHighlight(), (CGPoint)m_mousePosition, &onButton);
- mouseIsOverButton = onButton;
- return hovered;
-}
-
-std::chrono::milliseconds ServicesOverlayController::remainingTimeUntilHighlightShouldBeShown(Highlight* highlight) const
-{
- if (!highlight)
- return std::chrono::milliseconds::zero();
-
- auto minimumTimeUntilHighlightShouldBeShown = 200_ms;
- if (m_webPage.corePage()->focusController().focusedOrMainFrame().selection().selection().isContentEditable())
- minimumTimeUntilHighlightShouldBeShown = 1000_ms;
-
- bool mousePressed = false;
- if (Frame* mainFrame = m_webPage.mainFrame())
- mousePressed = mainFrame->eventHandler().mousePressed();
-
- // Highlight hysteresis is only for selection services, because telephone number highlights are already much more stable
- // by virtue of being expanded to include the entire telephone number. However, we will still avoid highlighting
- // telephone numbers while the mouse is down.
- if (highlight->type() == Highlight::Type::TelephoneNumber)
- return mousePressed ? minimumTimeUntilHighlightShouldBeShown : 0_ms;
-
- auto now = std::chrono::steady_clock::now();
- auto timeSinceLastSelectionChange = now - m_lastSelectionChangeTime;
- auto timeSinceHighlightBecameActive = now - m_nextActiveHighlightChangeTime;
- auto timeSinceLastMouseUp = mousePressed ? 0_ms : now - m_lastMouseUpTime;
-
- auto remainingDelay = minimumTimeUntilHighlightShouldBeShown - std::min(std::min(timeSinceLastSelectionChange, timeSinceHighlightBecameActive), timeSinceLastMouseUp);
- return std::chrono::duration_cast<std::chrono::milliseconds>(remainingDelay);
-}
-
-void ServicesOverlayController::determineActiveHighlightTimerFired(Timer<ServicesOverlayController>&)
-{
- bool mouseIsOverButton;
- determineActiveHighlight(mouseIsOverButton);
-}
-
-void ServicesOverlayController::drawRect(PageOverlay& overlay, GraphicsContext& graphicsContext, const IntRect& dirtyRect)
-{
-}
-
-void ServicesOverlayController::clearActiveHighlight()
-{
- if (!m_activeHighlight)
- return;
-
- if (m_currentMouseDownOnButtonHighlight == m_activeHighlight)
- m_currentMouseDownOnButtonHighlight = nullptr;
- m_activeHighlight = nullptr;
-}
-
-void ServicesOverlayController::removeAllPotentialHighlightsOfType(Highlight::Type type)
-{
- Vector<RefPtr<Highlight>> highlightsToRemove;
- for (auto& highlight : m_potentialHighlights) {
- if (highlight->type() == type)
- highlightsToRemove.append(highlight);
- }
-
- while (!highlightsToRemove.isEmpty())
- m_potentialHighlights.remove(highlightsToRemove.takeLast());
-}
-
-void ServicesOverlayController::buildPhoneNumberHighlights()
-{
- if (!DataDetectorsLibrary())
- return;
-
- HashSet<RefPtr<Highlight>> newPotentialHighlights;
-
- Frame* mainFrame = m_webPage.mainFrame();
- FrameView& mainFrameView = *mainFrame->view();
-
- for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
- auto& ranges = frame->editor().detectedTelephoneNumberRanges();
- for (auto& range : ranges) {
- // FIXME: This will choke if the range wraps around the edge of the view.
- // What should we do in that case?
- IntRect rect = textQuadsToBoundingRectForRange(*range);
-
- // 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 = range->ownerDocument().view();
- if (!viewForRange)
- continue;
- rect.setLocation(mainFrameView.windowToContents(viewForRange->contentsToWindow(rect.location())));
-
- CGRect cgRect = rect;
- RetainPtr<DDHighlightRef> ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, &cgRect, 1, mainFrameView.visibleContentRect(), DDHighlightOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
-
- newPotentialHighlights.add(Highlight::createForTelephoneNumber(*this, ddHighlight, range));
- }
- }
-
- replaceHighlightsOfTypePreservingEquivalentHighlights(newPotentialHighlights, Highlight::Type::TelephoneNumber);
-
- didRebuildPotentialHighlights();
-}
-
-void ServicesOverlayController::buildSelectionHighlight()
-{
- if (!DataDetectorsLibrary())
- return;
-
- HashSet<RefPtr<Highlight>> newPotentialHighlights;
-
- Vector<CGRect> cgRects;
- cgRects.reserveCapacity(m_currentSelectionRects.size());
-
- RefPtr<Range> selectionRange = m_webPage.corePage()->selection().firstRange();
- if (selectionRange) {
- Frame* mainFrame = m_webPage.mainFrame();
- FrameView& mainFrameView = *mainFrame->view();
- FrameView* viewForRange = selectionRange->ownerDocument().view();
-
- for (auto& rect : m_currentSelectionRects) {
- IntRect currentRect = snappedIntRect(rect);
- currentRect.setLocation(mainFrameView.windowToContents(viewForRange->contentsToWindow(currentRect.location())));
- cgRects.append((CGRect)currentRect);
- }
-
- if (!cgRects.isEmpty()) {
- CGRect visibleRect = m_webPage.corePage()->mainFrame().view()->visibleContentRect();
- RetainPtr<DDHighlightRef> ddHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRectWithStyleAndDirection(nullptr, cgRects.begin(), cgRects.size(), visibleRect, DDHighlightNoOutlineWithArrow, YES, NSWritingDirectionNatural, NO, YES));
-
- newPotentialHighlights.add(Highlight::createForSelection(*this, ddHighlight, selectionRange));
- }
- }
-
- replaceHighlightsOfTypePreservingEquivalentHighlights(newPotentialHighlights, Highlight::Type::Selection);
-
- didRebuildPotentialHighlights();
-}
-
-void ServicesOverlayController::replaceHighlightsOfTypePreservingEquivalentHighlights(HashSet<RefPtr<Highlight>>& newPotentialHighlights, Highlight::Type type)
-{
- // If any old Highlights are equivalent (by Range) to a new Highlight, reuse the old
- // one so that any metadata is retained.
- HashSet<RefPtr<Highlight>> reusedPotentialHighlights;
-
- for (auto& oldHighlight : m_potentialHighlights) {
- if (oldHighlight->type() != type)
- continue;
-
- for (auto& newHighlight : newPotentialHighlights) {
- if (highlightsAreEquivalent(oldHighlight.get(), newHighlight.get())) {
- oldHighlight->setDDHighlight(newHighlight->ddHighlight());
-
- reusedPotentialHighlights.add(oldHighlight);
- newPotentialHighlights.remove(newHighlight);
-
- break;
- }
- }
- }
-
- removeAllPotentialHighlightsOfType(type);
-
- m_potentialHighlights.add(newPotentialHighlights.begin(), newPotentialHighlights.end());
- m_potentialHighlights.add(reusedPotentialHighlights.begin(), reusedPotentialHighlights.end());
-}
-
-bool ServicesOverlayController::hasRelevantSelectionServices()
-{
- return (m_isTextOnly && WebProcess::shared().hasSelectionServices()) || WebProcess::shared().hasRichContentServices();
-}
-
-void ServicesOverlayController::didRebuildPotentialHighlights()
-{
- if (m_potentialHighlights.isEmpty()) {
- if (m_servicesOverlay)
- m_webPage.mainFrame()->pageOverlayController().uninstallPageOverlay(m_servicesOverlay, PageOverlay::FadeMode::DoNotFade);
- return;
- }
-
- if (telephoneNumberRangesForFocusedFrame().isEmpty() && !hasRelevantSelectionServices())
- return;
-
- createOverlayIfNeeded();
-
- bool mouseIsOverButton;
- determineActiveHighlight(mouseIsOverButton);
-}
-
-void ServicesOverlayController::createOverlayIfNeeded()
-{
- if (m_servicesOverlay)
- return;
-
- RefPtr<PageOverlay> overlay = PageOverlay::create(*this, PageOverlay::OverlayType::Document);
- m_servicesOverlay = overlay.get();
- m_webPage.mainFrame()->pageOverlayController().installPageOverlay(overlay.release(), PageOverlay::FadeMode::DoNotFade);
-}
-
-Vector<RefPtr<Range>> ServicesOverlayController::telephoneNumberRangesForFocusedFrame()
-{
- Page* page = m_webPage.corePage();
- if (!page)
- return Vector<RefPtr<Range>>();
-
- return page->focusController().focusedOrMainFrame().editor().detectedTelephoneNumberRanges();
-}
-
-bool ServicesOverlayController::highlightsAreEquivalent(const Highlight* a, const Highlight* b)
-{
- if (a == b)
- return true;
-
- if (!a || !b)
- return false;
-
- if (a->type() == b->type() && areRangesEqual(a->range(), b->range()))
- return true;
-
- return false;
-}
-
-ServicesOverlayController::Highlight* ServicesOverlayController::findTelephoneNumberHighlightContainingSelectionHighlight(Highlight& selectionHighlight)
-{
- if (selectionHighlight.type() != Highlight::Type::Selection)
- return nullptr;
-
- const VisibleSelection& selection = m_webPage.corePage()->selection();
- if (!selection.isRange())
- return nullptr;
-
- RefPtr<Range> activeSelectionRange = selection.toNormalizedRange();
- if (!activeSelectionRange)
- return nullptr;
-
- for (auto& highlight : m_potentialHighlights) {
- if (highlight->type() != Highlight::Type::TelephoneNumber)
- continue;
-
- if (highlight->range()->contains(*activeSelectionRange))
- return highlight.get();
- }
-
- return nullptr;
-}
-
-void ServicesOverlayController::determineActiveHighlight(bool& mouseIsOverActiveHighlightButton)
-{
- mouseIsOverActiveHighlightButton = false;
-
- RefPtr<Highlight> newActiveHighlight;
-
- for (auto& highlight : m_potentialHighlights) {
- if (highlight->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 (newActiveHighlight && newActiveHighlight->type() == Highlight::Type::TelephoneNumber)
- continue;
-
- // If this highlight has no compatible services, it can't be active.
- if (!hasRelevantSelectionServices())
- continue;
- }
-
- // If this highlight isn't hovered, it can't be active.
- bool mouseIsOverButton;
- if (!mouseIsOverHighlight(*highlight, mouseIsOverButton))
- continue;
-
- newActiveHighlight = highlight;
- mouseIsOverActiveHighlightButton = mouseIsOverButton;
- }
-
- // If our new active highlight is a selection highlight that is completely contained
- // by one of the phone number highlights, we'll make the phone number highlight active even if it's not hovered.
- if (newActiveHighlight && newActiveHighlight->type() == Highlight::Type::Selection) {
- if (Highlight* containedTelephoneNumberHighlight = findTelephoneNumberHighlightContainingSelectionHighlight(*newActiveHighlight)) {
- newActiveHighlight = containedTelephoneNumberHighlight;
-
- // We will always initially choose the telephone number highlight over the selection highlight if the
- // mouse is over the telephone number highlight's button, so we know that it's not hovered if we got here.
- mouseIsOverActiveHighlightButton = false;
- }
- }
-
- if (!this->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();
- }
-
- m_currentMouseDownOnButtonHighlight = nullptr;
-
- if (m_activeHighlight) {
- m_activeHighlight->fadeOut();
- m_activeHighlight = nullptr;
- }
-
- auto remainingTimeUntilHighlightShouldBeShown = this->remainingTimeUntilHighlightShouldBeShown(newActiveHighlight.get());
- if (remainingTimeUntilHighlightShouldBeShown > std::chrono::steady_clock::duration::zero()) {
- m_determineActiveHighlightTimer.startOneShot(remainingTimeUntilHighlightShouldBeShown);
- return;
- }
-
- m_activeHighlight = m_nextActiveHighlight.release();
-
- if (m_activeHighlight) {
- m_servicesOverlay->layer().addChild(m_activeHighlight->layer());
- m_activeHighlight->fadeIn();
- }
- }
-}
-
-bool ServicesOverlayController::mouseEvent(PageOverlay&, const PlatformMouseEvent& event)
-{
- m_mousePosition = m_webPage.corePage()->mainFrame().view()->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.
- if (event.button() != MouseButton::LeftButton) {
- m_currentMouseDownOnButtonHighlight = nullptr;
- return false;
- }
-
- // If the mouse lifted while still over the highlight button that it went down on, then that is a click.
- if (event.type() == PlatformEvent::MouseReleased) {
- RefPtr<Highlight> mouseDownHighlight = m_currentMouseDownOnButtonHighlight;
- m_currentMouseDownOnButtonHighlight = nullptr;
-
- m_lastMouseUpTime = std::chrono::steady_clock::now();
-
- if (mouseIsOverActiveHighlightButton && mouseDownHighlight) {
- handleClick(m_mousePosition, *mouseDownHighlight);
- return true;
- }
-
- return false;
- }
-
- // If the mouse moved outside of the button tracking a potential click, stop tracking the click.
- if (event.type() == PlatformEvent::MouseMoved) {
- if (m_currentMouseDownOnButtonHighlight && mouseIsOverActiveHighlightButton)
- return true;
-
- m_currentMouseDownOnButtonHighlight = nullptr;
- return false;
- }
-
- // If the mouse went down over the active highlight's button, track this as a potential click.
- if (event.type() == PlatformEvent::MousePressed) {
- if (m_activeHighlight && mouseIsOverActiveHighlightButton) {
- m_currentMouseDownOnButtonHighlight = m_activeHighlight;
- return true;
- }
-
- return false;
- }
-
- return false;
-}
-
-void ServicesOverlayController::didScrollFrame(PageOverlay&, Frame& frame)
-{
- if (frame.isMainFrame())
- return;
-
- buildPhoneNumberHighlights();
- buildSelectionHighlight();
-
- bool mouseIsOverActiveHighlightButton;
- determineActiveHighlight(mouseIsOverActiveHighlightButton);
-}
-
-void ServicesOverlayController::handleClick(const IntPoint& clickPoint, Highlight& highlight)
-{
- FrameView* frameView = m_webPage.mainFrameView();
- if (!frameView)
- return;
-
- IntPoint windowPoint = frameView->contentsToWindow(clickPoint);
-
- if (highlight.type() == Highlight::Type::Selection) {
- auto telephoneNumberRanges = telephoneNumberRangesForFocusedFrame();
- Vector<String> selectedTelephoneNumbers;
- selectedTelephoneNumbers.reserveCapacity(telephoneNumberRanges.size());
- for (auto& range : telephoneNumberRanges)
- selectedTelephoneNumbers.append(range->text());
-
- m_webPage.handleSelectionServiceClick(m_webPage.corePage()->focusController().focusedOrMainFrame().selection(), selectedTelephoneNumbers, windowPoint);
- } else if (highlight.type() == Highlight::Type::TelephoneNumber)
- m_webPage.handleTelephoneNumberClick(highlight.range()->text(), windowPoint);
-}
-
-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);
-}
-
-} // namespace WebKit
-
-#endif // #if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(MAC)