ValueProfile/PredictedType contains dead code, and doesn't recognize functions
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / FindController.cpp
1 /*
2  * Copyright (C) 2010 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 #include "config.h"
27 #include "FindController.h"
28
29 #include "ShareableBitmap.h"
30 #include "WKPage.h"
31 #include "WebCoreArgumentCoders.h"
32 #include "WebPage.h"
33 #include "WebPageProxyMessages.h"
34 #include "WebProcess.h"
35 #include <WebCore/DocumentMarkerController.h>
36 #include <WebCore/FocusController.h>
37 #include <WebCore/Frame.h>
38 #include <WebCore/FrameView.h>
39 #include <WebCore/GraphicsContext.h>
40 #include <WebCore/Page.h>
41
42 using namespace std;
43 using namespace WebCore;
44
45 namespace WebKit {
46
47 static WebCore::FindOptions core(FindOptions options)
48 {
49     return (options & FindOptionsCaseInsensitive ? CaseInsensitive : 0)
50         | (options & FindOptionsAtWordStarts ? AtWordStarts : 0)
51         | (options & FindOptionsTreatMedialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0)
52         | (options & FindOptionsBackwards ? Backwards : 0)
53         | (options & FindOptionsWrapAround ? WrapAround : 0);
54 }
55
56 FindController::FindController(WebPage* webPage)
57     : m_webPage(webPage)
58     , m_findPageOverlay(0)
59     , m_isShowingFindIndicator(false)
60 {
61 }
62
63 FindController::~FindController()
64 {
65 }
66
67 void FindController::countStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
68 {
69     if (maxMatchCount == numeric_limits<unsigned>::max())
70         --maxMatchCount;
71     
72     unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount + 1);
73     m_webPage->corePage()->unmarkAllTextMatches();
74
75     // Check if we have more matches than allowed.
76     if (matchCount > maxMatchCount)
77         matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
78     
79     m_webPage->send(Messages::WebPageProxy::DidCountStringMatches(string, matchCount));
80 }
81
82 static Frame* frameWithSelection(Page* page)
83 {
84     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
85         if (frame->selection()->isRange())
86             return frame;
87     }
88
89     return 0;
90 }
91
92 void FindController::findString(const String& string, FindOptions options, unsigned maxMatchCount)
93 {
94     m_webPage->corePage()->unmarkAllTextMatches();
95
96     bool found = m_webPage->corePage()->findString(string, core(options));
97
98     Frame* selectedFrame = frameWithSelection(m_webPage->corePage());
99
100     bool shouldShowOverlay = false;
101
102     if (!found) {
103         // Clear the selection.
104         if (selectedFrame)
105             selectedFrame->selection()->clear();
106
107         hideFindIndicator();
108
109         m_webPage->send(Messages::WebPageProxy::DidFailToFindString(string));
110     } else {
111         shouldShowOverlay = options & FindOptionsShowOverlay;
112
113         if (shouldShowOverlay) {
114             if (maxMatchCount == numeric_limits<unsigned>::max())
115                 --maxMatchCount;
116             
117             unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount + 1);
118
119             // Check if we have more matches than allowed.
120             if (matchCount > maxMatchCount) {
121                 shouldShowOverlay = false;
122                 matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
123             }
124
125             m_webPage->send(Messages::WebPageProxy::DidFindString(string, matchCount));
126         }
127
128         if (!(options & FindOptionsShowFindIndicator) || !updateFindIndicator(selectedFrame, shouldShowOverlay)) {
129             // Either we shouldn't show the find indicator, or we couldn't update it.
130             hideFindIndicator();
131         }
132     }
133
134     if (!shouldShowOverlay) {
135         if (m_findPageOverlay) {
136             // Get rid of the overlay.
137             m_webPage->uninstallPageOverlay(m_findPageOverlay, false);
138         }
139         
140         ASSERT(!m_findPageOverlay);
141         return;
142     }
143
144     if (!m_findPageOverlay) {
145         RefPtr<PageOverlay> findPageOverlay = PageOverlay::create(this);
146         m_findPageOverlay = findPageOverlay.get();
147         m_webPage->installPageOverlay(findPageOverlay.release());
148     } else {
149         // The page overlay needs to be repainted.
150         m_findPageOverlay->setNeedsDisplay();
151     }
152 }
153
154 void FindController::hideFindUI()
155 {
156     if (m_findPageOverlay)
157         m_webPage->uninstallPageOverlay(m_findPageOverlay, false);
158
159     hideFindIndicator();
160 }
161
162 bool FindController::updateFindIndicator(Frame* selectedFrame, bool isShowingOverlay)
163 {
164     if (!selectedFrame)
165         return false;
166
167     IntRect selectionRect = enclosingIntRect(selectedFrame->selection()->bounds());
168     
169     // Selection rect can be empty for matches that are currently obscured from view.
170     if (selectionRect.isEmpty())
171         return false;
172
173     // We want the selection rect in window coordinates.
174     IntRect selectionRectInWindowCoordinates = selectedFrame->view()->contentsToWindow(selectionRect);
175     
176     Vector<FloatRect> textRects;
177     selectedFrame->selection()->getClippedVisibleTextRectangles(textRects);
178
179     IntSize backingStoreSize = selectionRect.size();
180     backingStoreSize.scale(m_webPage->corePage()->deviceScaleFactor());
181
182     // Create a backing store and paint the find indicator text into it.
183     RefPtr<ShareableBitmap> findIndicatorTextBackingStore = ShareableBitmap::createShareable(backingStoreSize, ShareableBitmap::SupportsAlpha);
184     if (!findIndicatorTextBackingStore)
185         return false;
186     
187     OwnPtr<GraphicsContext> graphicsContext = findIndicatorTextBackingStore->createGraphicsContext();
188     graphicsContext->scale(FloatSize(m_webPage->corePage()->deviceScaleFactor(), m_webPage->corePage()->deviceScaleFactor()));
189
190     IntRect paintRect = selectionRect;
191     paintRect.move(selectedFrame->view()->frameRect().x(), selectedFrame->view()->frameRect().y());
192     paintRect.move(-selectedFrame->view()->scrollOffset());
193
194     graphicsContext->translate(-paintRect.x(), -paintRect.y());
195     selectedFrame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorForceBlackText | PaintBehaviorFlattenCompositingLayers);
196     selectedFrame->document()->updateLayout();
197
198     selectedFrame->view()->paint(graphicsContext.get(), paintRect);
199     selectedFrame->view()->setPaintBehavior(PaintBehaviorNormal);
200     
201     ShareableBitmap::Handle handle;
202     if (!findIndicatorTextBackingStore->createHandle(handle))
203         return false;
204
205     // We want the text rects in selection rect coordinates.
206     Vector<FloatRect> textRectsInSelectionRectCoordinates;
207     
208     for (size_t i = 0; i < textRects.size(); ++i) {
209         IntRect textRectInSelectionRectCoordinates = selectedFrame->view()->contentsToWindow(enclosingIntRect(textRects[i]));
210         textRectInSelectionRectCoordinates.move(-selectionRectInWindowCoordinates.x(), -selectionRectInWindowCoordinates.y());
211
212         textRectsInSelectionRectCoordinates.append(textRectInSelectionRectCoordinates);
213     }            
214     
215     m_webPage->send(Messages::WebPageProxy::SetFindIndicator(selectionRectInWindowCoordinates, textRectsInSelectionRectCoordinates, m_webPage->corePage()->deviceScaleFactor(), handle, !isShowingOverlay));
216     m_isShowingFindIndicator = true;
217
218     return true;
219 }
220
221 void FindController::hideFindIndicator()
222 {
223     if (!m_isShowingFindIndicator)
224         return;
225
226     ShareableBitmap::Handle handle;
227     m_webPage->send(Messages::WebPageProxy::SetFindIndicator(FloatRect(), Vector<FloatRect>(), m_webPage->corePage()->deviceScaleFactor(), handle, false));
228     m_isShowingFindIndicator = false;
229 }
230
231 void FindController::showFindIndicatorInSelection()
232 {
233     Frame* selectedFrame = m_webPage->corePage()->focusController()->focusedOrMainFrame();
234     if (!selectedFrame)
235         return;
236     
237     updateFindIndicator(selectedFrame, false);
238 }
239
240 Vector<IntRect> FindController::rectsForTextMatches()
241 {
242     Vector<IntRect> rects;
243
244     for (Frame* frame = m_webPage->corePage()->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
245         Document* document = frame->document();
246         if (!document)
247             continue;
248
249         IntRect visibleRect = frame->view()->visibleContentRect();
250         Vector<IntRect> frameRects = document->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
251         IntPoint frameOffset(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
252         frameOffset = frame->view()->convertToContainingWindow(frameOffset);
253
254         for (Vector<IntRect>::iterator it = frameRects.begin(), end = frameRects.end(); it != end; ++it) {
255             it->intersect(visibleRect);
256             it->move(frameOffset.x(), frameOffset.y());
257             rects.append(*it);
258         }
259     }
260
261     return rects;
262 }
263
264 void FindController::pageOverlayDestroyed(PageOverlay*)
265 {
266 }
267
268 void FindController::willMoveToWebPage(PageOverlay*, WebPage* webPage)
269 {
270     if (webPage)
271         return;
272
273     // The page overlay is moving away from the web page, reset it.
274     ASSERT(m_findPageOverlay);
275     m_findPageOverlay = 0;
276 }
277     
278 void FindController::didMoveToWebPage(PageOverlay*, WebPage*)
279 {
280 }
281
282 static const float shadowOffsetX = 0.0;
283 static const float shadowOffsetY = 1.0;
284 static const float shadowBlurRadius = 2.0;
285 static const float whiteFrameThickness = 1.0;
286
287 static const float overlayBackgroundRed = 0.1;
288 static const float overlayBackgroundGreen = 0.1;
289 static const float overlayBackgroundBlue = 0.1;
290 static const float overlayBackgroundAlpha = 0.25;
291
292 static Color overlayBackgroundColor(float fractionFadedIn)
293 {
294     return Color(overlayBackgroundRed, overlayBackgroundGreen, overlayBackgroundBlue, overlayBackgroundAlpha * fractionFadedIn);
295 }
296
297 static Color holeShadowColor(float fractionFadedIn)
298 {
299     return Color(0.0f, 0.0f, 0.0f, fractionFadedIn);
300 }
301
302 static Color holeFillColor(float fractionFadedIn)
303 {
304     return Color(1.0f, 1.0f, 1.0f, fractionFadedIn);
305 }
306
307 void FindController::drawRect(PageOverlay* pageOverlay, GraphicsContext& graphicsContext, const IntRect& dirtyRect)
308 {
309     float fractionFadedIn = pageOverlay->fractionFadedIn();
310
311     Vector<IntRect> rects = rectsForTextMatches();
312
313     // Draw the background.
314     graphicsContext.fillRect(dirtyRect, overlayBackgroundColor(fractionFadedIn), ColorSpaceSRGB);
315
316     {
317         GraphicsContextStateSaver stateSaver(graphicsContext);
318
319         graphicsContext.setShadow(FloatSize(shadowOffsetX, shadowOffsetY), shadowBlurRadius, holeShadowColor(fractionFadedIn), ColorSpaceSRGB);
320         graphicsContext.setFillColor(holeFillColor(fractionFadedIn), ColorSpaceSRGB);
321
322         // Draw white frames around the holes.
323         for (size_t i = 0; i < rects.size(); ++i) {
324             IntRect whiteFrameRect = rects[i];
325             whiteFrameRect.inflate(1);
326
327             graphicsContext.fillRect(whiteFrameRect);
328         }
329     }
330
331     graphicsContext.setFillColor(Color::transparent, ColorSpaceSRGB);
332
333     // Clear out the holes.
334     for (size_t i = 0; i < rects.size(); ++i)
335         graphicsContext.fillRect(rects[i]);
336 }
337
338 bool FindController::mouseEvent(PageOverlay* pageOverlay, const WebMouseEvent& mouseEvent)
339 {
340     // If we get a mouse down event inside the page overlay we should hide the find UI.
341     if (mouseEvent.type() == WebEvent::MouseDown) {
342         // Dismiss the overlay.
343         hideFindUI();
344     }
345
346     return false;
347 }
348
349 } // namespace WebKit