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