Service overlays stay fixed when <iframe> scrolls
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / ServicesOverlayController.h
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef ServicesOverlayController_h
27 #define ServicesOverlayController_h
28
29 #if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
30
31 #include "PageOverlay.h"
32 #include "WebFrame.h"
33 #include <WebCore/GraphicsLayerClient.h>
34 #include <WebCore/Range.h>
35 #include <WebCore/Timer.h>
36 #include <wtf/RefCounted.h>
37
38 typedef void* DDHighlightRef;
39
40 namespace WebCore {
41 class LayoutRect;
42
43 struct GapRects;
44 }
45
46 namespace WebKit {
47
48 class WebPage;
49
50 class ServicesOverlayController : private PageOverlay::Client {
51 public:
52     ServicesOverlayController(WebPage&);
53     ~ServicesOverlayController();
54
55     void selectedTelephoneNumberRangesChanged();
56     void selectionRectsDidChange(const Vector<WebCore::LayoutRect>&, const Vector<WebCore::GapRects>&, bool isTextOnly);
57
58 private:
59     class Highlight : public RefCounted<Highlight>, private WebCore::GraphicsLayerClient {
60         WTF_MAKE_NONCOPYABLE(Highlight);
61     public:
62         static PassRefPtr<Highlight> createForSelection(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
63         static PassRefPtr<Highlight> createForTelephoneNumber(ServicesOverlayController&, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
64         ~Highlight();
65
66         void invalidate();
67
68         DDHighlightRef ddHighlight() const { return m_ddHighlight.get(); }
69         WebCore::Range* range() const { return m_range.get(); }
70         WebCore::GraphicsLayer* layer() const { return m_graphicsLayer.get(); }
71
72         enum class Type {
73             TelephoneNumber,
74             Selection
75         };
76         Type type() const { return m_type; }
77
78         void fadeIn();
79         void fadeOut();
80
81         void setDDHighlight(DDHighlightRef);
82
83     private:
84         explicit Highlight(ServicesOverlayController&, Type, RetainPtr<DDHighlightRef>, PassRefPtr<WebCore::Range>);
85
86         // GraphicsLayerClient
87         virtual void notifyAnimationStarted(const WebCore::GraphicsLayer*, double time) override { }
88         virtual void notifyFlushRequired(const WebCore::GraphicsLayer*) override;
89         virtual void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& inClip) override;
90         virtual float deviceScaleFactor() const override;
91
92         void didFinishFadeOutAnimation();
93
94         RetainPtr<DDHighlightRef> m_ddHighlight;
95         RefPtr<WebCore::Range> m_range;
96         std::unique_ptr<WebCore::GraphicsLayer> m_graphicsLayer;
97         Type m_type;
98         ServicesOverlayController* m_controller;
99     };
100
101     // PageOverlay::Client
102     virtual void pageOverlayDestroyed(PageOverlay*) override;
103     virtual void willMoveToWebPage(PageOverlay*, WebPage*) override;
104     virtual void didMoveToWebPage(PageOverlay*, WebPage*) override;
105     virtual void drawRect(PageOverlay*, WebCore::GraphicsContext&, const WebCore::IntRect& dirtyRect) override;
106     virtual bool mouseEvent(PageOverlay*, const WebMouseEvent&) override;
107     virtual void didScrollFrame(PageOverlay*, WebCore::Frame*) override;
108
109     void createOverlayIfNeeded();
110     void handleClick(const WebCore::IntPoint&, Highlight&);
111
112     void drawHighlight(Highlight&, WebCore::GraphicsContext&);
113
114     void replaceHighlightsOfTypePreservingEquivalentHighlights(HashSet<RefPtr<Highlight>>&, Highlight::Type);
115     void removeAllPotentialHighlightsOfType(Highlight::Type);
116     void buildPhoneNumberHighlights();
117     void buildSelectionHighlight();
118     void didRebuildPotentialHighlights();
119
120     void determineActiveHighlight(bool& mouseIsOverButton);
121     void clearActiveHighlight();
122     Highlight* activeHighlight() const { return m_activeHighlight.get(); }
123
124     Highlight* findTelephoneNumberHighlightContainingSelectionHighlight(Highlight&);
125
126     bool hasRelevantSelectionServices();
127
128     bool mouseIsOverHighlight(Highlight&, bool& mouseIsOverButton) const;
129     std::chrono::milliseconds remainingTimeUntilHighlightShouldBeShown(Highlight*) const;
130     void determineActiveHighlightTimerFired(WebCore::Timer<ServicesOverlayController>&);
131
132     static bool highlightsAreEquivalent(const Highlight* a, const Highlight* b);
133
134     Vector<RefPtr<WebCore::Range>> telephoneNumberRangesForFocusedFrame();
135
136     void didCreateHighlight(Highlight*);
137     void willDestroyHighlight(Highlight*);
138     void didFinishFadingOutHighlight(Highlight*);
139
140     WebPage& webPage() const { return m_webPage; }
141
142     WebPage& m_webPage;
143     PageOverlay* m_servicesOverlay;
144
145     RefPtr<Highlight> m_activeHighlight;
146     RefPtr<Highlight> m_nextActiveHighlight;
147     HashSet<RefPtr<Highlight>> m_potentialHighlights;
148     HashSet<RefPtr<Highlight>> m_animatingHighlights;
149
150     HashSet<Highlight*> m_highlights;
151
152     // FIXME: These should move onto Highlight.
153     Vector<WebCore::LayoutRect> m_currentSelectionRects;
154     bool m_isTextOnly;
155
156     std::chrono::steady_clock::time_point m_lastSelectionChangeTime;
157     std::chrono::steady_clock::time_point m_nextActiveHighlightChangeTime;
158     std::chrono::steady_clock::time_point m_lastMouseUpTime;
159
160     RefPtr<Highlight> m_currentMouseDownOnButtonHighlight;
161     WebCore::IntPoint m_mousePosition;
162
163     WebCore::Timer<ServicesOverlayController> m_determineActiveHighlightTimer;
164 };
165
166 } // namespace WebKit
167
168 #endif // ENABLE(SERVICE_CONTROLS) && ENABLE(TELEPHONE_NUMBER_DETECTION)
169 #endif // ServicesOverlayController_h