Bug Summary

File:Source/WebKit/WebProcess/WebPage/FindController.cpp
Warning:line 296, column 124
Call argument for parameter 'page' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx15.5.0 -Os -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource143.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=15.5 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebKit -target-linker-version 1167.5 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebKit -resource-dir /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebKit/WebKit/normal/arm64/UnifiedSource143.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/WebKit-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/WebKit-project-headers.hmap -isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx15.0-additions.sdk/usr/local/include -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/10373006496219643705/WebKit2Prefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D CLANG_WEBKIT_BRANCH=1 -D NDEBUG -D HAVE_CORE_PREDICTION -D ENABLE_LOWER_FORMATREADERBUNDLE_CODESIGNING_REQUIREMENTS -D WEBKIT_BUNDLE_VERSION="625.1.10+" -D FRAMEWORK_NAME=WebKit -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/WebKit-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/WebKit-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/WebCore.framework/Versions/A/PrivateHeaders/ForwardingHeaders -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebKit -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebKit/IPC -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/pal/graphics/WebGPU -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/pal/graphics/WebGPU -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebKit -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release/WebKit.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -F/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks -D __STDC_WANT_LIB_EXT1__=1 -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -internal-isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wno-unused-parameter -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -Wno-unknown-warning-option -Wno-missing-field-initializers -Wno-nullability-completeness -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebKit/WebKit/normal/arm64/UnifiedSource143.plist -x c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebKit/unified-sources/UnifiedSource143.cpp
1/*
2 * Copyright (C) 2010-2025 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 "DrawingArea.h"
30#include "FindIndicator.h"
31#include "MessageSenderInlines.h"
32#include "PluginView.h"
33#include "WKPage.h"
34#include "WebFrame.h"
35#include "WebImage.h"
36#include "WebPage.h"
37#include "WebPageProxyMessages.h"
38#include <WebCore/BoundaryPointInlines.h>
39#include <WebCore/DocumentMarkerController.h>
40#include <WebCore/DocumentMarkers.h>
41#include <WebCore/DocumentView.h>
42#include <WebCore/FindOptions.h>
43#include <WebCore/FindRevealAlgorithms.h>
44#include <WebCore/FloatQuad.h>
45#include <WebCore/FocusController.h>
46#include <WebCore/FrameDestructionObserverInlines.h>
47#include <WebCore/FrameSelection.h>
48#include <WebCore/GeometryUtilities.h>
49#include <WebCore/GraphicsContext.h>
50#include <WebCore/ImageAnalysisQueue.h>
51#include <WebCore/ImageBuffer.h>
52#include <WebCore/ImageOverlay.h>
53#include <WebCore/LocalFrameInlines.h>
54#include <WebCore/LocalFrameView.h>
55#include <WebCore/Page.h>
56#include <WebCore/PageOverlayController.h>
57#include <WebCore/PathUtilities.h>
58#include <WebCore/PlatformMouseEvent.h>
59#include <WebCore/PluginDocument.h>
60#include <WebCore/Range.h>
61#include <WebCore/RenderObject.h>
62#include <WebCore/ShareableBitmap.h>
63#include <WebCore/SimpleRange.h>
64#include <wtf/Forward.h>
65#include <wtf/TZoneMallocInlines.h>
66
67namespace WebKit {
68using namespace WebCore;
69
70WTF_MAKE_TZONE_ALLOCATED_IMPL(FindController)::bmalloc::api::HeapRef FindController::s_heapRef; const TZoneSpecification
FindController::s_heapSpec = { &FindController::s_heapRef
, TZoneSpecification::encodeSize<FindController>(), TZoneSpecification
::encodeAlignment<FindController>(), TZoneSpecification
::encodeCategory<FindController>(), ::bmalloc::api::compactAllocationMode
<FindController>(), TZoneSpecification::encodeDescriptor
<FindController>(), }; void* FindController::operatorNewSlow
(size_t size) { if constexpr (::bmalloc::api::compactAllocationMode
<FindController>() == CompactAllocationMode::Compact) return
::bmalloc::api::tzoneAllocateCompactSlow(size, s_heapSpec); return
::bmalloc::api::tzoneAllocateNonCompactSlow(size, s_heapSpec
); } using __makeBtzoneMallocedInlineMacroSemicolonifier __attribute__
((unused)) = int
;
71
72FindController::FindController(WebPage* webPage)
73 : m_webPage(webPage)
74#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
75 , m_findIndicator(WTF::makeUnique<FindIndicatorIOS>(webPage))
76#else
77 , m_findIndicator(WTF::makeUnique<FindIndicator>(webPage))
78#endif
79{
80}
81
82FindController::~FindController() = default;
83
84#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
85
86PluginView* FindController::mainFramePlugIn()
87{
88 return protect(m_webPage.get())->mainFramePlugIn();
89}
90
91#endif
92
93void FindController::countStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(uint32_t)>&& completionHandler)
94{
95 if (maxMatchCount == std::numeric_limits<unsigned>::max())
96 --maxMatchCount;
97
98 unsigned matchCount;
99#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
100 if (RefPtr pluginView = mainFramePlugIn())
101 matchCount = pluginView->countFindMatches(string, core(options), maxMatchCount + 1);
102 else
103#endif
104 {
105 RefPtr webPage { m_webPage.get() };
106 matchCount = protect(webPage->corePage())->countFindMatches(string, core(options), maxMatchCount + 1);
107 protect(webPage->corePage())->unmarkAllTextMatches();
108 }
109
110 if (matchCount > maxMatchCount)
111 matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
112
113 completionHandler(matchCount);
114}
115
116uint32_t FindController::replaceMatches(const Vector<uint32_t>& matchIndices, const String& replacementText, bool selectionOnly)
117{
118 RefPtr webPage { m_webPage.get() };
119 if (matchIndices.isEmpty())
120 return protect(webPage->corePage())->replaceSelectionWithText(replacementText);
121
122 // FIXME: This is an arbitrary cap on the maximum number of matches to try and replace, to prevent the web process from
123 // hanging while replacing an enormous amount of matches. In the future, we should handle replacement in batches, and
124 // periodically update an NSProgress in the UI process when a batch of find-in-page matches are replaced.
125 constexpr uint32_t maximumNumberOfMatchesToReplace = 1000;
126
127 Vector<SimpleRange> rangesToReplace;
128 rangesToReplace.reserveInitialCapacity(std::min<uint32_t>(maximumNumberOfMatchesToReplace, matchIndices.size()));
129 for (auto index : matchIndices) {
130 if (index < m_findMatches.size())
131 rangesToReplace.append(m_findMatches[index]);
132 if (rangesToReplace.size() >= maximumNumberOfMatchesToReplace)
133 break;
134 }
135 return protect(webPage->corePage())->replaceRangesWithText(rangesToReplace, replacementText, selectionOnly);
136}
137
138RefPtr<LocalFrame> FindController::frameWithSelection(Page* page)
139{
140 for (RefPtr<Frame> frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
141 auto* localFrame = dynamicDowncast<LocalFrame>(frame.get());
142 if (!localFrame)
143 continue;
144
145 if (localFrame->selection().isCaretOrRange())
146 return localFrame;
147 }
148 return nullptr;
149}
150
151void FindController::updateFindUIAfterIncrementalFind(bool found, const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, WebCore::DidWrap didWrap, std::optional<FrameIdentifier> idOfFrameContainingString, CompletionHandler<void(std::optional<WebCore::FrameIdentifier>, Vector<IntRect>&&, uint32_t, int32_t, bool)>&& completionHandler)
152{
153 RefPtr webPage { m_webPage.get() };
154 RefPtr selectedFrame = frameWithSelection(protect(webPage->corePage()).get());
155
156#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
157 RefPtr pluginView = mainFramePlugIn();
158#endif
159
160 bool shouldShowOverlay = found && options.contains(FindOptions::ShowOverlay);
161 unsigned matchCount = 0;
162 Vector<IntRect> matchRects;
163 if (!found) {
164 if (selectedFrame && !options.contains(FindOptions::DoNotSetSelection))
165 protect(selectedFrame->selection())->clear();
166
167 hideFindUI();
168
169 completionHandler(idOfFrameContainingString, WTF::move(matchRects), matchCount, m_foundStringMatchIndex.value_or(-1), didWrap == WebCore::DidWrap::Yes);
170 return;
171 }
172
173 bool needsCount = options.contains(FindOptions::DetermineMatchIndex);
174 bool needsMarking = shouldShowOverlay || options.contains(FindOptions::ShowHighlight);
175 matchCount = 1;
176
177 // marking implicitly counts, so we try not to double count here
178 if (needsMarking)
179 matchCount = markMatches(string, options, maxMatchCount);
180 else if (needsCount)
181 matchCount = getMatchCount(string, options, maxMatchCount);
182
183 if (matchCount > maxMatchCount)
184 matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
185
186 updateMatchIndex(matchCount, options);
187
188 if (auto range = protect(webPage->corePage())->selection().firstRange())
189 matchRects = RenderObject::absoluteTextRects(*range);
190
191 updateFindPageOverlay(shouldShowOverlay);
192 updateFindIndicatorIfNeeded(found, options, shouldShowOverlay);
193 completionHandler(idOfFrameContainingString, WTF::move(matchRects), matchCount, m_foundStringMatchIndex.value_or(0), didWrap == WebCore::DidWrap::Yes);
194}
195
196unsigned FindController::markMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
197{
198 maxMatchCount = std::min(std::numeric_limits<unsigned>::max() - 1, maxMatchCount);
199
200#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
201 if (RefPtr pluginView = mainFramePlugIn())
202 return pluginView->countFindMatches(string, core(options), maxMatchCount + 1);
203#endif
204
205 RefPtr webPage { m_webPage.get() };
206 bool shouldShowHighlight = options.contains(FindOptions::ShowHighlight);
207
208 protect(webPage->corePage())->unmarkAllTextMatches();
209 return protect(webPage->corePage())->markAllMatchesForText(string, core(options), shouldShowHighlight, maxMatchCount + 1);
210}
211
212unsigned FindController::getMatchCount(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
213{
214#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
215 if (RefPtr pluginView = mainFramePlugIn(); pluginView)
216 return pluginView->countFindMatches(string, core(options), maxMatchCount + 1);
217#endif
218
219 RefPtr webPage { m_webPage.get() };
220 return protect(webPage->corePage())->countFindMatches(string, core(options), maxMatchCount + 1);
221}
222
223void FindController::updateMatchIndex(unsigned matchCount, OptionSet<FindOptions> options)
224{
225 if (!options.contains(FindOptions::DetermineMatchIndex))
226 return;
227
228 if (matchCount == static_cast<unsigned>(kWKMoreThanMaximumMatchCount)) {
229 m_foundStringMatchIndex = std::nullopt;
230 return;
231 }
232
233 if (!m_foundStringMatchIndex)
234 m_foundStringMatchIndex = matchCount;
235 else if (*m_foundStringMatchIndex >= matchCount)
236 *m_foundStringMatchIndex -= matchCount;
237}
238
239void FindController::updateFindUIAfterFindingAllMatches(bool found, const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount)
240{
241 RefPtr webPage { m_webPage.get() };
242 RefPtr selectedFrame = frameWithSelection(protect(webPage->corePage()).get());
243
244#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
245 RefPtr pluginView = mainFramePlugIn();
246#endif
247
248 bool shouldShowOverlay = found && options.contains(FindOptions::ShowOverlay);
249 if (!found) {
250 if (selectedFrame && !options.contains(FindOptions::DoNotSetSelection))
251 protect(selectedFrame->selection())->clear();
252 hideFindUI();
253 return;
254 }
255
256 bool shouldShowHighlight = options.contains(FindOptions::ShowHighlight);
257 if (shouldShowOverlay || shouldShowHighlight) {
258 protect(webPage->corePage())->unmarkAllTextMatches();
259 protect(webPage->corePage())->markAllMatchesForText(string, core(options), shouldShowHighlight, maxMatchCount + 1);
260 }
261
262 updateFindPageOverlay(shouldShowOverlay);
263 updateFindIndicatorIfNeeded(found, options, shouldShowOverlay);
264}
265
266void FindController::updateFindPageOverlay(bool shouldShowOverlay)
267{
268 if (!shouldShowOverlay) {
269 if (RefPtr findPageOverlay = m_findPageOverlay.get())
270 m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*findPageOverlay, PageOverlay::FadeMode::Fade);
271 return;
272 }
273
274 RefPtr findPageOverlay = m_findPageOverlay.get();
275 if (!findPageOverlay) {
276 findPageOverlay = PageOverlay::create(*this, PageOverlay::OverlayType::Document);
277 m_findPageOverlay = findPageOverlay.get();
278#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
279 if (RefPtr pluginView = mainFramePlugIn(); pluginView && !pluginView->drawsFindOverlay())
280 findPageOverlay->setNeedsSynchronousScrolling(true);
281#endif
282 m_webPage->corePage()->pageOverlayController().installPageOverlay(*findPageOverlay, PageOverlay::FadeMode::Fade);
283 }
284 findPageOverlay->setNeedsDisplay();
285}
286
287void FindController::updateFindIndicatorIfNeeded(bool found, OptionSet<FindOptions> options, bool shouldShowOverlay)
288{
289 bool shouldSetSelection = !options.contains(FindOptions::DoNotSetSelection);
290 bool wantsFindIndicator = found && options.contains(FindOptions::ShowFindIndicator);
291 bool canShowFindIndicator = frameWithSelection(protect(protect(m_webPage.get())->corePage()).get());
292#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
293 if (RefPtr pluginView = mainFramePlugIn())
294 canShowFindIndicator |= !pluginView->drawsFindOverlay();
295#endif
296 if (shouldSetSelection && (!wantsFindIndicator || !canShowFindIndicator || !m_findIndicator->update(frameWithSelection(m_webPage->corePage()), shouldShowOverlay)))
Call argument for parameter 'page' is uncounted and unsafe
297 m_findIndicator->hide();
298}
299
300#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
301void FindController::findStringIncludingImages(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(std::optional<FrameIdentifier>, Vector<IntRect>&&, uint32_t, int32_t, bool)>&& completionHandler)
302{
303 protect(protect(m_webPage.get())->corePage())->analyzeImagesForFindInPage([weakPage = WeakPtr { m_webPage }, string, options, maxMatchCount, completionHandler = WTF::move(completionHandler)]() mutable {
304 if (weakPage)
305 weakPage->findController().findString(string, options, maxMatchCount, WTF::move(completionHandler));
306 else
307 completionHandler({ }, { }, { }, { }, { });
308 });
309}
310#endif
311
312void FindController::findString(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(std::optional<FrameIdentifier>, Vector<IntRect>&&, uint32_t, int32_t, bool)>&& completionHandler)
313{
314#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
315 RefPtr pluginView = mainFramePlugIn();
316#endif
317
318 WebCore::FindOptions coreOptions = core(options);
319
320 // iOS will reveal the selection through a different mechanism, and
321 // we need to avoid sending the non-painted selection change to the UI process
322 // so that it does not clear the selection out from under us.
323 //
324 // To share logic between platforms, prevent Editor from revealing the selection
325 // and reveal the selection in FindIndicatorStrategy::didFindString.
326 coreOptions.add(FindOption::DoNotRevealSelection);
327
328 m_findIndicator->willFindString();
329
330 bool foundStringStartsAfterSelection = false;
331 RefPtr webPage { m_webPage.get() };
332#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
333 if (!pluginView)
334#endif
335 {
336 if (RefPtr selectedFrame = frameWithSelection(protect(webPage->corePage()).get())) {
337 if (protect(selectedFrame->selection())->selectionBounds().isEmpty()) {
338 auto result = protect(webPage->corePage())->findTextMatches(string, coreOptions, maxMatchCount);
339 m_foundStringMatchIndex = result.indexForSelection;
340 foundStringStartsAfterSelection = true;
341 }
342 }
343 }
344
345 bool found;
346 std::optional<FrameIdentifier> idOfFrameContainingString;
347 auto didWrap = WebCore::DidWrap::No;
348#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
349 if (pluginView) {
350 found = pluginView->findString(string, coreOptions, maxMatchCount);
351 if (auto* frame = pluginView->frame(); frame && found)
352 idOfFrameContainingString = frame->frameID();
353 } else
354#endif
355 {
356 auto [frameID, _] = protect(webPage->corePage())->findString(string, coreOptions, &didWrap);
357 idOfFrameContainingString = frameID;
358 found = idOfFrameContainingString.has_value();
359 }
360
361 if (found && !options.contains(FindOptions::DoNotSetSelection)) {
362 m_findIndicator->didFindString(frameWithSelection(protect(m_webPage->corePage()).get()));
363
364 if (!foundStringStartsAfterSelection && m_foundStringMatchIndex) {
365 if (options.contains(FindOptions::Backwards))
366 (*m_foundStringMatchIndex)--;
367 else if (!options.contains(FindOptions::NoIndexChange))
368 (*m_foundStringMatchIndex)++;
369 }
370 }
371
372 protect(webPage->drawingArea())->dispatchAfterEnsuringUpdatedScrollPosition([webPage, found, string, options, maxMatchCount, didWrap, idOfFrameContainingString, completionHandler = WTF::move(completionHandler)]() mutable {
373 webPage->findController().updateFindUIAfterIncrementalFind(found, string, options, maxMatchCount, didWrap, idOfFrameContainingString, WTF::move(completionHandler));
374 });
375}
376
377void FindController::findStringMatches(const String& string, OptionSet<FindOptions> options, unsigned maxMatchCount, CompletionHandler<void(Vector<Vector<WebCore::IntRect>>, int32_t)>&& completionHandler)
378{
379 RefPtr webPage { m_webPage.get() };
380 auto result = protect(webPage->corePage())->findTextMatches(string, core(options), maxMatchCount);
381 m_findMatches = WTF::move(result.ranges);
382
383 auto matchRects = m_findMatches.map([](auto& range) {
384 return RenderObject::absoluteTextRects(range);
385 });
386 completionHandler(matchRects, result.indexForSelection.value_or(-1));
387
388 if (!options.contains(FindOptions::ShowOverlay) && !options.contains(FindOptions::ShowFindIndicator))
389 return;
390
391 bool found = !m_findMatches.isEmpty();
392 protect(webPage->drawingArea())->dispatchAfterEnsuringUpdatedScrollPosition([webPage, found, string, options, maxMatchCount]() {
393 webPage->findController().updateFindUIAfterFindingAllMatches(found, string, options, maxMatchCount);
394 });
395}
396
397void FindController::getImageForFindMatch(uint32_t matchIndex)
398{
399 if (matchIndex >= m_findMatches.size())
400 return;
401 RefPtr frame = m_findMatches[matchIndex].start.document().frame();
402 if (!frame)
403 return;
404
405 CheckedRef frameSelection = frame->selection();
406 auto oldSelection = frameSelection->selection();
407 frameSelection->setSelection(m_findMatches[matchIndex]);
408
409 auto selectionSnapshot = protect(WebFrame::fromCoreFrame(*frame))->createSelectionSnapshot();
410
411 frameSelection->setSelection(oldSelection);
412
413 if (!selectionSnapshot)
414 return;
415
416 auto handle = selectionSnapshot->createHandle();
417 if (!handle || !selectionSnapshot->parameters())
418 return;
419
420 m_webPage->send(Messages::WebPageProxy::DidGetImageForFindMatch(*selectionSnapshot->parameters(), WTF::move(*handle), matchIndex));
421}
422
423void FindController::selectFindMatch(uint32_t matchIndex)
424{
425 if (matchIndex >= m_findMatches.size())
426 return;
427 RefPtr frame = m_findMatches[matchIndex].start.document().frame();
428 if (!frame)
429 return;
430 protect(frame->selection())->setSelection(m_findMatches[matchIndex]);
431}
432
433void FindController::indicateFindMatch(uint32_t matchIndex)
434{
435 m_findIndicator->willFindString();
436
437 selectFindMatch(matchIndex);
438 RefPtr selectedFrame = frameWithSelection(protect(protect(m_webPage.get())->corePage()).get());
439 if (!selectedFrame)
440 return;
441
442 m_findIndicator->didFindString(selectedFrame);
443 m_findIndicator->update(selectedFrame, !!m_findPageOverlay);
444}
445
446void FindController::hideFindUI()
447{
448 m_findMatches.clear();
449 if (RefPtr findPageOverlay = m_findPageOverlay.get())
450 m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*findPageOverlay, PageOverlay::FadeMode::Fade);
451
452#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
453 if (RefPtr pluginView = mainFramePlugIn())
454 pluginView->findString(emptyString(), { }, 0);
455 else
456#endif
457 protect(protect(m_webPage.get())->corePage())->unmarkAllTextMatches();
458
459 m_findIndicator->hide();
460 resetMatchIndex();
461
462#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
463 if (RefPtr imageAnalysisQueue = m_webPage->corePage()->imageAnalysisQueueIfExists())
464 imageAnalysisQueue->clearDidBecomeEmptyCallback();
465#endif
466}
467
468void FindController::hideFindIndicator()
469{
470 m_findIndicator->hide();
471}
472
473void FindController::resetMatchIndex()
474{
475 m_foundStringMatchIndex = std::nullopt;
476}
477
478void FindController::showFindIndicatorInSelection()
479{
480 m_findIndicator->update(frameWithSelection(protect(m_webPage->corePage())), false);
481}
482
483void FindController::deviceScaleFactorDidChange()
484{
485 ASSERT(isShowingOverlay())((void)0);
486
487 m_findIndicator->update(frameWithSelection(protect(m_webPage->corePage())), true, false);
488}
489
490void FindController::redraw()
491{
492 if (!m_findIndicator->isShowing())
493 return;
494
495 m_findIndicator->update(frameWithSelection(protect(m_webPage->corePage())), isShowingOverlay(), false);
496}
497
498Vector<FloatRect> FindController::rectsForTextMatchesInRect(IntRect clipRect)
499{
500#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
501 if (RefPtr pluginView = mainFramePlugIn())
502 return pluginView->rectsForTextMatchesInRect(clipRect);
503#endif
504
505 Vector<FloatRect> rects;
506 RefPtr mainFrameView = protect(protect(protect(m_webPage.get())->corePage())->mainFrame())->virtualView();
507 for (RefPtr frame = m_webPage->corePage()->mainFrame(); frame; frame = frame->tree().traverseNext()) {
508 auto* localFrame = dynamicDowncast<LocalFrame>(frame.get());
509 if (!localFrame)
510 continue;
511 RefPtr document = localFrame->document();
512 if (!document)
513 continue;
514
515 for (FloatRect rect : protect(document->markers())->renderedRectsForMarkers(DocumentMarkerType::TextMatch)) {
516 if (!localFrame->isMainFrame())
517 rect = mainFrameView->windowToContents(protect(localFrame->view())->contentsToWindow(enclosingIntRect(rect)));
518
519 if (rect.isEmpty() || !rect.intersects(clipRect))
520 continue;
521
522 rects.append(rect);
523 }
524 }
525
526 return rects;
527}
528
529void FindController::willMoveToPage(PageOverlay&, Page* page)
530{
531 if (page)
532 return;
533
534 ASSERT(m_findPageOverlay)((void)0);
535 m_findPageOverlay = nullptr;
536}
537
538void FindController::didMoveToPage(PageOverlay&, Page*)
539{
540}
541
542constexpr float shadowOffsetX = 0;
543constexpr float shadowOffsetY = 0;
544constexpr float shadowBlurRadius = 1;
545void FindController::drawRect(PageOverlay&, GraphicsContext& graphicsContext, const IntRect& dirtyRect)
546{
547 constexpr int borderWidth = 1;
548
549 constexpr auto overlayBackgroundColor = SRGBA<uint8_t> { 26, 26, 26, 64 };
550 constexpr auto shadowColor = Color::black.colorWithAlphaByte(128);
551
552 IntRect borderInflatedDirtyRect = dirtyRect;
553 borderInflatedDirtyRect.inflate(borderWidth);
554 Vector<FloatRect> rects = rectsForTextMatchesInRect(borderInflatedDirtyRect);
555
556 // Draw the background.
557 graphicsContext.fillRect(dirtyRect, overlayBackgroundColor);
558
559 Vector<Path> whiteFramePaths = PathUtilities::pathsWithShrinkWrappedRects(rects, m_findIndicator->radius());
560
561 GraphicsContextStateSaver stateSaver(graphicsContext);
562
563 // Draw white frames around the holes.
564 // We double the thickness because half of the stroke will be erased when we clear the holes.
565 graphicsContext.setDropShadow({ { shadowOffsetX, shadowOffsetY }, shadowBlurRadius, shadowColor, ShadowRadiusMode::Default });
566 graphicsContext.setStrokeColor(Color::white);
567 graphicsContext.setStrokeThickness(borderWidth * 2);
568 for (auto& path : whiteFramePaths)
569 graphicsContext.strokePath(path);
570
571 graphicsContext.clearDropShadow();
572
573 // Clear out the holes.
574 graphicsContext.setCompositeOperation(CompositeOperator::Clear);
575 for (auto& path : whiteFramePaths)
576 graphicsContext.fillPath(path);
577
578 if (!m_findIndicator->isShowing())
579 return;
580
581 if (RefPtr selectedFrame = frameWithSelection(protect(protect(m_webPage)->corePage()))) {
582 auto findIndicatorRect = protect(selectedFrame->view())->contentsToRootView(enclosingIntRect(protect(selectedFrame->selection())->selectionBounds(FrameSelection::ClipToVisibleContent::No)));
583
584 if (findIndicatorRect != m_findIndicator->rect()) {
585 // We are underneath painting, so it's not safe to mutate the layer tree synchronously.
586 callOnMainRunLoop([weakWebPage = WeakPtr { m_webPage }] {
587 if (!weakWebPage)
588 return;
589 weakWebPage->findController().didScrollAffectingFindIndicatorPosition();
590 });
591 }
592 }
593}
594
595void FindController::didScrollAffectingFindIndicatorPosition()
596{
597 if (m_findIndicator->shouldHideOnScroll())
598 m_findIndicator->hide();
599 else
600 m_findIndicator->update(frameWithSelection(protect(m_webPage->corePage())), true, false);
601}
602
603bool FindController::mouseEvent(PageOverlay&, const PlatformMouseEvent& mouseEvent)
604{
605 if (mouseEvent.type() == PlatformEvent::Type::MousePressed)
606 hideFindUI();
607
608 return false;
609}
610
611void FindController::didInvalidateFindRects()
612{
613 if (RefPtr findPageOverlay = m_findPageOverlay.get())
614 findPageOverlay->setNeedsDisplay();
615}
616
617} // namespace WebKit