[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / ios / FindControllerIOS.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
28 #if PLATFORM(IOS_FAMILY)
29
30 #import "FindController.h"
31 #import "FindIndicatorOverlayClientIOS.h"
32 #import "SmartMagnificationControllerMessages.h"
33 #import "WebCoreArgumentCoders.h"
34 #import "WebPage.h"
35 #import "WebPageProxyMessages.h"
36 #import <WebCore/Editor.h>
37 #import <WebCore/FocusController.h>
38 #import <WebCore/Frame.h>
39 #import <WebCore/FrameView.h>
40 #import <WebCore/GraphicsContext.h>
41 #import <WebCore/Page.h>
42 #import <WebCore/PageOverlayController.h>
43 #import <WebCore/PathUtilities.h>
44 #import <WebCore/Settings.h>
45 #import <WebCore/TextIndicator.h>
46
47 namespace WebKit {
48 using namespace WebCore;
49
50 const int cornerRadius = 3;
51 const int totalHorizontalMargin = 1;
52 const int totalVerticalMargin = 1;
53
54 const TextIndicatorOptions findTextIndicatorOptions = TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionDoNotClipToVisibleRect;
55
56 static Color highlightColor()
57 {
58     return Color(255, 228, 56, 255);
59 }
60
61 void FindIndicatorOverlayClientIOS::drawRect(PageOverlay& overlay, GraphicsContext& context, const IntRect& dirtyRect)
62 {
63     float scaleFactor = m_frame.page()->deviceScaleFactor();
64
65     if (m_frame.settings().delegatesPageScaling())
66         scaleFactor *= m_frame.page()->pageScaleFactor();
67
68     // If the page scale changed, we need to paint a new TextIndicator.
69     if (m_textIndicator->contentImageScaleFactor() != scaleFactor)
70         m_textIndicator = TextIndicator::createWithSelectionInFrame(m_frame, findTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize(totalHorizontalMargin, totalVerticalMargin));
71
72     if (!m_textIndicator)
73         return;
74
75     Image* indicatorImage = m_textIndicator->contentImage();
76     if (!indicatorImage)
77         return;
78
79     Vector<FloatRect> textRectsInBoundingRectCoordinates = m_textIndicator->textRectsInBoundingRectCoordinates();
80     Vector<Path> paths = PathUtilities::pathsWithShrinkWrappedRects(textRectsInBoundingRectCoordinates, cornerRadius);
81
82     context.setFillColor(highlightColor());
83     for (const auto& path : paths)
84         context.fillPath(path);
85
86     context.drawImage(*indicatorImage, overlay.bounds());
87 }
88
89 bool FindController::updateFindIndicator(Frame& selectedFrame, bool isShowingOverlay, bool shouldAnimate)
90 {
91     if (m_findIndicatorOverlay) {
92         m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
93         m_findIndicatorOverlay = nullptr;
94         m_isShowingFindIndicator = false;
95     }
96
97     auto textIndicator = TextIndicator::createWithSelectionInFrame(selectedFrame, findTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize(totalHorizontalMargin, totalVerticalMargin));
98     if (!textIndicator)
99         return false;
100
101     m_findIndicatorOverlayClient = makeUnique<FindIndicatorOverlayClientIOS>(selectedFrame, textIndicator.get());
102     m_findIndicatorRect = enclosingIntRect(textIndicator->selectionRectInRootViewCoordinates());
103     m_findIndicatorOverlay = PageOverlay::create(*m_findIndicatorOverlayClient, PageOverlay::OverlayType::Document);
104     m_webPage->corePage()->pageOverlayController().installPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
105
106     m_findIndicatorOverlay->setFrame(enclosingIntRect(textIndicator->textBoundingRectInRootViewCoordinates()));
107     m_findIndicatorOverlay->setNeedsDisplay();
108
109     if (shouldAnimate) {
110         bool isReplaced;
111         const VisibleSelection& visibleSelection = selectedFrame.selection().selection();
112         FloatRect renderRect = visibleSelection.start().containerNode()->renderRect(&isReplaced);
113         IntRect startRect = visibleSelection.visibleStart().absoluteCaretBounds();
114
115         m_webPage->send(Messages::SmartMagnificationController::ScrollToRect(startRect.center(), renderRect));
116     }
117
118     m_isShowingFindIndicator = true;
119     
120     return true;
121 }
122
123 void FindController::hideFindIndicator()
124 {
125     if (!m_isShowingFindIndicator)
126         return;
127
128     m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
129     m_findIndicatorOverlay = nullptr;
130     m_isShowingFindIndicator = false;
131     m_foundStringMatchIndex = -1;
132     didHideFindIndicator();
133 }
134
135 static void setSelectionChangeUpdatesEnabledInAllFrames(WebPage& page, bool enabled)
136 {
137     for (Frame* coreFrame = page.mainFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext())
138         coreFrame->editor().setIgnoreSelectionChanges(enabled);
139 }
140
141 void FindController::willFindString()
142 {
143     setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, true);
144 }
145
146 void FindController::didFindString()
147 {
148     // If the selection before we enabled appearance updates is equal to the
149     // range that we just found, setSelection will bail and fail to actually call
150     // updateAppearance, so the selection won't have been pushed to the render tree.
151     // Therefore, we need to force an update no matter what.
152
153     Frame& frame = m_webPage->corePage()->focusController().focusedOrMainFrame();
154     frame.selection().setUpdateAppearanceEnabled(true);
155     frame.selection().updateAppearance();
156     frame.selection().setUpdateAppearanceEnabled(false);
157
158     // Scrolling the main frame is handled by the SmartMagnificationController class but we still
159     // need to consider overflow nodes and subframes here.
160     // Many sites have overlay headers or footers that may overlap with the highlighted
161     // text, so we reveal the text at the center of the viewport.
162     // FIXME: Find a better way to estimate the obscured area (https://webkit.org/b/183889).
163     frame.selection().revealSelection(SelectionRevealMode::RevealUpToMainFrame, ScrollAlignment::alignCenterAlways, WebCore::DoNotRevealExtent);
164 }
165
166 void FindController::didFailToFindString()
167 {
168     setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, false);
169 }
170
171 void FindController::didHideFindIndicator()
172 {
173     setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, false);
174 }
175     
176 unsigned FindController::findIndicatorRadius() const
177 {
178     return cornerRadius;
179 }
180     
181 bool FindController::shouldHideFindIndicatorOnScroll() const
182 {
183     return false;
184 }
185
186 } // namespace WebKit
187
188 #endif