If there are no services available, do not show the service controls UI
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / mac / SelectionOverlayControllerMac.mm
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 #import "config.h"
27 #import "SelectionOverlayController.h"
28
29 #if ENABLE(SERVICE_CONTROLS)
30
31 #import "WebProcess.h"
32 #import <WebCore/FrameView.h>
33 #import <WebCore/GraphicsContext.h>
34 #import <WebCore/MainFrame.h>
35 #import <WebCore/SoftLinking.h>
36
37 #if __has_include(<DataDetectors/DDHighlightDrawing.h>)
38 #import <DataDetectors/DDHighlightDrawing.h>
39 #else
40 typedef void* DDHighlightRef;
41 #endif
42
43 #if __has_include(<DataDetectors/DDHighlightDrawing_Private.h>)
44 #import <DataDetectors/DDHighlightDrawing_Private.h>
45 #endif
46
47 SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
48 SOFT_LINK(DataDetectors, DDHighlightCreateWithRectsInVisibleRect, DDHighlightRef, (CFAllocatorRef allocator, CGRect * rects, CFIndex count, CGRect globalVisibleRect, Boolean withArrow), (allocator, rects, count, globalVisibleRect, withArrow))
49 SOFT_LINK(DataDetectors, DDHighlightGetLayerWithContext, CGLayerRef, (DDHighlightRef highlight, CGContextRef context), (highlight, context))
50 SOFT_LINK(DataDetectors, DDHighlightGetBoundingRect, CGRect, (DDHighlightRef highlight), (highlight))
51 SOFT_LINK(DataDetectors, DDHighlightPointIsOnHighlight, Boolean, (DDHighlightRef highlight, CGPoint point, Boolean* onButton), (highlight, point, onButton))
52 SOFT_LINK(DataDetectors, DDHighlightSetButtonPressed, void, (DDHighlightRef highlight, Boolean buttonPressed), (highlight, buttonPressed))
53
54 using namespace WebCore;
55
56 namespace WebKit {
57
58 void SelectionOverlayController::drawRect(PageOverlay* overlay, WebCore::GraphicsContext& graphicsContext, const WebCore::IntRect& dirtyRect)
59 {
60     if (m_currentSelectionRects.isEmpty())
61         return;
62
63     if (!WebProcess::shared().hasSelectionServices()) {
64         destroyOverlay();
65         return;
66     }
67
68     if (!m_currentHighlight) {
69         Vector<CGRect> cgRects;
70         cgRects.reserveCapacity(m_currentSelectionRects.size());
71
72         for (auto& rect : m_currentSelectionRects)
73             cgRects.append((CGRect)pixelSnappedIntRect(rect));
74
75         m_currentHighlight = adoptCF(DDHighlightCreateWithRectsInVisibleRect(nullptr, cgRects.begin(), cgRects.size(), (CGRect)dirtyRect, true));
76
77         Boolean onButton;
78         m_mouseIsOverHighlight = DDHighlightPointIsOnHighlight(m_currentHighlight.get(), (CGPoint)m_mousePosition, &onButton);
79     }
80
81     // If the mouse is not over the DDHighlight we have no drawing to do.
82     if (!m_mouseIsOverHighlight)
83         return;
84
85     CGContextRef cgContext = graphicsContext.platformContext();
86
87     CGLayerRef highlightLayer = DDHighlightGetLayerWithContext(m_currentHighlight.get(), cgContext);
88     CGRect highlightBoundingRect = DDHighlightGetBoundingRect(m_currentHighlight.get());
89     
90     GraphicsContextStateSaver stateSaver(graphicsContext);
91
92     graphicsContext.translate(toFloatSize(highlightBoundingRect.origin));
93     graphicsContext.scale(FloatSize(1, -1));
94     graphicsContext.translate(FloatSize(0, -highlightBoundingRect.size.height));
95     
96     CGRect highlightDrawRect = highlightBoundingRect;
97     highlightDrawRect.origin.x = 0;
98     highlightDrawRect.origin.y = 0;
99     
100     CGContextDrawLayerInRect(cgContext, highlightDrawRect, highlightLayer);
101 }
102     
103 bool SelectionOverlayController::mouseEvent(PageOverlay*, const WebMouseEvent& event)
104 {
105     m_mousePosition = m_webPage->corePage()->mainFrame().view()->rootViewToContents(event.position());
106
107     bool mouseWasOverHighlight = m_mouseIsOverHighlight;
108     Boolean onButton = false;
109     m_mouseIsOverHighlight = m_currentHighlight ? DDHighlightPointIsOnHighlight(m_currentHighlight.get(), (CGPoint)m_mousePosition, &onButton) : false;
110
111     if (mouseWasOverHighlight != m_mouseIsOverHighlight)
112         m_selectionOverlay->setNeedsDisplay();
113
114     // If this event has nothing to do with the left button, it clears the current mouse down tracking and we're done processing it.
115     if (event.button() != WebMouseEvent::LeftButton) {
116         m_mouseIsDownOnButton = false;
117         return false;
118     }
119
120     if (!m_currentHighlight)
121         return false;
122
123     // Check and see if the mouse went up and we have a current mouse down highlight button.
124     if (event.type() == WebEvent::MouseUp) {
125         bool mouseWasDownOnButton = m_mouseIsDownOnButton;
126         m_mouseIsDownOnButton = false;
127
128         // If the mouse lifted while still over the highlight button that it went down on, then that is a click.
129         if (m_mouseIsOverHighlight && onButton && mouseWasDownOnButton) {
130             handleClick(m_mousePosition);
131             return true;
132         }
133         
134         return false;
135     }
136     
137     // Check and see if the mouse moved within the confines of the DD highlight button.
138     if (event.type() == WebEvent::MouseMove) {
139         // Moving with the mouse button down is okay as long as the mouse never leaves the highlight button.
140         if (m_mouseIsOverHighlight && onButton)
141             return true;
142
143         m_mouseIsDownOnButton = false;
144         
145         return false;
146     }
147     
148     // Check and see if the mouse went down over a DD highlight button.
149     if (event.type() == WebEvent::MouseDown) {
150         if (m_mouseIsOverHighlight && onButton) {
151             m_mouseIsDownOnButton = true;
152
153             // FIXME: We need to do the following, but SOFT_LINK isn't working for this method.
154             // DDHighlightSetButtonPressed(m_currentHighlight.get(), true);
155             
156             m_selectionOverlay->setNeedsDisplay();
157             return true;
158         }
159
160         return false;
161     }
162         
163     return false;
164 }
165
166 void SelectionOverlayController::handleClick(const WebCore::IntPoint& point)
167 {
168     m_webPage->handleSelectionServiceClick(m_webPage->corePage()->mainFrame().selection(), point);
169 }
170     
171 void SelectionOverlayController::clearHighlight()
172 {
173     m_currentHighlight.clear();
174     m_mouseIsOverHighlight = false;
175 }
176     
177 } // namespace WebKit
178
179 #endif // ENABLE(SERVICE_CONTROLS)
180